Skip to content

Commit 1504c9b

Browse files
JonasBamalwilley
andauthored
ref(nuqs): Use nuqs in monitor list page (#104524)
~Taking over @malwilley's PR that was marked as stale. Seems like there might be some issues with Nuqs, so I'm taking a quick look~ It appears as if we got a bit lucky with this changeset, and the file that was failing our tests has since been deleted. --------- Co-authored-by: Malachi Willey <malwilley@gmail.com>
1 parent 9e72a7d commit 1504c9b

File tree

6 files changed

+33
-45
lines changed

6 files changed

+33
-45
lines changed

static/app/utils/queryString.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {createParser} from 'nuqs';
12
import * as qs from 'query-string';
23

34
import {escapeDoubleQuotes} from 'sentry/utils';
@@ -166,6 +167,16 @@ export function decodeBoolean(
166167
return fallback;
167168
}
168169

170+
export const parseAsSort = createParser({
171+
parse: value => {
172+
const sorts = decodeSorts(value);
173+
return sorts[0] ? sorts[0] : null;
174+
},
175+
serialize: (value: Sort) => {
176+
return value.kind === 'desc' ? `-${value.field}` : value.field;
177+
},
178+
});
179+
169180
const queryString = {
170181
decodeBoolean,
171182
decodeInteger,

static/app/views/detectors/components/detectorListTable/index.tsx

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from 'react';
99
import {css, type Theme} from '@emotion/react';
1010
import styled from '@emotion/styled';
11+
import {useQueryState} from 'nuqs';
1112

1213
import {
1314
GridLineLabels,
@@ -21,17 +22,15 @@ import {t} from 'sentry/locale';
2122
import {space} from 'sentry/styles/space';
2223
import type {Detector} from 'sentry/types/workflowEngine/detectors';
2324
import {defined} from 'sentry/utils';
24-
import type {Sort} from 'sentry/utils/discover/fields';
2525
import {useDebouncedValue} from 'sentry/utils/useDebouncedValue';
2626
import {useDimensions} from 'sentry/utils/useDimensions';
27-
import {useLocation} from 'sentry/utils/useLocation';
28-
import {useNavigate} from 'sentry/utils/useNavigate';
2927
import {DetectorsTableActions} from 'sentry/views/detectors/components/detectorListTable/actions';
3028
import {
3129
DetectorListRow,
3230
DetectorListRowSkeleton,
3331
} from 'sentry/views/detectors/components/detectorListTable/detectorListRow';
3432
import {DETECTOR_LIST_PAGE_LIMIT} from 'sentry/views/detectors/list/common/constants';
33+
import {useDetectorListSort} from 'sentry/views/detectors/list/common/useDetectorListSort';
3534
import {
3635
useMonitorViewContext,
3736
type MonitorListAdditionalColumn,
@@ -47,7 +46,6 @@ type DetectorListTableProps = {
4746
isPending: boolean;
4847
isSuccess: boolean;
4948
queryCount: string;
50-
sort: Sort | undefined;
5149
};
5250

5351
function LoadingSkeletons() {
@@ -59,27 +57,22 @@ function LoadingSkeletons() {
5957
export function HeaderCell({
6058
children,
6159
sortKey,
62-
sort,
6360
...props
6461
}: {
65-
sort: Sort | undefined;
6662
children?: React.ReactNode;
6763
divider?: boolean;
6864
sortKey?: string;
6965
} & Omit<ComponentProps<typeof SimpleTable.HeaderCell>, 'sort'>) {
70-
const location = useLocation();
71-
const navigate = useNavigate();
66+
const [sort, setSort] = useDetectorListSort();
67+
const [, setCursor] = useQueryState('cursor');
7268
const isSortedByField = sort?.field === sortKey;
7369
const handleSort = () => {
7470
if (!sortKey) {
7571
return;
7672
}
77-
const newSort =
78-
sort && isSortedByField ? `${sort.kind === 'asc' ? '-' : ''}${sortKey}` : sortKey;
79-
navigate({
80-
pathname: location.pathname,
81-
query: {...location.query, sort: newSort, cursor: undefined},
82-
});
73+
const sortDirection = sort && isSortedByField && sort.kind === 'asc' ? 'desc' : 'asc';
74+
setSort({field: sortKey, kind: sortDirection});
75+
setCursor(null);
8376
};
8477

8578
return (
@@ -98,7 +91,6 @@ function DetectorListTable({
9891
isPending,
9992
isError,
10093
isSuccess,
101-
sort,
10294
queryCount,
10395
allResultsVisible,
10496
}: DetectorListTableProps) {
@@ -160,7 +152,7 @@ function DetectorListTable({
160152
>
161153
{selected.size === 0 ? (
162154
<SimpleTable.Header>
163-
<HeaderCell sortKey="name" sort={sort}>
155+
<HeaderCell sortKey="name">
164156
<Flex gap="md" align="center">
165157
<SelectAllHeaderCheckbox
166158
checked={pageSelected || (anySelected ? 'indeterminate' : false)}
@@ -169,25 +161,19 @@ function DetectorListTable({
169161
<span>{t('Name')}</span>
170162
</Flex>
171163
</HeaderCell>
172-
<HeaderCell data-column-name="type" divider sortKey="type" sort={sort}>
164+
<HeaderCell data-column-name="type" divider sortKey="type">
173165
{t('Type')}
174166
</HeaderCell>
175-
<HeaderCell
176-
data-column-name="last-issue"
177-
divider
178-
sortKey="latestGroup"
179-
sort={sort}
180-
>
167+
<HeaderCell data-column-name="last-issue" divider sortKey="latestGroup">
181168
{t('Last Issue')}
182169
</HeaderCell>
183-
<HeaderCell data-column-name="assignee" divider sort={sort}>
170+
<HeaderCell data-column-name="assignee" divider>
184171
{t('Assignee')}
185172
</HeaderCell>
186173
<HeaderCell
187174
data-column-name="connected-automations"
188175
divider
189176
sortKey="connectedWorkflows"
190-
sort={sort}
191177
>
192178
{t('Alerts')}
193179
</HeaderCell>

static/app/views/detectors/list/common/detectorListContent.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {VisuallyCompleteWithData} from 'sentry/utils/performanceForSentry';
77
import {useLocation} from 'sentry/utils/useLocation';
88
import {useNavigate} from 'sentry/utils/useNavigate';
99
import DetectorListTable from 'sentry/views/detectors/components/detectorListTable';
10-
import {useDetectorListSort} from 'sentry/views/detectors/list/common/useDetectorListSort';
1110

1211
interface DetectorListContentProps {
1312
data: Detector[] | undefined;
@@ -28,7 +27,6 @@ export function DetectorListContent({
2827
}: DetectorListContentProps) {
2928
const location = useLocation();
3029
const navigate = useNavigate();
31-
const sort = useDetectorListSort();
3230

3331
const hits = getResponseHeader?.('X-Hits') || '';
3432
const hitsInt = hits ? parseInt(hits, 10) || 0 : 0;
@@ -61,7 +59,6 @@ export function DetectorListContent({
6159
isPending={isLoading}
6260
isError={isError}
6361
isSuccess={isSuccess}
64-
sort={sort}
6562
queryCount={hitsInt > maxHitsInt ? `${maxHits}+` : hits}
6663
allResultsVisible={allResultsVisible()}
6764
/>

static/app/views/detectors/list/common/useDetectorListQuery.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function useDetectorListQuery({
1919
const {selection, isReady} = usePageFilters();
2020
const cursor = decodeScalar(location.query.cursor);
2121
const query = decodeScalar(location.query.query);
22-
const sort = useDetectorListSort();
22+
const [sort] = useDetectorListSort();
2323

2424
// Build the query with detector type and assignee filters if provided
2525
// Map DetectorType values to query values (e.g., 'monitor_check_in_failure' -> 'cron')
Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
import type {Sort} from 'sentry/utils/discover/fields';
2-
import {decodeSorts} from 'sentry/utils/queryString';
3-
import {useLocation} from 'sentry/utils/useLocation';
1+
import {useQueryState} from 'nuqs';
42

5-
const DEFAULT_SORT: Sort = {kind: 'desc', field: 'latestGroup'};
3+
import {parseAsSort} from 'sentry/utils/queryString';
64

7-
export function useDetectorListSort(): Sort {
8-
const location = useLocation();
9-
const sort = decodeSorts(location.query.sort)[0];
10-
11-
if (!sort) {
12-
return DEFAULT_SORT;
13-
}
14-
15-
return sort;
5+
export function useDetectorListSort() {
6+
return useQueryState(
7+
'sort',
8+
parseAsSort.withDefault({kind: 'desc', field: 'latestGroup'}).withOptions({
9+
history: 'push',
10+
})
11+
);
1612
}

static/app/views/detectors/list/cron.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,7 @@ const ADDITIONAL_COLUMNS: MonitorListAdditionalColumn[] = [
100100
{
101101
id: 'environment-label',
102102
columnWidth: '120px',
103-
renderHeaderCell: () => (
104-
<HeaderCell data-column-name="environment-label" sort={undefined} />
105-
),
103+
renderHeaderCell: () => <HeaderCell data-column-name="environment-label" />,
106104
renderCell: (detector: Detector) => {
107105
if (detector.type !== 'monitor_check_in_failure') {
108106
return null;

0 commit comments

Comments
 (0)