diff --git a/static/app/views/issueDetails/groupEventAttachments/groupEventAttachments.tsx b/static/app/views/issueDetails/groupEventAttachments/groupEventAttachments.tsx
index c42d1716cd3c3b..decf5e1bb058a9 100644
--- a/static/app/views/issueDetails/groupEventAttachments/groupEventAttachments.tsx
+++ b/static/app/views/issueDetails/groupEventAttachments/groupEventAttachments.tsx
@@ -67,11 +67,10 @@ export function GroupEventAttachments({project, group}: GroupEventAttachmentsPro
}
}, [previouslyUsedAttachmentsTab, location, navigate]);
- const {attachments, isPending, isError, getResponseHeader, refetch} =
- useGroupEventAttachments({
- group,
- activeAttachmentsTab,
- });
+ const {attachments, isPending, isError, pageLinks, refetch} = useGroupEventAttachments({
+ group,
+ activeAttachmentsTab,
+ });
const {mutate: deleteAttachment} = useDeleteGroupEventAttachment();
@@ -162,7 +161,7 @@ export function GroupEventAttachments({project, group}: GroupEventAttachmentsPro
{activeAttachmentsTab === EventAttachmentFilter.SCREENSHOT
? renderScreenshotGallery()
: renderAttachmentsTable()}
-
+
);
}
diff --git a/static/app/views/issueDetails/groupEventAttachments/useDeleteGroupEventAttachment.tsx b/static/app/views/issueDetails/groupEventAttachments/useDeleteGroupEventAttachment.tsx
index 1169d8478e92fa..bf7cbf2de6a729 100644
--- a/static/app/views/issueDetails/groupEventAttachments/useDeleteGroupEventAttachment.tsx
+++ b/static/app/views/issueDetails/groupEventAttachments/useDeleteGroupEventAttachment.tsx
@@ -1,26 +1,24 @@
+import {useMutation, useQueryClient} from '@tanstack/react-query';
+
import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
import {t} from 'sentry/locale';
import type {IssueAttachment} from 'sentry/types/group';
-import {
- getApiQueryData,
- setApiQueryData,
- useMutation,
- useQueryClient,
-} from 'sentry/utils/queryClient';
+import type {ApiResponse} from 'sentry/utils/api/apiFetch';
import type {RequestError} from 'sentry/utils/requestError/requestError';
import {useApi} from 'sentry/utils/useApi';
-import {makeFetchGroupEventAttachmentsQueryKey} from './useGroupEventAttachments';
+import {
+ fetchGroupEventAttachmentsApiOptions,
+ type FetchGroupEventAttachmentsApiOptionsParams,
+} from './useGroupEventAttachments';
-type DeleteGroupEventAttachmentVariables = Parameters<
- typeof makeFetchGroupEventAttachmentsQueryKey
->[0] & {
+type DeleteGroupEventAttachmentVariables = FetchGroupEventAttachmentsApiOptionsParams & {
attachment: IssueAttachment;
projectSlug: string;
};
type DeleteGroupEventAttachmentContext = {
- previous?: IssueAttachment[];
+ previous?: ApiResponse;
};
export function useDeleteGroupEventAttachment() {
@@ -41,28 +39,24 @@ export function useDeleteGroupEventAttachment() {
}
),
onMutate: async variables => {
- await queryClient.cancelQueries({
- queryKey: makeFetchGroupEventAttachmentsQueryKey(variables),
- });
+ const {queryKey} = fetchGroupEventAttachmentsApiOptions(variables);
- const previous = getApiQueryData(
- queryClient,
- makeFetchGroupEventAttachmentsQueryKey(variables)
- );
+ await queryClient.cancelQueries({queryKey});
- setApiQueryData(
- queryClient,
- makeFetchGroupEventAttachmentsQueryKey(variables),
- oldData => {
- if (!Array.isArray(oldData)) {
- return oldData;
- }
+ const previous = queryClient.getQueryData>(queryKey);
- return oldData.filter(
- oldAttachment => oldAttachment.id !== variables.attachment.id
- );
+ queryClient.setQueryData>(queryKey, oldData => {
+ if (!oldData) {
+ return oldData;
}
- );
+
+ return {
+ ...oldData,
+ json: oldData.json.filter(
+ oldAttachment => oldAttachment.id !== variables.attachment.id
+ ),
+ };
+ });
return {previous};
},
@@ -77,11 +71,8 @@ export function useDeleteGroupEventAttachment() {
);
if (context) {
- setApiQueryData(
- queryClient,
- makeFetchGroupEventAttachmentsQueryKey(variables),
- context.previous
- );
+ const {queryKey} = fetchGroupEventAttachmentsApiOptions(variables);
+ queryClient.setQueryData(queryKey, context.previous);
}
},
});
diff --git a/static/app/views/issueDetails/groupEventAttachments/useGroupEventAttachments.tsx b/static/app/views/issueDetails/groupEventAttachments/useGroupEventAttachments.tsx
index 00b6e9b93cae9b..7cab4ca24505d0 100644
--- a/static/app/views/issueDetails/groupEventAttachments/useGroupEventAttachments.tsx
+++ b/static/app/views/issueDetails/groupEventAttachments/useGroupEventAttachments.tsx
@@ -1,11 +1,9 @@
+import {useQuery} from '@tanstack/react-query';
+
import type {DateString} from 'sentry/types/core';
import type {Group, IssueAttachment} from 'sentry/types/group';
-import {getApiUrl} from 'sentry/utils/api/getApiUrl';
-import {
- useApiQuery,
- type ApiQueryKey,
- type UseApiQueryOptions,
-} from 'sentry/utils/queryClient';
+import {apiOptions, selectJsonWithHeaders} from 'sentry/utils/api/apiOptions';
+import {keepPreviousData} from 'sentry/utils/queryClient';
import {useLocation} from 'sentry/utils/useLocation';
import {useOrganization} from 'sentry/utils/useOrganization';
import {useEventQuery} from 'sentry/views/issueDetails/streamline/hooks/useEventQuery';
@@ -20,20 +18,10 @@ interface UseGroupEventAttachmentsOptions {
* current filters (for environment, date, query, etc).
*/
fetchAllAvailable?: boolean;
- placeholderData?: UseApiQueryOptions['placeholderData'];
+ placeholderData?: typeof keepPreviousData;
};
}
-interface MakeFetchGroupEventAttachmentsQueryKeyOptions extends UseGroupEventAttachmentsOptions {
- cursor: string | undefined;
- environment: string[] | string | undefined;
- orgSlug: string;
- end?: DateString;
- eventQuery?: string;
- start?: DateString;
- statsPeriod?: string;
-}
-
type GroupEventAttachmentsTypeFilter =
| 'event.minidump'
| 'event.applecrashreport'
@@ -51,7 +39,19 @@ interface GroupEventAttachmentsQuery {
types?: GroupEventAttachmentsTypeFilter | GroupEventAttachmentsTypeFilter[];
}
-export const makeFetchGroupEventAttachmentsQueryKey = ({
+export interface FetchGroupEventAttachmentsApiOptionsParams {
+ activeAttachmentsTab: 'all' | 'onlyCrash' | 'screenshot';
+ group: Group;
+ orgSlug: string;
+ cursor?: string;
+ end?: DateString;
+ environment?: string[] | string;
+ eventQuery?: string;
+ start?: DateString;
+ statsPeriod?: string;
+}
+
+export function fetchGroupEventAttachmentsApiOptions({
activeAttachmentsTab,
group,
orgSlug,
@@ -61,7 +61,7 @@ export const makeFetchGroupEventAttachmentsQueryKey = ({
start,
end,
statsPeriod,
-}: MakeFetchGroupEventAttachmentsQueryKeyOptions): ApiQueryKey => {
+}: FetchGroupEventAttachmentsApiOptionsParams) {
const query: GroupEventAttachmentsQuery = {};
if (environment) {
@@ -94,13 +94,15 @@ export const makeFetchGroupEventAttachmentsQueryKey = ({
query.types = ['event.minidump', 'event.applecrashreport'];
}
- return [
- getApiUrl('/organizations/$organizationIdOrSlug/issues/$issueId/attachments/', {
+ return apiOptions.as()(
+ '/organizations/$organizationIdOrSlug/issues/$issueId/attachments/',
+ {
path: {organizationIdOrSlug: orgSlug, issueId: group.id},
- }),
- {query},
- ];
-};
+ query,
+ staleTime: 60_000,
+ }
+ );
+}
export function useGroupEventAttachments({
group,
@@ -115,14 +117,9 @@ export function useGroupEventAttachments({
const hasSetStatsPeriod =
location.query.statsPeriod || location.query.start || location.query.end;
const fetchAllAvailable = options?.fetchAllAvailable;
- const {
- data: attachments = [],
- isPending,
- isError,
- getResponseHeader,
- refetch,
- } = useApiQuery(
- makeFetchGroupEventAttachmentsQueryKey({
+
+ const {data, isPending, isError, refetch} = useQuery({
+ ...fetchGroupEventAttachmentsApiOptions({
activeAttachmentsTab,
group,
orgSlug: organization.slug,
@@ -135,13 +132,15 @@ export function useGroupEventAttachments({
fetchAllAvailable && !hasSetStatsPeriod ? undefined : eventView.statsPeriod,
eventQuery: fetchAllAvailable ? undefined : eventQuery,
}),
- {placeholderData: options?.placeholderData, staleTime: 60_000}
- );
+ placeholderData: options?.placeholderData,
+ select: selectJsonWithHeaders,
+ });
+
return {
- attachments,
+ attachments: data?.json ?? [],
isPending,
isError,
- getResponseHeader,
+ pageLinks: data?.headers.Link ?? null,
refetch,
};
}
diff --git a/static/app/views/issueDetails/streamline/eventNavigation.tsx b/static/app/views/issueDetails/streamline/eventNavigation.tsx
index ce65213c9055ad..089de174b5080e 100644
--- a/static/app/views/issueDetails/streamline/eventNavigation.tsx
+++ b/static/app/views/issueDetails/streamline/eventNavigation.tsx
@@ -98,9 +98,7 @@ export function IssueEventNavigation({event, group}: IssueEventNavigationProps)
options: {placeholderData: keepPreviousData},
});
- const attachmentPagination = parseLinkHeader(
- attachments.getResponseHeader?.('Link') ?? null
- );
+ const attachmentPagination = parseLinkHeader(attachments.pageLinks);
// Since we reuse whatever page the user was on, we can look at pagination to determine if there are more attachments
const hasManyAttachments =
attachmentPagination.next?.results || attachmentPagination.previous?.results;
diff --git a/static/app/views/issueDetails/streamline/header/attachmentsBadge.tsx b/static/app/views/issueDetails/streamline/header/attachmentsBadge.tsx
index e37e62abe4fcfe..bb6548d40f53a4 100644
--- a/static/app/views/issueDetails/streamline/header/attachmentsBadge.tsx
+++ b/static/app/views/issueDetails/streamline/header/attachmentsBadge.tsx
@@ -23,9 +23,7 @@ export function AttachmentsBadge({group}: {group: Group}) {
options: {placeholderData: keepPreviousData, fetchAllAvailable: true},
});
- const attachmentPagination = parseLinkHeader(
- attachments.getResponseHeader?.('Link') ?? null
- );
+ const attachmentPagination = parseLinkHeader(attachments.pageLinks);
// Since we reuse whatever page the user was on, we can look at pagination to determine if there are more attachments
const hasManyAttachments =