Skip to content

Commit 39b88a8

Browse files
committed
adds shortcuts to the query page filters
1 parent 522ef14 commit 39b88a8

4 files changed

Lines changed: 32 additions & 52 deletions

File tree

apps/webapp/app/components/metrics/ScopeFilter.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,27 @@ const scopeOptions = [
1919
{ value: "organization", label: "Organization" },
2020
] as const;
2121

22-
export function ScopeFilter({ shortcut }: { shortcut?: ShortcutDefinition } = {}) {
23-
const { value, replace } = useSearchParams();
24-
const scope = (value("scope") as QueryScope) ?? "environment";
22+
export type ScopeFilterProps = {
23+
shortcut?: ShortcutDefinition;
24+
/** Controlled value. If provided, the filter uses controlled mode and ignores search params. */
25+
value?: QueryScope;
26+
/** Called when the user selects a new scope. Required when `value` is provided. */
27+
onValueChange?: (scope: QueryScope) => void;
28+
};
29+
30+
export function ScopeFilter({ shortcut, value, onValueChange }: ScopeFilterProps = {}) {
31+
const { value: paramValue, replace } = useSearchParams();
32+
const isControlled = value !== undefined;
33+
const scope: QueryScope = isControlled
34+
? value
35+
: ((paramValue("scope") as QueryScope) ?? "environment");
2536
const triggerRef = useRef<HTMLButtonElement>(null);
2637

2738
const handleChange = (newScope: string) => {
39+
if (isControlled) {
40+
onValueChange?.(newScope as QueryScope);
41+
return;
42+
}
2843
replace({ scope: newScope === "environment" ? undefined : newScope });
2944
};
3045

@@ -57,8 +72,8 @@ export function ScopeFilter({ shortcut }: { shortcut?: ShortcutDefinition } = {}
5772
/>
5873
</Ariakit.TooltipAnchor>
5974
{shortcut && (
60-
<Ariakit.Tooltip className="z-40 cursor-default rounded border border-charcoal-700 bg-background-bright py-1.5 pl-2.5 pr-3 text-xs text-text-dimmed">
61-
<div className="flex items-center gap-3">
75+
<Ariakit.Tooltip className="z-40 cursor-default rounded border border-charcoal-700 bg-background-bright py-1.5 pl-2.5 pr-2 text-xs text-text-dimmed">
76+
<div className="flex items-center gap-1.5">
6277
<span>Change scope</span>
6378
<ShortcutKey className="size-4 flex-none" shortcut={shortcut} variant="small" />
6479
</div>

apps/webapp/app/components/primitives/Select.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export interface SelectProps<TValue extends string | string[], TItem>
104104
open?: boolean;
105105
setOpen?: (open: boolean) => void;
106106
shortcut?: ShortcutDefinition;
107+
tooltipTitle?: string;
107108
allowItemShortcuts?: boolean;
108109
clearSearchOnSelection?: boolean;
109110
dropdownIcon?: boolean | React.ReactNode;
@@ -127,6 +128,7 @@ export function Select<TValue extends string | string[], TItem>({
127128
open,
128129
setOpen,
129130
shortcut,
131+
tooltipTitle,
130132
allowItemShortcuts = true,
131133
disabled,
132134
clearSearchOnSelection = true,
@@ -206,6 +208,7 @@ export function Select<TValue extends string | string[], TItem>({
206208
text={text}
207209
placeholder={placeholder}
208210
shortcut={shortcut}
211+
tooltipTitle={tooltipTitle}
209212
disabled={disabled}
210213
dropdownIcon={dropdownIcon}
211214
{...props}

apps/webapp/app/components/query/QueryEditor.tsx

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
type QueryWidgetData,
3838
} from "~/components/metrics/QueryWidget";
3939
import { SaveToDashboardDialog } from "~/components/metrics/SaveToDashboardDialog";
40+
import { ScopeFilter } from "~/components/metrics/ScopeFilter";
4041
import { Button, LinkButton } from "~/components/primitives/Buttons";
4142
import { Callout } from "~/components/primitives/Callout";
4243
import {
@@ -89,12 +90,6 @@ function toISOString(value: Date | string): string {
8990
return value.toISOString();
9091
}
9192

92-
const scopeOptions = [
93-
{ value: "environment", label: "Environment" },
94-
{ value: "project", label: "Project" },
95-
{ value: "organization", label: "Organization" },
96-
] as const;
97-
9893
// Type for the query action response
9994
type QueryActionResponse = {
10095
error: string | null;
@@ -277,7 +272,7 @@ const QueryEditorForm = forwardRef<
277272
<input type="hidden" name="from" value={from ?? ""} />
278273
<input type="hidden" name="to" value={to ?? ""} />
279274
<QueryHistoryPopover history={history} onQuerySelected={handleHistorySelected} />
280-
<div className="flex items-center gap-1">
275+
<div className="flex items-center gap-1.5">
281276
{isAdmin && (
282277
<Button
283278
type="submit"
@@ -289,24 +284,11 @@ const QueryEditorForm = forwardRef<
289284
Explain
290285
</Button>
291286
)}
292-
<Select
287+
<ScopeFilter
293288
value={scope}
294-
setValue={(value) => setScope(value as QueryScope)}
295-
variant="secondary/small"
296-
dropdownIcon={true}
297-
items={[...scopeOptions]}
298-
text={(value) => {
299-
return <ScopeItem scope={value as QueryScope} />;
300-
}}
301-
>
302-
{(items) =>
303-
items.map((item) => (
304-
<SelectItem key={item.value} value={item.value}>
305-
<ScopeItem scope={item.value as QueryScope} />
306-
</SelectItem>
307-
))
308-
}
309-
</Select>
289+
onValueChange={setScope}
290+
shortcut={{ key: "e" }}
291+
/>
310292
{queryHasTriggeredAt ? (
311293
<SimpleTooltip
312294
asChild
@@ -335,6 +317,7 @@ const QueryEditorForm = forwardRef<
335317
period={period}
336318
from={from}
337319
to={to}
320+
shortcut={{ key: "d" }}
338321
applyShortcut={{ key: "enter", enabledOnInputElements: true }}
339322
onValueChange={(values) => {
340323
flushSync(() => {
@@ -1133,27 +1116,6 @@ function ExportResultsButton({
11331116
);
11341117
}
11351118

1136-
function ScopeItem({ scope }: { scope: QueryScope }) {
1137-
const organization = useOrganization();
1138-
const project = useProject();
1139-
const environment = useEnvironment();
1140-
1141-
switch (scope) {
1142-
case "organization":
1143-
return <span className="text-text-bright">{`Org: ${organization.title}`}</span>;
1144-
case "project":
1145-
return <span className="text-text-bright">{`Project: ${project.name}`}</span>;
1146-
case "environment":
1147-
return (
1148-
<span className="text-text-bright">
1149-
Env: <EnvironmentLabel environment={environment} />
1150-
</span>
1151-
);
1152-
default:
1153-
return <span className="text-text-bright">{scope}</span>;
1154-
}
1155-
}
1156-
11571119
function QueryResultsCallouts({
11581120
hiddenColumns,
11591121
periodClipped,

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { Popover, PopoverTrigger } from "~/components/primitives/Popover";
55
import * as PopoverPrimitive from "@radix-ui/react-popover";
66
import type { QueryHistoryItem } from "~/presenters/v3/QueryPresenter.server";
77
import { timeFilterRenderValues } from "~/components/runs/v3/SharedFilters";
8-
import { ChevronUpDownIcon } from "@heroicons/react/20/solid";
98
import { cn } from "~/utils/cn";
109

1110
const SQL_KEYWORDS = [
@@ -97,8 +96,9 @@ export function QueryHistoryPopover({
9796
variant="secondary/small"
9897
LeadingIcon={ClockRotateLeftIcon}
9998
leadingIconClassName="-mr-1.5"
100-
TrailingIcon={ChevronUpDownIcon}
10199
disabled={history.length === 0}
100+
tooltip="Query history"
101+
shortcut={{ key: "h" }}
102102
>
103103
History
104104
</Button>

0 commit comments

Comments
 (0)