Skip to content

Commit 2d27fe2

Browse files
authored
fix: Support JSON keys in dashboard filters (#1271)
1 parent 2dc0079 commit 2d27fe2

File tree

5 files changed

+36
-6
lines changed

5 files changed

+36
-6
lines changed

.changeset/fifty-garlics-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hyperdx/app": patch
3+
---
4+
5+
fix: Support JSON keys in dashboard filters

packages/app/src/DBDashboardPage.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,6 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
10831083
<Tooltip withArrow label="Edit Filters" fz="xs" color="gray">
10841084
<Button
10851085
variant="outline"
1086-
type="submit"
10871086
color="gray"
10881087
px="xs"
10891088
mr={6}

packages/app/src/__tests__/searchFilters.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,19 @@ describe('searchFilters', () => {
5252
{ type: 'sql', condition: "a NOT IN ('c')" },
5353
]);
5454
});
55+
56+
it('should wrap keys with toString() when specified', () => {
57+
const filters = {
58+
'json.key': {
59+
included: new Set<string>(['value']),
60+
excluded: new Set<string>(['other value']),
61+
},
62+
};
63+
expect(filtersToQuery(filters, { stringifyKeys: true })).toEqual([
64+
{ type: 'sql', condition: "toString(json.key) IN ('value')" },
65+
{ type: 'sql', condition: "toString(json.key) NOT IN ('other value')" },
66+
]);
67+
});
5568
});
5669

5770
describe('parseQuery', () => {

packages/app/src/hooks/useDashboardFilters.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ const useDashboardFilters = (filters: DashboardFilter[]) => {
2323
};
2424
}
2525

26-
return filtersToQuery(filterValues);
26+
return filtersToQuery(
27+
filterValues,
28+
{ stringifyKeys: false }, // Don't wrap keys with toString(), to preserve exact key names in URL query parameters
29+
);
2730
});
2831
},
2932
[setFilterQueries],
@@ -42,7 +45,12 @@ const useDashboardFilters = (filters: DashboardFilter[]) => {
4245

4346
return {
4447
valuesForExistingFilters,
45-
queriesForExistingFilters: filtersToQuery(valuesForExistingFilters),
48+
queriesForExistingFilters: filtersToQuery(
49+
valuesForExistingFilters,
50+
// Wrap keys in `toString()` to support JSON/Dynamic-type columns.
51+
// All keys can be stringified, since filter select values are stringified as well.
52+
{ stringifyKeys: true },
53+
),
4654
};
4755
}, [filterQueries, filters]);
4856

packages/app/src/searchFilters.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,30 @@ export type FilterState = {
1111
};
1212
};
1313

14-
export const filtersToQuery = (filters: FilterState): Filter[] => {
14+
export const filtersToQuery = (
15+
filters: FilterState,
16+
{ stringifyKeys = false }: { stringifyKeys?: boolean } = {},
17+
): Filter[] => {
1518
return Object.entries(filters)
1619
.filter(
1720
([_, values]) => values.included.size > 0 || values.excluded.size > 0,
1821
)
1922
.flatMap(([key, values]) => {
2023
const conditions = [];
24+
const actualKey = stringifyKeys ? `toString(${key})` : key;
25+
2126
if (values.included.size > 0) {
2227
conditions.push({
2328
type: 'sql' as const,
24-
condition: `${key} IN (${Array.from(values.included)
29+
condition: `${actualKey} IN (${Array.from(values.included)
2530
.map(v => `'${v}'`)
2631
.join(', ')})`,
2732
});
2833
}
2934
if (values.excluded.size > 0) {
3035
conditions.push({
3136
type: 'sql' as const,
32-
condition: `${key} NOT IN (${Array.from(values.excluded)
37+
condition: `${actualKey} NOT IN (${Array.from(values.excluded)
3338
.map(v => `'${v}'`)
3439
.join(', ')})`,
3540
});

0 commit comments

Comments
 (0)