Skip to content

Commit 1e7d424

Browse files
committed
ref(tsc): dashboards endpoint to apiOptions
1 parent a16fcfa commit 1e7d424

File tree

6 files changed

+128
-111
lines changed

6 files changed

+128
-111
lines changed
Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,56 @@
1+
import {useQuery} from '@tanstack/react-query';
2+
13
import type {Organization} from 'sentry/types/organization';
2-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
3-
import type {ApiQueryKey} from 'sentry/utils/queryClient';
4-
import {useApiQuery} from 'sentry/utils/queryClient';
4+
import {apiOptions} from 'sentry/utils/api/apiOptions';
55
import {useHasProjectAccess} from 'sentry/utils/useHasProjectAccess';
66
import {useOrganization} from 'sentry/utils/useOrganization';
77
import type {DashboardListItem} from 'sentry/views/dashboards/types';
88

9-
export function getStarredDashboardsQueryKey(organization: Organization): ApiQueryKey {
10-
const DASHBOARDS_QUERY_KEY = [
11-
getApiUrl('/organizations/$organizationIdOrSlug/dashboards/', {
12-
path: {organizationIdOrSlug: organization.slug},
13-
}),
9+
export function getStarredDashboardsQueryKey(organization: Organization) {
10+
if (organization.features.includes('dashboards-starred-reordering')) {
11+
return apiOptions.as<DashboardListItem[]>()(
12+
'/organizations/$organizationIdOrSlug/dashboards/starred/',
13+
{
14+
path: {organizationIdOrSlug: organization.slug},
15+
staleTime: Infinity,
16+
}
17+
).queryKey;
18+
}
19+
return apiOptions.as<DashboardListItem[]>()(
20+
'/organizations/$organizationIdOrSlug/dashboards/',
1421
{
15-
query: {
16-
filter: 'onlyFavorites',
17-
},
18-
},
19-
] as const;
20-
const STARRED_DASHBOARDS_QUERY_KEY = [
21-
getApiUrl('/organizations/$organizationIdOrSlug/dashboards/starred/', {
2222
path: {organizationIdOrSlug: organization.slug},
23-
}),
24-
{},
25-
] as const;
26-
return organization.features.includes('dashboards-starred-reordering')
27-
? STARRED_DASHBOARDS_QUERY_KEY
28-
: DASHBOARDS_QUERY_KEY;
23+
query: {filter: 'onlyFavorites'},
24+
staleTime: Infinity,
25+
}
26+
).queryKey;
2927
}
3028

3129
export function useGetStarredDashboards() {
3230
const organization = useOrganization();
3331
const {hasProjectAccess, projectsLoaded} = useHasProjectAccess();
3432

35-
return useApiQuery<DashboardListItem[]>(getStarredDashboardsQueryKey(organization), {
36-
staleTime: Infinity,
33+
const usesStarredEndpoint = organization.features.includes(
34+
'dashboards-starred-reordering'
35+
);
36+
37+
return useQuery({
38+
...(usesStarredEndpoint
39+
? apiOptions.as<DashboardListItem[]>()(
40+
'/organizations/$organizationIdOrSlug/dashboards/starred/',
41+
{
42+
path: {organizationIdOrSlug: organization.slug},
43+
staleTime: Infinity,
44+
}
45+
)
46+
: apiOptions.as<DashboardListItem[]>()(
47+
'/organizations/$organizationIdOrSlug/dashboards/',
48+
{
49+
path: {organizationIdOrSlug: organization.slug},
50+
query: {filter: 'onlyFavorites'},
51+
staleTime: Infinity,
52+
}
53+
)),
3754
enabled: hasProjectAccess || !projectsLoaded,
3855
});
3956
}
Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
2-
import {useApiQuery} from 'sentry/utils/queryClient';
1+
import {useQuery} from '@tanstack/react-query';
2+
3+
import {apiOptions, selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
34
import {useOrganization} from 'sentry/utils/useOrganization';
45
import type {DashboardListItem} from 'sentry/views/dashboards/types';
56

@@ -15,12 +16,11 @@ export function useOwnedDashboards({
1516
sort: string;
1617
}) {
1718
const organization = useOrganization();
18-
return useApiQuery<DashboardListItem[]>(
19-
[
20-
getApiUrl('/organizations/$organizationIdOrSlug/dashboards/', {
21-
path: {organizationIdOrSlug: organization.slug},
22-
}),
19+
return useQuery({
20+
...apiOptions.as<DashboardListItem[]>()(
21+
'/organizations/$organizationIdOrSlug/dashboards/',
2322
{
23+
path: {organizationIdOrSlug: organization.slug},
2424
query: {
2525
query,
2626
cursor,
@@ -29,11 +29,10 @@ export function useOwnedDashboards({
2929
pin: 'favorites',
3030
per_page: 20,
3131
},
32-
},
33-
],
34-
{
35-
staleTime: 0,
36-
enabled,
37-
}
38-
);
32+
staleTime: 0,
33+
}
34+
),
35+
select: selectJsonWithHeaders,
36+
enabled,
37+
});
3938
}

static/app/views/dashboards/manage/index.tsx

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Fragment, useEffect, useMemo, useRef, useState} from 'react';
22
import styled from '@emotion/styled';
33
import * as Sentry from '@sentry/react';
4+
import {useQuery} from '@tanstack/react-query';
45
import type {Query} from 'history';
56
import debounce from 'lodash/debounce';
67
import pick from 'lodash/pick';
@@ -31,10 +32,9 @@ import {IconAdd, IconGrid, IconList} from 'sentry/icons';
3132
import {t} from 'sentry/locale';
3233
import type {Organization} from 'sentry/types/organization';
3334
import {trackAnalytics} from 'sentry/utils/analytics';
34-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
35+
import {apiOptions, selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
3536
import {localStorageWrapper} from 'sentry/utils/localStorage';
3637
import {parseLinkHeader} from 'sentry/utils/parseLinkHeader';
37-
import {useApiQuery} from 'sentry/utils/queryClient';
3838
import {decodeScalar} from 'sentry/utils/queryString';
3939
import {scheduleMicroTask} from 'sentry/utils/scheduleMicroTask';
4040
import {normalizeUrl} from 'sentry/utils/url/normalizeUrl';
@@ -199,18 +199,16 @@ function ManageDashboards() {
199199
});
200200

201201
const {
202-
data: dashboardsWithoutPrebuiltConfigs,
202+
data: dashboardsResponse,
203203
isLoading,
204204
isError,
205205
error,
206-
getResponseHeader,
207206
refetch: refetchDashboards,
208-
} = useApiQuery<DashboardListItem[]>(
209-
[
210-
getApiUrl('/organizations/$organizationIdOrSlug/dashboards/', {
211-
path: {organizationIdOrSlug: organization.slug},
212-
}),
207+
} = useQuery({
208+
...apiOptions.as<DashboardListItem[]>()(
209+
'/organizations/$organizationIdOrSlug/dashboards/',
213210
{
211+
path: {organizationIdOrSlug: organization.slug},
214212
query: {
215213
...pick(location.query, ['cursor', 'query']),
216214
sort: getActiveSort()!.value,
@@ -221,18 +219,18 @@ function ManageDashboards() {
221219
? {filter: DashboardFilter.ONLY_PREBUILT}
222220
: {filter: DashboardFilter.EXCLUDE_PREBUILT}),
223221
},
224-
},
225-
],
226-
{
227-
staleTime: 0,
228-
enabled:
229-
(hasProjectAccess || !projectsLoaded) &&
230-
!(
231-
organization.features.includes('dashboards-starred-reordering') &&
232-
dashboardsLayout === TABLE
233-
),
234-
}
235-
);
222+
staleTime: 0,
223+
}
224+
),
225+
select: selectJsonWithHeaders,
226+
enabled:
227+
(hasProjectAccess || !projectsLoaded) &&
228+
!(
229+
organization.features.includes('dashboards-starred-reordering') &&
230+
dashboardsLayout === TABLE
231+
),
232+
});
233+
const dashboardsWithoutPrebuiltConfigs = dashboardsResponse?.json;
236234

237235
const dashboards = useMemo(
238236
() =>
@@ -267,7 +265,7 @@ function ManageDashboards() {
267265
dashboardsLayout === TABLE,
268266
});
269267

270-
const dashboardsPageLinks = getResponseHeader?.('Link') ?? '';
268+
const dashboardsPageLinks = dashboardsResponse?.headers.Link ?? '';
271269

272270
function setRowsAndColumns(containerWidth: number) {
273271
const numWidgetsFitInRow = Math.floor(
@@ -510,9 +508,9 @@ function ManageDashboards() {
510508
/>
511509
) : organization.features.includes('dashboards-starred-reordering') ? (
512510
<OwnedDashboardsTable
513-
dashboards={ownedDashboards.data ?? []}
511+
dashboards={ownedDashboards.data?.json ?? []}
514512
isLoading={ownedDashboards.isLoading}
515-
pageLinks={ownedDashboards.getResponseHeader?.('Link') ?? undefined}
513+
pageLinks={ownedDashboards.data?.headers.Link}
516514
/>
517515
) : (
518516
<DashboardTable

static/app/views/dashboards/orgDashboards.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {useEffect, useMemo, useRef, useState} from 'react';
2+
import {useQuery, useQueryClient} from '@tanstack/react-query';
23
import isEqual from 'lodash/isEqual';
34

45
import {Stack} from '@sentry/scraps/layout';
@@ -8,8 +9,10 @@ import {LoadingError} from 'sentry/components/loadingError';
89
import {LoadingIndicator} from 'sentry/components/loadingIndicator';
910
import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle';
1011
import {t} from 'sentry/locale';
12+
import {apiOptions} from 'sentry/utils/api/apiOptions';
1113
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
12-
import {useApiQuery, useQueryClient} from 'sentry/utils/queryClient';
14+
import {useApiQuery} from 'sentry/utils/queryClient';
15+
import {RequestError} from 'sentry/utils/requestError/requestError';
1316
import {normalizeUrl} from 'sentry/utils/url/normalizeUrl';
1417
import {useLocation} from 'sentry/utils/useLocation';
1518
import {useNavigate} from 'sentry/utils/useNavigate';
@@ -46,10 +49,6 @@ export function OrgDashboards({children, initialDashboard}: OrgDashboardsProps)
4649
const dashboardRedirectRef = useRef<string | null>(null);
4750
const queryClient = useQueryClient();
4851

49-
const ENDPOINT = getApiUrl('/organizations/$organizationIdOrSlug/dashboards/', {
50-
path: {organizationIdOrSlug: organization.slug},
51-
});
52-
5352
// The currently selected dashboard. Use initialDashboard for optimistic updates
5453
// when navigating from widget builder (passed via location.state).
5554
const [selectedDashboardState, setSelectedDashboardState] =
@@ -60,7 +59,16 @@ export function OrgDashboards({children, initialDashboard}: OrgDashboardsProps)
6059
isPending: isDashboardsPending,
6160
isError: isDashboardsError,
6261
error: dashboardsError,
63-
} = useApiQuery<DashboardListItem[]>([ENDPOINT], {staleTime: 0, retry: false});
62+
} = useQuery({
63+
...apiOptions.as<DashboardListItem[]>()(
64+
'/organizations/$organizationIdOrSlug/dashboards/',
65+
{
66+
path: {organizationIdOrSlug: organization.slug},
67+
staleTime: 0,
68+
}
69+
),
70+
retry: false,
71+
});
6472

6573
const {
6674
data: fetchedSelectedDashboard,
@@ -189,10 +197,14 @@ export function OrgDashboards({children, initialDashboard}: OrgDashboardsProps)
189197
// a flicker from stale data on refetch
190198
return () => {
191199
queryClient.removeQueries({
192-
queryKey: [`${ENDPOINT}${dashboardId}/`],
200+
queryKey: [
201+
getApiUrl('/organizations/$organizationIdOrSlug/dashboards/$dashboardId/', {
202+
path: {organizationIdOrSlug: organization.slug, dashboardId},
203+
}),
204+
],
193205
});
194206
};
195-
}, [dashboardId, ENDPOINT, queryClient]);
207+
}, [dashboardId, organization.slug, queryClient]);
196208

197209
const childrenProps = useMemo(
198210
() => ({
@@ -235,7 +247,8 @@ export function OrgDashboards({children, initialDashboard}: OrgDashboardsProps)
235247

236248
if (isDashboardsError || isSelectedDashboardError) {
237249
const notFound =
238-
dashboardsError?.status === 404 || selectedDashboardError?.status === 404;
250+
(dashboardsError instanceof RequestError && dashboardsError.status === 404) ||
251+
selectedDashboardError?.status === 404;
239252

240253
if (notFound) {
241254
return <NotFound />;

static/app/views/dashboards/utils/usePopulateLinkedDashboards.tsx

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import {useMemo} from 'react';
22
import type {QueryClient} from '@tanstack/react-query';
3+
import {useQuery} from '@tanstack/react-query';
34

45
import {defined} from 'sentry/utils';
5-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
6-
import type {ApiQueryKey} from 'sentry/utils/queryClient';
7-
import {fetchDataQuery, useApiQuery} from 'sentry/utils/queryClient';
6+
import {apiOptions} from 'sentry/utils/api/apiOptions';
87
import {useOrganization} from 'sentry/utils/useOrganization';
98
import {
109
DashboardFilter,
@@ -46,13 +45,9 @@ export async function resolveLinkedDashboardIds({
4645
return dashboard;
4746
}
4847

49-
const queryKey = makeDashboardsQueryKey(orgSlug, prebuiltIds);
50-
51-
const [resolvedDashboards] = await queryClient.fetchQuery({
52-
queryKey,
53-
queryFn: fetchDataQuery<DashboardDetails[]>,
54-
staleTime: Infinity,
55-
});
48+
const resolvedDashboards = (
49+
await queryClient.fetchQuery(dashboardsByPrebuiltIdOptions(orgSlug, prebuiltIds))
50+
).json;
5651

5752
const resolvedIdMap = buildResolvedIdMap(resolvedDashboards);
5853
return replacePlaceholderLinkedDashboardIds(dashboard, resolvedIdMap);
@@ -73,17 +68,14 @@ const usePopulatePrebuiltIdsWithActualIds = (
7368

7469
const hasLinkedDashboards = prebuiltIds.length > 0;
7570

76-
const {data, isLoading} = useApiQuery<DashboardDetails[]>(
77-
makeDashboardsQueryKey(
71+
const {data, isLoading} = useQuery({
72+
...dashboardsByPrebuiltIdOptions(
7873
organization.slug,
7974
[...prebuiltIds, prebuiltId].filter(defined)
8075
),
81-
{
82-
enabled: hasLinkedDashboards || Boolean(prebuiltId),
83-
staleTime: Infinity,
84-
retry: false,
85-
}
86-
);
76+
enabled: hasLinkedDashboards || Boolean(prebuiltId),
77+
retry: false,
78+
});
8779

8880
return useMemo(() => {
8981
const populatedDashboard = {
@@ -162,19 +154,19 @@ function buildResolvedIdMap(
162154
return map;
163155
}
164156

165-
function makeDashboardsQueryKey(
157+
function dashboardsByPrebuiltIdOptions(
166158
orgSlug: string,
167159
prebuiltIds: PrebuiltDashboardId[]
168-
): ApiQueryKey {
169-
return [
170-
getApiUrl('/organizations/$organizationIdOrSlug/dashboards/', {
171-
path: {organizationIdOrSlug: orgSlug},
172-
}),
160+
) {
161+
return apiOptions.as<DashboardDetails[]>()(
162+
'/organizations/$organizationIdOrSlug/dashboards/',
173163
{
164+
path: {organizationIdOrSlug: orgSlug},
174165
query: {
175166
prebuiltId: prebuiltIds.sort(),
176167
filter: DashboardFilter.SHOW_HIDDEN,
177168
},
178-
},
179-
];
169+
staleTime: Infinity,
170+
}
171+
);
180172
}

0 commit comments

Comments
 (0)