Skip to content

Commit 019fd4d

Browse files
authored
ref(tsc): move automations to apiOptions (#112369)
1 parent fe836ca commit 019fd4d

File tree

6 files changed

+106
-174
lines changed

6 files changed

+106
-174
lines changed

static/app/views/automations/hooks/index.tsx

Lines changed: 41 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ import type {
1515
} from 'sentry/types/workflowEngine/dataConditions';
1616
import {apiOptions} from 'sentry/utils/api/apiOptions';
1717
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
18-
import type {
19-
ApiQueryKey,
20-
UseApiQueryOptions,
21-
UseMutationOptions,
22-
} from 'sentry/utils/queryClient';
18+
import type {ApiQueryKey, UseMutationOptions} from 'sentry/utils/queryClient';
2319
import {
2420
setApiQueryData,
2521
useApiQuery,
@@ -30,73 +26,48 @@ import type {RequestError} from 'sentry/utils/requestError/requestError';
3026
import {useApi} from 'sentry/utils/useApi';
3127
import {useOrganization} from 'sentry/utils/useOrganization';
3228

33-
export const makeAutomationsQueryKey = ({
34-
orgSlug,
35-
query,
36-
sortBy,
37-
priorityDetector,
38-
ids,
39-
limit,
40-
cursor,
41-
projects,
42-
detector,
43-
}: {
44-
orgSlug: string;
45-
cursor?: string;
46-
detector?: string[];
47-
ids?: string[];
48-
limit?: number;
49-
priorityDetector?: string;
50-
projects?: number[];
51-
query?: string;
52-
sortBy?: string;
53-
}): ApiQueryKey => [
54-
getApiUrl('/organizations/$organizationIdOrSlug/workflows/', {
55-
path: {organizationIdOrSlug: orgSlug},
56-
}),
57-
{
58-
query: {
29+
export const automationsApiOptions = (
30+
organization: Organization,
31+
options?: {
32+
cursor?: string;
33+
detector?: string[];
34+
ids?: string[];
35+
limit?: number;
36+
priorityDetector?: string;
37+
projects?: number[];
38+
query?: string;
39+
sortBy?: string;
40+
}
41+
) => {
42+
const query = options
43+
? {
44+
query: options.query,
45+
sortBy: options.sortBy,
46+
priorityDetector: options.priorityDetector,
47+
id: options.ids,
48+
per_page: options.limit,
49+
cursor: options.cursor,
50+
project: options.projects,
51+
detector: options.detector,
52+
}
53+
: undefined;
54+
55+
return queryOptions({
56+
...apiOptions.as<Automation[]>()('/organizations/$organizationIdOrSlug/workflows/', {
57+
path: {organizationIdOrSlug: organization.slug},
5958
query,
60-
sortBy,
61-
priorityDetector,
62-
id: ids,
63-
per_page: limit,
64-
cursor,
65-
project: projects,
66-
detector,
67-
},
68-
},
69-
];
59+
staleTime: 0,
60+
}),
61+
retry: false,
62+
});
63+
};
7064

7165
const makeAutomationQueryKey = (orgSlug: string, automationId: string): ApiQueryKey => [
7266
getApiUrl('/organizations/$organizationIdOrSlug/workflows/$workflowId/', {
7367
path: {organizationIdOrSlug: orgSlug, workflowId: automationId},
7468
}),
7569
];
7670

77-
interface UseAutomationsQueryOptions {
78-
cursor?: string;
79-
detector?: string[];
80-
ids?: string[];
81-
limit?: number;
82-
priorityDetector?: string;
83-
projects?: number[];
84-
query?: string;
85-
sortBy?: string;
86-
}
87-
export function useAutomationsQuery(
88-
options: UseAutomationsQueryOptions = {},
89-
useApiQueryOptions: Partial<UseApiQueryOptions<Automation[]>> = {}
90-
) {
91-
const {slug: orgSlug} = useOrganization();
92-
93-
return useApiQuery<Automation[]>(makeAutomationsQueryKey({orgSlug, ...options}), {
94-
staleTime: 0,
95-
retry: false,
96-
...useApiQueryOptions,
97-
});
98-
}
99-
10071
export function useAutomationQuery(automationId: string) {
10172
const {slug} = useOrganization();
10273

@@ -186,11 +157,7 @@ export function useCreateAutomation() {
186157
),
187158
onSuccess: _ => {
188159
queryClient.invalidateQueries({
189-
queryKey: [
190-
getApiUrl('/organizations/$organizationIdOrSlug/workflows/', {
191-
path: {organizationIdOrSlug: org.slug},
192-
}),
193-
],
160+
queryKey: automationsApiOptions(org).queryKey,
194161
});
195162
},
196163
onError: _ => {
@@ -216,11 +183,7 @@ export function useDeleteAutomationMutation() {
216183
),
217184
onSuccess: () => {
218185
queryClient.invalidateQueries({
219-
queryKey: [
220-
getApiUrl('/organizations/$organizationIdOrSlug/workflows/', {
221-
path: {organizationIdOrSlug: org.slug},
222-
}),
223-
],
186+
queryKey: automationsApiOptions(org).queryKey,
224187
});
225188
addSuccessMessage(t('Alert deleted'));
226189
},
@@ -258,11 +221,7 @@ export function useDeleteAutomationsMutation() {
258221
},
259222
onSuccess: () => {
260223
queryClient.invalidateQueries({
261-
queryKey: [
262-
getApiUrl('/organizations/$organizationIdOrSlug/workflows/', {
263-
path: {organizationIdOrSlug: org.slug},
264-
}),
265-
],
224+
queryKey: automationsApiOptions(org).queryKey,
266225
});
267226
addSuccessMessage(t('Alerts deleted'));
268227
},
@@ -305,11 +264,7 @@ export function useUpdateAutomation() {
305264
);
306265
// Invalidate list query
307266
queryClient.invalidateQueries({
308-
queryKey: [
309-
getApiUrl('/organizations/$organizationIdOrSlug/workflows/', {
310-
path: {organizationIdOrSlug: org.slug},
311-
}),
312-
],
267+
queryKey: automationsApiOptions(org).queryKey,
313268
});
314269
},
315270
onError: _ => {
@@ -347,11 +302,7 @@ export function useUpdateAutomationsMutation() {
347302
},
348303
onSuccess: (_, variables) => {
349304
queryClient.invalidateQueries({
350-
queryKey: [
351-
getApiUrl('/organizations/$organizationIdOrSlug/workflows/', {
352-
path: {organizationIdOrSlug: org.slug},
353-
}),
354-
],
305+
queryKey: automationsApiOptions(org).queryKey,
355306
});
356307
addSuccessMessage(variables.enabled ? t('Alerts enabled') : t('Alerts disabled'));
357308
},
@@ -388,11 +339,7 @@ export function useSendTestNotification(
388339
...options,
389340
onSuccess: (data, variables, onMutateResult, context) => {
390341
queryClient.invalidateQueries({
391-
queryKey: [
392-
getApiUrl('/organizations/$organizationIdOrSlug/workflows/', {
393-
path: {organizationIdOrSlug: org.slug},
394-
}),
395-
],
342+
queryKey: automationsApiOptions(org).queryKey,
396343
});
397344
addSuccessMessage(
398345
tn('Notification fired!', 'Notifications sent!', variables.length)

static/app/views/automations/list.tsx

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

34
import {LinkButton} from '@sentry/scraps/button';
45
import {Flex} from '@sentry/scraps/layout';
@@ -10,6 +11,7 @@ import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle';
1011
import {WorkflowEngineListLayout as ListLayout} from 'sentry/components/workflowEngine/layout/list';
1112
import {IconAdd} from 'sentry/icons';
1213
import {t} from 'sentry/locale';
14+
import {selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
1315
import {parseLinkHeader} from 'sentry/utils/parseLinkHeader';
1416
import {VisuallyCompleteWithData} from 'sentry/utils/performanceForSentry';
1517
import {decodeScalar, decodeSorts} from 'sentry/utils/queryString';
@@ -21,11 +23,12 @@ import {AutomationFeedbackButton} from 'sentry/views/automations/components/auto
2123
import {AutomationListTable} from 'sentry/views/automations/components/automationListTable';
2224
import {AutomationSearch} from 'sentry/views/automations/components/automationListTable/search';
2325
import {AUTOMATION_LIST_PAGE_LIMIT} from 'sentry/views/automations/constants';
24-
import {useAutomationsQuery} from 'sentry/views/automations/hooks';
26+
import {automationsApiOptions} from 'sentry/views/automations/hooks';
2527
import {makeAutomationCreatePathname} from 'sentry/views/automations/pathnames';
2628
import {AlertsRedirectNotice} from 'sentry/views/detectors/list/common/alertsRedirectNotice';
2729

2830
export default function AutomationsList() {
31+
const organization = useOrganization();
2932
const location = useLocation();
3033
const navigate = useNavigate();
3134
const {selection, isReady} = usePageFilters();
@@ -43,30 +46,23 @@ export default function AutomationsList() {
4346
});
4447
const sort = sorts[0] ?? {kind: 'desc', field: 'lastTriggered'};
4548

46-
const {
47-
data: automations,
48-
isLoading,
49-
isError,
50-
isSuccess,
51-
getResponseHeader,
52-
} = useAutomationsQuery(
53-
{
54-
cursor,
49+
const {data, isLoading, isError, isSuccess} = useQuery({
50+
...automationsApiOptions(organization, {
5551
query,
5652
sortBy: sort ? `${sort?.kind === 'asc' ? '' : '-'}${sort?.field}` : undefined,
5753
projects: selection.projects,
5854
limit: AUTOMATION_LIST_PAGE_LIMIT,
59-
},
60-
{enabled: isReady}
61-
);
55+
cursor,
56+
}),
57+
select: selectJsonWithHeaders,
58+
enabled: isReady,
59+
});
6260

63-
const hits = getResponseHeader?.('X-Hits') || '';
64-
const hitsInt = hits ? parseInt(hits, 10) || 0 : 0;
61+
const automations = data?.json;
62+
const hits = data?.headers['X-Hits'] ?? 0;
6563
// If maxHits is not set, we assume there is no max
66-
const maxHits = getResponseHeader?.('X-Max-Hits') || '';
67-
const maxHitsInt = maxHits ? parseInt(maxHits, 10) || Infinity : Infinity;
68-
69-
const pageLinks = getResponseHeader?.('Link');
64+
const maxHits = data?.headers['X-Max-Hits'] ?? Infinity;
65+
const pageLinks = data?.headers.Link;
7066

7167
const allResultsVisible = useCallback(() => {
7268
if (!pageLinks) {
@@ -102,7 +98,7 @@ export default function AutomationsList() {
10298
isError={isError}
10399
isSuccess={isSuccess}
104100
sort={sort}
105-
queryCount={hitsInt > maxHitsInt ? `${maxHits}+` : hits}
101+
queryCount={hits > maxHits ? `${maxHits}+` : `${hits}`}
106102
allResultsVisible={allResultsVisible()}
107103
/>
108104
</VisuallyCompleteWithData>

static/app/views/detectors/components/connectAutomationsDrawer.tsx

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import {DrawerHeader} from 'sentry/components/globalDrawer/components';
55
import {DetailSection} from 'sentry/components/workflowEngine/ui/detailSection';
66
import {t} from 'sentry/locale';
77
import type {Automation} from 'sentry/types/workflowEngine/automations';
8-
import {getApiQueryData, setApiQueryData, useQueryClient} from 'sentry/utils/queryClient';
8+
import {useQueryClient} from 'sentry/utils/queryClient';
99
import {useOrganization} from 'sentry/utils/useOrganization';
1010
import {AutomationSearch} from 'sentry/views/automations/components/automationListTable/search';
11-
import {makeAutomationsQueryKey} from 'sentry/views/automations/hooks';
11+
import {automationsApiOptions} from 'sentry/views/automations/hooks';
1212
import {ConnectedAutomationsList} from 'sentry/views/detectors/components/connectedAutomationList';
1313

1414
function ConnectedAutomations({
@@ -81,13 +81,11 @@ export function ConnectAutomationsDrawer({
8181

8282
const toggleConnected = ({automation}: {automation: Automation}) => {
8383
const oldAutomationsData =
84-
getApiQueryData<Automation[]>(
85-
queryClient,
86-
makeAutomationsQueryKey({
87-
orgSlug: organization.slug,
84+
queryClient.getQueryData(
85+
automationsApiOptions(organization, {
8886
ids: localWorkflowIds,
89-
})
90-
) ?? [];
87+
}).queryKey
88+
)?.json ?? [];
9189

9290
const newAutomations = (
9391
oldAutomationsData.some(a => a.id === automation.id)
@@ -96,13 +94,9 @@ export function ConnectAutomationsDrawer({
9694
).sort((a, b) => a.id.localeCompare(b.id));
9795
const newWorkflowIds = newAutomations.map(a => a.id);
9896

99-
setApiQueryData<Automation[]>(
100-
queryClient,
101-
makeAutomationsQueryKey({
102-
orgSlug: organization.slug,
103-
ids: newWorkflowIds,
104-
}),
105-
newAutomations
97+
queryClient.setQueryData(
98+
automationsApiOptions(organization, {ids: newWorkflowIds}).queryKey,
99+
old => ({headers: old?.headers ?? {}, json: newAutomations})
106100
);
107101

108102
setLocalWorkflowIds(newWorkflowIds);

static/app/views/detectors/components/connectedAutomationList.tsx

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

45
import {Button} from '@sentry/scraps/button';
56

@@ -14,8 +15,10 @@ import {TimeAgoCell} from 'sentry/components/workflowEngine/gridCell/timeAgoCell
1415
import {t, tct} from 'sentry/locale';
1516
import type {Automation} from 'sentry/types/workflowEngine/automations';
1617
import type {Detector} from 'sentry/types/workflowEngine/detectors';
18+
import {selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
1719
import {parseCursor} from 'sentry/utils/cursor';
18-
import {useAutomationsQuery} from 'sentry/views/automations/hooks';
20+
import {useOrganization} from 'sentry/utils/useOrganization';
21+
import {automationsApiOptions} from 'sentry/views/automations/hooks';
1922
import {getAutomationActions} from 'sentry/views/automations/hooks/utils';
2023

2124
const DEFAULT_AUTOMATIONS_PER_PAGE = 10;
@@ -72,29 +75,25 @@ export function ConnectedAutomationsList({
7275
openInNewTab,
7376
...props
7477
}: Props) {
78+
const organization = useOrganization();
7579
const canEdit = Boolean(
7680
connectedAutomationIds && typeof toggleConnected === 'function'
7781
);
7882

79-
const {
80-
data: automations,
81-
isLoading,
82-
isError,
83-
isSuccess,
84-
getResponseHeader,
85-
} = useAutomationsQuery(
86-
{
83+
const {data, isLoading, isError, isSuccess} = useQuery({
84+
...automationsApiOptions(organization, {
8785
ids: automationIds ?? undefined,
8886
limit: limit ?? undefined,
8987
cursor,
9088
query,
91-
},
92-
{enabled: automationIds === null || automationIds.length > 0}
93-
);
89+
}),
90+
select: selectJsonWithHeaders,
91+
enabled: automationIds === null || automationIds.length > 0,
92+
});
9493

95-
const pageLinks = getResponseHeader?.('Link');
96-
const totalCount = getResponseHeader?.('X-Hits');
97-
const totalCountInt = totalCount ? parseInt(totalCount, 10) : 0;
94+
const automations = data?.json;
95+
const pageLinks = data?.headers.Link;
96+
const totalCountInt = data?.headers['X-Hits'] ?? 0;
9897

9998
const paginationCaption = useMemo(() => {
10099
if (!automations || automations.length === 0 || isLoading || limit === null) {
@@ -137,12 +136,12 @@ export function ConnectedAutomationsList({
137136
/>
138137
)}
139138
{isError && <LoadingError />}
140-
{((isSuccess && automations.length === 0) ||
139+
{((isSuccess && automations?.length === 0) ||
141140
(automationIds !== null && automationIds.length === 0)) && (
142141
<SimpleTable.Empty>{emptyMessage}</SimpleTable.Empty>
143142
)}
144143
{isSuccess &&
145-
automations.map(automation => (
144+
automations?.map(automation => (
146145
<SimpleTable.Row
147146
key={automation.id}
148147
variant={automation.enabled ? 'default' : 'faded'}

0 commit comments

Comments
 (0)