Skip to content

Commit 86e1cf2

Browse files
TkDodogeorge-sentry
authored andcommitted
ref(tsc): move buildDetails endpoint to apiOptions (#112357)
1 parent 715c645 commit 86e1cf2

File tree

6 files changed

+78
-90
lines changed

6 files changed

+78
-90
lines changed

static/app/components/preprod/preprodBuildsTable.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {LoadingIndicator} from 'sentry/components/loadingIndicator';
77
import {Pagination} from 'sentry/components/pagination';
88
import {SimpleTable} from 'sentry/components/tables/simpleTable';
99
import {t, tct} from 'sentry/locale';
10-
import type {RequestError} from 'sentry/utils/requestError/requestError';
10+
import {RequestError} from 'sentry/utils/requestError/requestError';
1111
import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes';
1212
import {getLabels} from 'sentry/views/preprod/utils/labelUtils';
1313

@@ -20,20 +20,22 @@ interface PreprodBuildsTableProps {
2020
isLoading: boolean;
2121
organizationSlug: string;
2222
display?: PreprodBuildsDisplay;
23-
error?: RequestError | null;
23+
error?: Error | null;
2424
hasSearchQuery?: boolean;
2525
onRowClick?: (build: BuildDetailsApiResponse) => void;
2626
pageLinks?: string | null;
2727
showProjectColumn?: boolean;
2828
}
2929

30-
function getErrorMessage(error: RequestError): string {
31-
const detail = error.responseJSON?.detail;
32-
if (typeof detail === 'string') {
33-
return detail;
34-
}
35-
if (detail?.message) {
36-
return detail.message;
30+
function getErrorMessage(error: Error): string {
31+
if (error instanceof RequestError) {
32+
const detail = error.responseJSON?.detail;
33+
if (typeof detail === 'string') {
34+
return detail;
35+
}
36+
if (detail?.message) {
37+
return detail.message;
38+
}
3739
}
3840
return t('Error loading builds');
3941
}

static/app/views/preprod/buildComparison/main/sizeCompareSelectionContent.tsx

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {useState} from 'react';
22
import styled from '@emotion/styled';
3+
import {useQuery} from '@tanstack/react-query';
34

45
import {Alert} from '@sentry/scraps/alert';
56
import {InputGroup} from '@sentry/scraps/input';
@@ -24,10 +25,10 @@ import {
2425
import {IconBranch} from 'sentry/icons/iconBranch';
2526
import {t} from 'sentry/locale';
2627
import {trackAnalytics} from 'sentry/utils/analytics';
27-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
28+
import {selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
2829
import {parseApiError} from 'sentry/utils/parseApiError';
2930
import {parseLinkHeader} from 'sentry/utils/parseLinkHeader';
30-
import {useApiQuery, useMutation} from 'sentry/utils/queryClient';
31+
import {useMutation} from 'sentry/utils/queryClient';
3132
import {decodeScalar} from 'sentry/utils/queryString';
3233
import type {RequestError} from 'sentry/utils/requestError/requestError';
3334
import {useLocationQuery} from 'sentry/utils/url/useLocationQuery';
@@ -39,6 +40,7 @@ import {
3940
isSizeInfoCompleted,
4041
type BuildDetailsApiResponse,
4142
} from 'sentry/views/preprod/types/buildDetailsTypes';
43+
import {buildDetailsApiOptions} from 'sentry/views/preprod/utils/buildDetailsApiOptions';
4244
import {
4345
getCompareApiUrl,
4446
getCompareBuildPath,
@@ -88,26 +90,20 @@ export function SizeCompareSelectionContent({
8890
}
8991
const fullQuery = searchFilters.join(' ');
9092

91-
const queryParams: Record<string, any> = {
92-
per_page: 25,
93-
project: headBuildDetails.project_id,
94-
query: fullQuery,
95-
...(cursor && {cursor}),
96-
};
97-
98-
const buildsQuery = useApiQuery<BuildDetailsApiResponse[]>(
99-
[
100-
getApiUrl(`/organizations/$organizationIdOrSlug/builds/`, {
101-
path: {organizationIdOrSlug: organization.slug},
102-
}),
103-
{query: queryParams},
104-
],
105-
{
106-
staleTime: 0,
107-
}
108-
);
93+
const buildsQuery = useQuery({
94+
...buildDetailsApiOptions({
95+
organization,
96+
queryParams: {
97+
per_page: 25,
98+
project: headBuildDetails.project_id,
99+
query: fullQuery,
100+
...(cursor && {cursor}),
101+
},
102+
}),
103+
select: selectJsonWithHeaders,
104+
});
109105

110-
const pageLinks = buildsQuery.getResponseHeader?.('Link') || null;
106+
const pageLinks = buildsQuery.data?.headers.Link || null;
111107

112108
const parsedLinks = pageLinks ? parseLinkHeader(pageLinks) : {};
113109
const hasPagination =
@@ -194,9 +190,9 @@ export function SizeCompareSelectionContent({
194190
{buildsQuery.isError && (
195191
<Alert variant="danger">{buildsQuery.error?.message}</Alert>
196192
)}
197-
{buildsQuery.data && (
193+
{buildsQuery.data?.json && (
198194
<Stack gap="md">
199-
{buildsQuery.data?.map(build => {
195+
{buildsQuery.data.json.map(build => {
200196
if (build.id === headBuildDetails.id) {
201197
return null;
202198
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type {Organization} from 'sentry/types/organization';
2+
import {apiOptions} from 'sentry/utils/api/apiOptions';
3+
import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes';
4+
5+
export function buildDetailsApiOptions({
6+
queryParams,
7+
organization,
8+
}: {
9+
organization: Organization;
10+
queryParams?: Record<string, unknown>;
11+
}) {
12+
return apiOptions.as<BuildDetailsApiResponse[]>()(
13+
'/organizations/$organizationIdOrSlug/builds/',
14+
{
15+
path: {organizationIdOrSlug: organization.slug},
16+
query: queryParams,
17+
staleTime: 0,
18+
}
19+
);
20+
}

static/app/views/releases/detail/commitsAndFiles/preprodBuilds.tsx

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {useCallback, useContext, useEffect, useMemo, useState} from 'react';
2+
import {useQuery} from '@tanstack/react-query';
23

34
import {Container} from '@sentry/scraps/layout';
45

@@ -13,10 +14,8 @@ import {PreprodBuildsTable} from 'sentry/components/preprod/preprodBuildsTable';
1314
import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle';
1415
import {t} from 'sentry/locale';
1516
import {trackAnalytics} from 'sentry/utils/analytics';
16-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
17-
import {useApiQuery, type UseApiQueryResult} from 'sentry/utils/queryClient';
17+
import {selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
1818
import {decodeScalar} from 'sentry/utils/queryString';
19-
import type {RequestError} from 'sentry/utils/requestError/requestError';
2019
import {useLocationQuery} from 'sentry/utils/url/useLocationQuery';
2120
import {useDebouncedValue} from 'sentry/utils/useDebouncedValue';
2221
import {useLocation} from 'sentry/utils/useLocation';
@@ -26,6 +25,7 @@ import {useParams} from 'sentry/utils/useParams';
2625
import {formatVersion} from 'sentry/utils/versions/formatVersion';
2726
import {usePreprodBuildsAnalytics} from 'sentry/views/preprod/hooks/usePreprodBuildsAnalytics';
2827
import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes';
28+
import {buildDetailsApiOptions} from 'sentry/views/preprod/utils/buildDetailsApiOptions';
2929
import {ReleaseContext} from 'sentry/views/releases/detail';
3030

3131
import {PreprodOnboarding} from './preprodOnboarding';
@@ -107,25 +107,15 @@ export default function PreprodBuilds() {
107107
}
108108

109109
const {
110-
data: buildsData,
110+
data: buildsResponse,
111111
isPending: isLoadingBuilds,
112112
error: buildsError,
113113
refetch,
114-
getResponseHeader,
115-
}: UseApiQueryResult<BuildDetailsApiResponse[], RequestError> = useApiQuery<
116-
BuildDetailsApiResponse[]
117-
>(
118-
[
119-
getApiUrl(`/organizations/$organizationIdOrSlug/builds/`, {
120-
path: {organizationIdOrSlug: organization.slug},
121-
}),
122-
{query: queryParams},
123-
],
124-
{
125-
staleTime: 0,
126-
enabled: !!projectSlug && !!params.release,
127-
}
128-
);
114+
} = useQuery({
115+
...buildDetailsApiOptions({organization, queryParams}),
116+
select: selectJsonWithHeaders,
117+
enabled: !!projectSlug && !!params.release,
118+
});
129119

130120
const handleSearch = (query: string, _state?: {queryIsValid: boolean}) => {
131121
setLocalSearchQuery(query);
@@ -145,8 +135,8 @@ export default function PreprodBuilds() {
145135
[location, navigate]
146136
);
147137

148-
const builds = buildsData ?? [];
149-
const pageLinks = getResponseHeader?.('Link') || null;
138+
const builds = buildsResponse?.json ?? [];
139+
const pageLinks = buildsResponse?.headers.Link ?? null;
150140

151141
const hasSearchQuery = !!urlSearchQuery?.trim();
152142
const showOnboarding = builds.length === 0 && !hasSearchQuery && !isLoadingBuilds;

static/app/views/releases/list/mobileBuilds.tsx

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {Fragment, useCallback, useEffect, useMemo} from 'react';
2+
import {useQuery} from '@tanstack/react-query';
23
import {parseAsString, useQueryState} from 'nuqs';
34

45
import {Stack} from '@sentry/scraps/layout';
@@ -16,13 +17,11 @@ import {PreprodOnboardingPanel} from 'sentry/components/preprod/preprodOnboardin
1617
import {ProjectsStore} from 'sentry/stores/projectsStore';
1718
import type {Organization} from 'sentry/types/organization';
1819
import {trackAnalytics} from 'sentry/utils/analytics';
19-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
20-
import {useApiQuery, type UseApiQueryResult} from 'sentry/utils/queryClient';
21-
import type {RequestError} from 'sentry/utils/requestError/requestError';
20+
import {selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
2221
import {useLocation} from 'sentry/utils/useLocation';
2322
import {useNavigate} from 'sentry/utils/useNavigate';
2423
import {usePreprodBuildsAnalytics} from 'sentry/views/preprod/hooks/usePreprodBuildsAnalytics';
25-
import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes';
24+
import {buildDetailsApiOptions} from 'sentry/views/preprod/utils/buildDetailsApiOptions';
2625

2726
import {MobileBuildsChart} from './mobileBuildsChart';
2827

@@ -72,25 +71,15 @@ export function MobileBuilds({organization, selectedProjectIds}: Props) {
7271
}, [activeDisplay, cursor, location, searchQuery, selectedProjectIds]);
7372

7473
const {
75-
data: buildsData,
74+
data: buildsResponse,
7675
isPending: isLoadingBuilds,
7776
error: buildsError,
7877
refetch,
79-
getResponseHeader,
80-
}: UseApiQueryResult<BuildDetailsApiResponse[], RequestError> = useApiQuery<
81-
BuildDetailsApiResponse[]
82-
>(
83-
[
84-
getApiUrl(`/organizations/$organizationIdOrSlug/builds/`, {
85-
path: {organizationIdOrSlug: organization.slug},
86-
}),
87-
{query: buildsQueryParams},
88-
],
89-
{
90-
staleTime: 0,
91-
enabled: selectedProjectIds.length > 0,
92-
}
93-
);
78+
} = useQuery({
79+
...buildDetailsApiOptions({organization, queryParams: buildsQueryParams}),
80+
select: selectJsonWithHeaders,
81+
enabled: selectedProjectIds.length > 0,
82+
});
9483

9584
const handleSearch = useCallback(
9685
(query: string) => {
@@ -112,8 +101,8 @@ export function MobileBuilds({organization, selectedProjectIds}: Props) {
112101
[location, navigate]
113102
);
114103

115-
const builds = buildsData ?? [];
116-
const pageLinks = getResponseHeader?.('Link') ?? undefined;
104+
const builds = buildsResponse?.json ?? [];
105+
const pageLinks = buildsResponse?.headers.Link ?? undefined;
117106
const hasSearchQuery = !!searchQuery?.trim();
118107
const showProjectColumn = selectedProjectIds.length > 1;
119108
const projectId = selectedProjectIds[0];

static/app/views/settings/project/preprod/featureFilter.tsx

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {useCallback, useState} from 'react';
2+
import {useQuery} from '@tanstack/react-query';
23

34
import {Container, Flex, Stack} from '@sentry/scraps/layout';
45
import {Switch} from '@sentry/scraps/switch';
@@ -12,10 +13,8 @@ import {PreprodBuildsDisplay} from 'sentry/components/preprod/preprodBuildsDispl
1213
import {PreprodBuildsTable} from 'sentry/components/preprod/preprodBuildsTable';
1314
import {PreprodSearchBar} from 'sentry/components/preprod/preprodSearchBar';
1415
import {t} from 'sentry/locale';
15-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
16-
import {useApiQuery} from 'sentry/utils/queryClient';
1716
import {useOrganization} from 'sentry/utils/useOrganization';
18-
import type {BuildDetailsApiResponse} from 'sentry/views/preprod/types/buildDetailsTypes';
17+
import {buildDetailsApiOptions} from 'sentry/views/preprod/utils/buildDetailsApiOptions';
1918
import {useProjectSettingsOutlet} from 'sentry/views/settings/project/projectSettingsLayout';
2019

2120
import {useFeatureFilter, type PreprodEnabledWriteKey} from './useFeatureFilter';
@@ -95,18 +94,10 @@ export function FeatureFilter({
9594
queryParams.query = localQuery;
9695
}
9796

98-
const buildsQuery = useApiQuery<BuildDetailsApiResponse[]>(
99-
[
100-
getApiUrl(`/organizations/$organizationIdOrSlug/builds/`, {
101-
path: {organizationIdOrSlug: organization.slug},
102-
}),
103-
{query: queryParams},
104-
],
105-
{
106-
staleTime: 0,
107-
enabled,
108-
}
109-
);
97+
const buildsQuery = useQuery({
98+
...buildDetailsApiOptions({organization, queryParams}),
99+
enabled,
100+
});
110101

111102
const builds = buildsQuery.data ?? [];
112103

0 commit comments

Comments
 (0)