Skip to content

Commit d365dd0

Browse files
committed
ref(tsc): organization flag logs endpoint to apiOptions
1 parent 78e84a2 commit d365dd0

File tree

7 files changed

+136
-141
lines changed

7 files changed

+136
-141
lines changed

static/app/components/events/featureFlags/eventFeatureFlagSection.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Fragment, useCallback, useEffect, useMemo, useRef, useState} from 'react';
22
import {useTheme} from '@emotion/react';
33
import styled from '@emotion/styled';
4+
import {useQuery} from '@tanstack/react-query';
45

56
import {Button} from '@sentry/scraps/button';
67
import {Grid} from '@sentry/scraps/layout';
@@ -20,7 +21,7 @@ import {
2021
OrderBy,
2122
sortedFlags,
2223
} from 'sentry/components/events/featureFlags/utils';
23-
import {useOrganizationFlagLog} from 'sentry/components/featureFlags/hooks/useOrganizationFlagLog';
24+
import {organizationFlagLogOptions} from 'sentry/components/featureFlags/hooks/useOrganizationFlagLog';
2425
import {FeedbackButton} from 'sentry/components/feedbackButton/feedbackButton';
2526
import {useDrawer} from 'sentry/components/globalDrawer';
2627
import {useLegacyEventSuspectFlags} from 'sentry/components/issues/suspect/useLegacyEventSuspectFlags';
@@ -77,14 +78,16 @@ function BaseEventFeatureFlagList({event, group, project}: EventFeatureFlagSecti
7778
const viewAllButtonRef = useRef<HTMLButtonElement>(null);
7879

7980
const eventView = useIssueDetailsEventView({group});
80-
const {data: rawFlagData} = useOrganizationFlagLog({
81-
organization,
82-
query: {
83-
start: eventView.start,
84-
end: eventView.end,
85-
statsPeriod: eventView.statsPeriod,
86-
},
87-
});
81+
const {data: rawFlagData} = useQuery(
82+
organizationFlagLogOptions({
83+
organization,
84+
query: {
85+
start: eventView.start,
86+
end: eventView.end,
87+
statsPeriod: eventView.statsPeriod,
88+
},
89+
})
90+
);
8891
const location = useLocation();
8992

9093
// issue list params we want to preserve in the search

static/app/components/featureFlags/featureFlagsLogTable.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ import {GridEditable, type GridColumnOrder} from 'sentry/components/tables/gridE
88
import {t} from 'sentry/locale';
99
import {trackAnalytics} from 'sentry/utils/analytics';
1010
import {FIELD_FORMATTERS} from 'sentry/utils/discover/fieldRenderers';
11-
import type {RequestError} from 'sentry/utils/requestError/requestError';
1211
import {useNavigate} from 'sentry/utils/useNavigate';
1312
import {useOrganization} from 'sentry/utils/useOrganization';
1413

1514
export type ColumnKey = 'provider' | 'flag' | 'action' | 'createdAt';
1615

1716
interface FeatureFlagsLogTableProps {
1817
columns: Array<GridColumnOrder<ColumnKey>>;
19-
error: RequestError | null;
18+
error: Error | null;
2019
flags: RawFlag[];
2120
isPending: boolean;
2221
pageLinks: string | null;

static/app/components/featureFlags/hooks/useFlagsInEvent.tsx

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import {skipToken, useQuery} from '@tanstack/react-query';
2+
13
import {useFetchGroupAndEvent} from 'sentry/components/featureFlags/hooks/useFetchGroupAndEvent';
24
import {
3-
useOrganizationFlagLog,
5+
organizationFlagLogOptions,
46
useOrganizationFlagLogInfinite,
57
} from 'sentry/components/featureFlags/hooks/useOrganizationFlagLog';
68
import type {Event} from 'sentry/types/event';
79
import type {Group} from 'sentry/types/group';
810
import {defined} from 'sentry/utils';
9-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
10-
import {useApiQuery} from 'sentry/utils/queryClient';
11+
import {apiOptions, selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
1112
import {useOrganization} from 'sentry/utils/useOrganization';
1213
import {useGroup} from 'sentry/views/issueDetails/useGroup';
1314

@@ -48,23 +49,25 @@ export function useFlagsInEventPaginated({
4849
});
4950

5051
const {
51-
data: rawFlagData,
52-
getResponseHeader,
52+
data: rawFlagResp,
5353
isPending: isFlagsPending,
5454
isError: isFlagsError,
5555
error: flagsError,
56-
} = useOrganizationFlagLog({
57-
organization,
58-
query: {
59-
...query,
60-
flag: eventFlags,
61-
},
56+
} = useQuery({
57+
...organizationFlagLogOptions({
58+
organization,
59+
query: {
60+
...query,
61+
flag: eventFlags,
62+
},
63+
}),
6264
enabled: enabled && Boolean(eventFlags?.length),
65+
select: selectJsonWithHeaders,
6366
});
64-
const pageLinks = getResponseHeader?.('Link') ?? null;
67+
const pageLinks = rawFlagResp?.headers.Link ?? null;
6568

6669
return {
67-
flags: rawFlagData?.data ?? [],
70+
flags: rawFlagResp?.json?.data ?? [],
6871
event,
6972
group,
7073
pageLinks,
@@ -108,29 +111,27 @@ export function useFlagsInEvent({
108111
const group = groupProp ?? groupData;
109112

110113
const projectSlug = group?.project.slug;
114+
const eventEnabled =
115+
enabled && Boolean(eventId && projectSlug && organization.slug) && !eventProp;
111116
const {
112117
data: eventData,
113118
isPending: isEventPending,
114119
isError: isEventError,
115120
error: eventError,
116-
} = useApiQuery<Event>(
117-
[
118-
getApiUrl(
119-
'/organizations/$organizationIdOrSlug/events/$projectIdOrSlug:$eventId/',
120-
{
121-
path: {
122-
organizationIdOrSlug: organization.slug,
123-
projectIdOrSlug: projectSlug!,
124-
eventId: eventId!,
125-
},
126-
}
127-
),
128-
],
129-
{
130-
staleTime: Infinity,
131-
enabled:
132-
enabled && Boolean(eventId && projectSlug && organization.slug) && !eventProp,
133-
}
121+
} = useQuery(
122+
apiOptions.as<Event>()(
123+
'/organizations/$organizationIdOrSlug/events/$projectIdOrSlug:$eventId/',
124+
{
125+
path: eventEnabled
126+
? {
127+
organizationIdOrSlug: organization.slug,
128+
projectIdOrSlug: projectSlug!,
129+
eventId: eventId!,
130+
}
131+
: skipToken,
132+
staleTime: Infinity,
133+
}
134+
)
134135
);
135136
const event = eventProp ?? eventData;
136137

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,25 @@
11
import {useEffect} from 'react';
2+
import {skipToken, useInfiniteQuery} from '@tanstack/react-query';
23

34
import type {RawFlagData} from 'sentry/components/featureFlags/utils';
45
import type {Organization} from 'sentry/types/organization';
5-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
6-
import {useApiQuery, useInfiniteApiQuery} from 'sentry/utils/queryClient';
6+
import {apiOptions} from 'sentry/utils/api/apiOptions';
77

88
interface Params {
99
organization: Organization;
10-
query: Record<string, any>;
11-
enabled?: boolean;
10+
query: Record<string, unknown>;
1211
}
1312

14-
export function useOrganizationFlagLog({
15-
organization,
16-
query,
17-
enabled: enabledParam = true,
18-
}: Params) {
13+
export function organizationFlagLogOptions({organization, query}: Params) {
1914
// Don't make the request if start = end. The backend returns 400 but we prefer an empty response.
20-
const enabled =
21-
(!query.start || !query.end || query.start !== query.end) && enabledParam;
15+
const enabled = !query.start || !query.end || query.start !== query.end;
2216

23-
return useApiQuery<RawFlagData>(
24-
[
25-
getApiUrl('/organizations/$organizationIdOrSlug/flags/logs/', {
26-
path: {
27-
organizationIdOrSlug: organization.slug,
28-
},
29-
}),
30-
{query},
31-
],
17+
return apiOptions.as<RawFlagData>()(
18+
'/organizations/$organizationIdOrSlug/flags/logs/',
3219
{
20+
path: enabled ? {organizationIdOrSlug: organization.slug} : skipToken,
21+
query,
3322
staleTime: 0,
34-
enabled,
3523
}
3624
);
3725
}
@@ -48,39 +36,42 @@ export function useOrganizationFlagLogInfinite({
4836
query,
4937
enabled: enabledParam = true,
5038
maxPages = 10,
51-
}: InfiniteParams) {
39+
}: InfiniteParams & {enabled?: boolean}) {
5240
// Don't make the request if start = end. The backend returns 400 but we prefer an empty response.
5341
const enabled =
5442
(!query.start || !query.end || query.start !== query.end) && enabledParam;
5543

56-
const apiQuery = useInfiniteApiQuery<RawFlagData>({
57-
queryKey: [
58-
{infinite: true, version: 'v1'},
59-
getApiUrl('/organizations/$organizationIdOrSlug/flags/logs/', {
60-
path: {
61-
organizationIdOrSlug: organization.slug,
62-
},
63-
}),
64-
{query},
65-
],
66-
staleTime: 0,
67-
enabled,
44+
const {
45+
data: infiniteData,
46+
isFetching,
47+
hasNextPage,
48+
fetchNextPage,
49+
isPending,
50+
isError,
51+
error,
52+
} = useInfiniteQuery({
53+
...apiOptions.asInfinite<RawFlagData>()(
54+
'/organizations/$organizationIdOrSlug/flags/logs/',
55+
{
56+
path: enabled ? {organizationIdOrSlug: organization.slug} : skipToken,
57+
query,
58+
staleTime: 0,
59+
}
60+
),
6861
});
6962

70-
const currentNumberPages = apiQuery.data?.pages.length ?? 0;
63+
const currentNumberPages = infiniteData?.pages.length ?? 0;
7164

7265
useEffect(() => {
73-
if (
74-
!apiQuery.isFetching &&
75-
apiQuery.hasNextPage &&
76-
currentNumberPages + 1 < maxPages
77-
) {
78-
apiQuery.fetchNextPage();
66+
if (!isFetching && hasNextPage && currentNumberPages + 1 < maxPages) {
67+
fetchNextPage();
7968
}
80-
}, [apiQuery, maxPages, currentNumberPages]);
69+
}, [isFetching, hasNextPage, fetchNextPage, maxPages, currentNumberPages]);
8170

8271
return {
83-
...apiQuery,
84-
data: apiQuery.data?.pages.flatMap(([pageData]) => pageData.data),
72+
data: infiniteData?.pages.flatMap(page => page.json.data),
73+
isPending,
74+
isError,
75+
error,
8576
};
8677
}

static/app/components/issues/suspect/useLegacyEventSuspectFlags.tsx

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import {useEffect, useMemo} from 'react';
2+
import {useQuery} from '@tanstack/react-query';
23
import intersection from 'lodash/intersection';
34
import moment from 'moment-timezone';
45

6+
import {organizationFlagLogOptions} from 'sentry/components/featureFlags/hooks/useOrganizationFlagLog';
57
import {
68
hydrateToFlagSeries,
79
type RawFlag,
@@ -11,9 +13,6 @@ import type {Event} from 'sentry/types/event';
1113
import type {Organization} from 'sentry/types/organization';
1214
import {defined} from 'sentry/utils';
1315
import {trackAnalytics} from 'sentry/utils/analytics';
14-
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
15-
import {useApiQuery, type UseApiQueryResult} from 'sentry/utils/queryClient';
16-
import type {RequestError} from 'sentry/utils/requestError/requestError';
1716

1817
/**
1918
* Legacy suspect flags implementation.
@@ -33,7 +32,13 @@ export function useLegacyEventSuspectFlags({
3332
firstSeen: string;
3433
organization: Organization;
3534
rawFlagData: RawFlagData | undefined;
36-
}): UseApiQueryResult<RawFlagData, RequestError> & {suspectFlags: RawFlag[]} {
35+
}): {
36+
data: RawFlagData | undefined;
37+
error: Error | null;
38+
isError: boolean;
39+
isPending: boolean;
40+
suspectFlags: RawFlag[];
41+
} {
3742
const hydratedFlagData = hydrateToFlagSeries(rawFlagData?.data ?? []);
3843

3944
// map flag data to arrays of flag names
@@ -48,28 +53,19 @@ export function useLegacyEventSuspectFlags({
4853

4954
// get all the audit log flag changes which happened prior to the first seen date
5055
const start = moment(firstSeen).subtract(1, 'year').format('YYYY-MM-DD HH:mm:ss');
51-
const apiQueryResponse = useApiQuery<RawFlagData>(
52-
[
53-
getApiUrl('/organizations/$organizationIdOrSlug/flags/logs/', {
54-
path: {organizationIdOrSlug: organization.slug},
55-
}),
56-
{
57-
query: {
58-
flag: intersectionFlags,
59-
start,
60-
end: firstSeen,
61-
statsPeriod: undefined,
62-
},
56+
const {data, isError, isPending, error} = useQuery({
57+
...organizationFlagLogOptions({
58+
organization,
59+
query: {
60+
flag: intersectionFlags,
61+
start,
62+
end: firstSeen,
63+
statsPeriod: undefined,
6364
},
64-
],
65-
{
66-
staleTime: 0,
67-
// if no intersection, then there are no suspect flags
68-
enabled: enabled && Boolean(intersectionFlags.length),
69-
}
70-
);
71-
72-
const {data, isError, isPending} = apiQueryResponse;
65+
}),
66+
// if no intersection, then there are no suspect flags
67+
enabled: enabled && Boolean(intersectionFlags.length),
68+
});
7369

7470
// no flags in common between event evaluations and audit log
7571
// only track this analytic if there is at least 1 flag recorded
@@ -131,5 +127,5 @@ export function useLegacyEventSuspectFlags({
131127
organization,
132128
]);
133129

134-
return {...apiQueryResponse, suspectFlags};
130+
return {data, isError, isPending, error, suspectFlags};
135131
}

0 commit comments

Comments
 (0)