Skip to content

Commit d4a23bd

Browse files
committed
fix(tracemetrics): Decode saved query sorts into separate sample and aggregate sorts
Split orderby → sortBys and aggregateOrderby → aggregateSortBys when restoring a saved query URL, so each table retains its own sort order. Add tests covering the new decoding and backwards compatibility.
1 parent cdefa6b commit d4a23bd

File tree

2 files changed

+155
-2
lines changed

2 files changed

+155
-2
lines changed

static/app/views/explore/metrics/utils.spec.tsx

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import {mapMetricUnitToFieldType} from 'sentry/views/explore/metrics/utils';
1+
import qs from 'query-string';
2+
import {OrganizationFixture} from 'sentry-fixture/organization';
3+
4+
import {SavedQuery} from 'sentry/views/explore/hooks/useGetSavedQueries';
5+
import {decodeMetricsQueryParams} from 'sentry/views/explore/metrics/metricQuery';
6+
import {
7+
getMetricsUrlFromSavedQueryUrl,
8+
mapMetricUnitToFieldType,
9+
} from 'sentry/views/explore/metrics/utils';
10+
import {Mode} from 'sentry/views/explore/queryParams/mode';
211

312
describe('mapMetricUnitToFieldType', () => {
413
it.each([
@@ -18,3 +27,144 @@ describe('mapMetricUnitToFieldType', () => {
1827
expect(mapMetricUnitToFieldType(unit)).toEqual(expected);
1928
});
2029
});
30+
31+
describe('getMetricsUrlFromSavedQueryUrl', () => {
32+
const organization = OrganizationFixture();
33+
34+
function decodeMetricFromUrl(url: string) {
35+
const query = qs.parseUrl(url).query;
36+
const metricParam = Array.isArray(query.metric) ? query.metric[0] : query.metric;
37+
return decodeMetricsQueryParams(metricParam!);
38+
}
39+
40+
it('decodes orderby into sortBys', () => {
41+
const url = getMetricsUrlFromSavedQueryUrl({
42+
organization,
43+
savedQuery: new SavedQuery({
44+
id: 1,
45+
interval: '5m',
46+
name: 'test query',
47+
projects: [],
48+
dataset: 'metrics',
49+
dateAdded: '2025-01-01T00:00:00.000000Z',
50+
dateUpdated: '2025-01-01T00:00:00.000000Z',
51+
lastVisited: '2025-01-01T00:00:00.000000Z',
52+
starred: false,
53+
position: null,
54+
query: [
55+
{
56+
mode: Mode.SAMPLES,
57+
query: '',
58+
fields: ['id', 'timestamp'],
59+
orderby: '-value',
60+
aggregateField: [{yAxes: ['sum(value,test_metric,counter,-)']}],
61+
metric: {name: 'test_metric', type: 'counter'},
62+
},
63+
],
64+
}),
65+
});
66+
67+
const decoded = decodeMetricFromUrl(url);
68+
expect(decoded?.queryParams.sortBys).toEqual([{field: 'value', kind: 'desc'}]);
69+
});
70+
71+
it('decodes aggregateOrderby into aggregateSortBys', () => {
72+
const url = getMetricsUrlFromSavedQueryUrl({
73+
organization,
74+
savedQuery: new SavedQuery({
75+
id: 1,
76+
interval: '5m',
77+
name: 'test query',
78+
projects: [],
79+
dataset: 'metrics',
80+
dateAdded: '2025-01-01T00:00:00.000000Z',
81+
dateUpdated: '2025-01-01T00:00:00.000000Z',
82+
lastVisited: '2025-01-01T00:00:00.000000Z',
83+
starred: false,
84+
position: null,
85+
query: [
86+
{
87+
mode: Mode.SAMPLES,
88+
query: '',
89+
fields: ['id', 'timestamp'],
90+
orderby: '-timestamp',
91+
aggregateOrderby: '-sum(value,test_metric,counter,-)',
92+
aggregateField: [{yAxes: ['sum(value,test_metric,counter,-)']}],
93+
metric: {name: 'test_metric', type: 'counter'},
94+
},
95+
],
96+
}),
97+
});
98+
99+
const decoded = decodeMetricFromUrl(url);
100+
expect(decoded?.queryParams.sortBys).toEqual([{field: 'timestamp', kind: 'desc'}]);
101+
expect(decoded?.queryParams.aggregateSortBys).toEqual([
102+
{field: 'sum(value,test_metric,counter,-)', kind: 'desc'},
103+
]);
104+
});
105+
106+
it('falls back to defaults when aggregateOrderby is missing (backwards compat)', () => {
107+
const url = getMetricsUrlFromSavedQueryUrl({
108+
organization,
109+
savedQuery: new SavedQuery({
110+
id: 1,
111+
interval: '5m',
112+
name: 'test query',
113+
projects: [],
114+
dataset: 'metrics',
115+
dateAdded: '2025-01-01T00:00:00.000000Z',
116+
dateUpdated: '2025-01-01T00:00:00.000000Z',
117+
lastVisited: '2025-01-01T00:00:00.000000Z',
118+
starred: false,
119+
position: null,
120+
query: [
121+
{
122+
mode: Mode.SAMPLES,
123+
query: '',
124+
fields: ['id', 'timestamp'],
125+
orderby: '-timestamp',
126+
aggregateField: [{yAxes: ['sum(value,test_metric,counter,-)']}],
127+
metric: {name: 'test_metric', type: 'counter'},
128+
},
129+
],
130+
}),
131+
});
132+
133+
const decoded = decodeMetricFromUrl(url);
134+
expect(decoded?.queryParams.sortBys).toEqual([{field: 'timestamp', kind: 'desc'}]);
135+
expect(decoded?.queryParams.aggregateSortBys).toEqual([
136+
{field: 'sum(value,test_metric,counter,-)', kind: 'desc'},
137+
]);
138+
});
139+
140+
it('falls back to defaults when orderby is missing', () => {
141+
const url = getMetricsUrlFromSavedQueryUrl({
142+
organization,
143+
savedQuery: new SavedQuery({
144+
id: 1,
145+
interval: '5m',
146+
name: 'test query',
147+
projects: [],
148+
dataset: 'metrics',
149+
dateAdded: '2025-01-01T00:00:00.000000Z',
150+
dateUpdated: '2025-01-01T00:00:00.000000Z',
151+
lastVisited: '2025-01-01T00:00:00.000000Z',
152+
starred: false,
153+
position: null,
154+
query: [
155+
{
156+
mode: Mode.SAMPLES,
157+
query: '',
158+
fields: ['id', 'timestamp'],
159+
orderby: '',
160+
aggregateField: [{yAxes: ['sum(value,test_metric,counter,-)']}],
161+
metric: {name: 'test_metric', type: 'counter'},
162+
},
163+
],
164+
}),
165+
});
166+
167+
const decoded = decodeMetricFromUrl(url);
168+
expect(decoded?.queryParams.sortBys).toEqual([{field: 'timestamp', kind: 'desc'}]);
169+
});
170+
});

static/app/views/explore/metrics/utils.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ export function getMetricsUrlFromSavedQueryUrl({
145145
mode: queryItem.mode,
146146
query: queryItem.query,
147147
aggregateFields,
148-
aggregateSortBys: decodeSorts(queryItem.orderby) || [],
148+
aggregateSortBys: queryItem.aggregateOrderby
149+
? decodeSorts(queryItem.aggregateOrderby)
150+
: undefined,
151+
sortBys: queryItem.orderby ? decodeSorts(queryItem.orderby) : undefined,
149152
}),
150153
};
151154
});

0 commit comments

Comments
 (0)