Skip to content

Commit 87c723a

Browse files
authored
ref(explore): Use sort type from discover (#76220)
Discover already defines a `Sort` type, so let's try to reuse that instead of redefining our own.
1 parent c6af9cc commit 87c723a

File tree

8 files changed

+288
-194
lines changed

8 files changed

+288
-194
lines changed

static/app/views/explore/hooks/useSort.spec.tsx

Lines changed: 0 additions & 74 deletions
This file was deleted.

static/app/views/explore/hooks/useSort.tsx

Lines changed: 0 additions & 77 deletions
This file was deleted.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import {createMemoryHistory, Route, Router, RouterContext} from 'react-router';
2+
3+
import {act, render} from 'sentry-test/reactTestingLibrary';
4+
5+
import {useSorts} from 'sentry/views/explore/hooks/useSorts';
6+
import {RouteContext} from 'sentry/views/routeContext';
7+
8+
describe('useSorts', function () {
9+
it('allows changing sorts', function () {
10+
let sorts, setSorts;
11+
12+
const fields = ['id', 'timestamp'];
13+
14+
function TestPage() {
15+
[sorts, setSorts] = useSorts({fields});
16+
return null;
17+
}
18+
19+
const memoryHistory = createMemoryHistory();
20+
21+
render(
22+
<Router
23+
history={memoryHistory}
24+
render={props => {
25+
return (
26+
<RouteContext.Provider value={props}>
27+
<RouterContext {...props} />
28+
</RouteContext.Provider>
29+
);
30+
}}
31+
>
32+
<Route path="/" component={TestPage} />
33+
</Router>
34+
);
35+
36+
expect(sorts).toEqual([
37+
{
38+
kind: 'desc',
39+
field: 'timestamp',
40+
},
41+
]); // default
42+
43+
act(() =>
44+
setSorts([
45+
{
46+
kind: 'asc',
47+
field: 'timestamp',
48+
},
49+
])
50+
);
51+
expect(sorts).toEqual([
52+
{
53+
kind: 'asc',
54+
field: 'timestamp',
55+
},
56+
]);
57+
58+
act(() =>
59+
setSorts([
60+
{
61+
kind: 'desc',
62+
field: 'id',
63+
},
64+
])
65+
);
66+
expect(sorts).toEqual([
67+
{
68+
kind: 'desc',
69+
field: 'id',
70+
},
71+
]);
72+
});
73+
74+
it('falls back to timestamp desc if possible', function () {
75+
let sorts, setSorts;
76+
77+
const fields = ['id', 'timestamp'];
78+
79+
function TestPage() {
80+
[sorts, setSorts] = useSorts({fields});
81+
return null;
82+
}
83+
84+
const memoryHistory = createMemoryHistory();
85+
86+
render(
87+
<Router
88+
history={memoryHistory}
89+
render={props => {
90+
return (
91+
<RouteContext.Provider value={props}>
92+
<RouterContext {...props} />
93+
</RouteContext.Provider>
94+
);
95+
}}
96+
>
97+
<Route path="/" component={TestPage} />
98+
</Router>
99+
);
100+
act(() =>
101+
setSorts([
102+
{
103+
kind: 'asc',
104+
field: 'foo',
105+
},
106+
])
107+
);
108+
expect(sorts).toEqual([
109+
{
110+
kind: 'desc',
111+
field: 'timestamp',
112+
},
113+
]);
114+
});
115+
116+
it('falls back to first column desc if timestamp is not available', function () {
117+
let sorts, setSorts;
118+
119+
const fields = ['id'];
120+
121+
function TestPage() {
122+
[sorts, setSorts] = useSorts({fields});
123+
return null;
124+
}
125+
126+
const memoryHistory = createMemoryHistory();
127+
128+
render(
129+
<Router
130+
history={memoryHistory}
131+
render={props => {
132+
return (
133+
<RouteContext.Provider value={props}>
134+
<RouterContext {...props} />
135+
</RouteContext.Provider>
136+
);
137+
}}
138+
>
139+
<Route path="/" component={TestPage} />
140+
</Router>
141+
);
142+
act(() =>
143+
setSorts([
144+
{
145+
kind: 'asc',
146+
field: 'foo',
147+
},
148+
])
149+
);
150+
expect(sorts).toEqual([
151+
{
152+
kind: 'desc',
153+
field: 'id',
154+
},
155+
]);
156+
});
157+
});
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {useCallback, useMemo} from 'react';
2+
import type {Location} from 'history';
3+
4+
import type {Sort} from 'sentry/utils/discover/fields';
5+
import {decodeSorts} from 'sentry/utils/queryString';
6+
import {useLocation} from 'sentry/utils/useLocation';
7+
import {useNavigate} from 'sentry/utils/useNavigate';
8+
9+
import type {Field} from './useSampleFields';
10+
11+
interface Options {
12+
fields: Field[];
13+
}
14+
15+
export function useSorts(props): [Sort[], (newSorts: Sort[]) => void] {
16+
const location = useLocation();
17+
const navigate = useNavigate();
18+
const options = {location, navigate, ...props};
19+
20+
return useSortsImpl(options);
21+
}
22+
23+
interface ImplOptions extends Options {
24+
location: Location;
25+
navigate: ReturnType<typeof useNavigate>;
26+
}
27+
28+
function useSortsImpl({
29+
fields,
30+
location,
31+
navigate,
32+
}: ImplOptions): [Sort[], (newSorts: Sort[]) => void] {
33+
const sorts = useMemo(() => {
34+
const rawSorts = decodeSorts(location.query.sort);
35+
36+
// Try to assign a default sort if possible
37+
if (!rawSorts.length || !rawSorts.some(rawSort => fields.includes(rawSort.field))) {
38+
if (fields.includes('timestamp')) {
39+
return [
40+
{
41+
field: 'timestamp',
42+
kind: 'desc' as const,
43+
},
44+
];
45+
}
46+
47+
if (fields.length) {
48+
return [
49+
{
50+
field: fields[0],
51+
kind: 'desc' as const,
52+
},
53+
];
54+
}
55+
56+
return [];
57+
}
58+
59+
return rawSorts;
60+
}, [fields, location.query.sort]);
61+
62+
const setSort = useCallback(
63+
(newSorts: Sort[]) => {
64+
const formatted = newSorts.map(newSort => {
65+
return newSort.kind === 'desc' ? `-${newSort.field}` : newSort.field;
66+
});
67+
navigate({
68+
...location,
69+
query: {
70+
...location.query,
71+
sort: formatted,
72+
},
73+
});
74+
},
75+
[location, navigate]
76+
);
77+
78+
return [sorts, setSort];
79+
}

0 commit comments

Comments
 (0)