From be936ec72c47ac485e76f7ee787c6d76c1bb8c0f Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Wed, 6 May 2026 10:45:14 -0700 Subject: [PATCH 1/9] fix(checkboxState): Update useListItemCheckboxContext to not rely on ApiQueryKEy directly, only QueryKeyEndpointOptions --- .../components/feedback/list/feedbackList.tsx | 3 +- .../replays/table/replayBulkViewedActions.tsx | 23 ++++++++------- .../replays/table/replayTableHeader.tsx | 9 ++---- .../utils/list/useListItemCheckboxState.tsx | 29 ++++++++----------- .../explore/replays/list/replayIndexTable.tsx | 8 +++-- .../projectTable/seerProjectTable.tsx | 4 ++- .../projectTable/seerProjectTableHeader.tsx | 5 +--- .../components/repoTable/seerRepoTable.tsx | 3 +- .../repoTable/seerRepoTableHeader.tsx | 5 +--- 9 files changed, 42 insertions(+), 47 deletions(-) diff --git a/static/app/components/feedback/list/feedbackList.tsx b/static/app/components/feedback/list/feedbackList.tsx index 2bf0cebea0ead2..4b9d8800e7d989 100644 --- a/static/app/components/feedback/list/feedbackList.tsx +++ b/static/app/components/feedback/list/feedbackList.tsx @@ -17,6 +17,7 @@ import {InfiniteListState} from 'sentry/components/infiniteList/infiniteListStat import {LoadingIndicator} from 'sentry/components/loadingIndicator'; import {t} from 'sentry/locale'; import type {ApiResponse} from 'sentry/utils/api/apiFetch'; +import {safeParseQueryKey} from 'sentry/utils/api/apiQueryKey'; import type {FeedbackIssueListItem} from 'sentry/utils/feedback/types'; import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState'; @@ -46,7 +47,7 @@ export function FeedbackList({onItemSelect}: Props) { const checkboxState = useListItemCheckboxContext({ hits: Number(queryResult.data?.pages[0]?.headers['X-Hits'] ?? issues.length), knownIds: issues.map(issue => issue.id), - queryKey: listApiOptions.queryKey, + queryKey: safeParseQueryKey(listApiOptions.queryKey)?.options, }); return ( diff --git a/static/app/components/replays/table/replayBulkViewedActions.tsx b/static/app/components/replays/table/replayBulkViewedActions.tsx index ce092e0129599c..53c58da72c4e70 100644 --- a/static/app/components/replays/table/replayBulkViewedActions.tsx +++ b/static/app/components/replays/table/replayBulkViewedActions.tsx @@ -8,18 +8,15 @@ import {LoadingIndicator} from 'sentry/components/loadingIndicator'; import {IconCheckmark} from 'sentry/icons'; import {t, tn} from 'sentry/locale'; import {trackAnalytics} from 'sentry/utils/analytics'; -import type {ApiResponse} from 'sentry/utils/api/apiFetch'; import type {ListCheckboxQueryKeyRef} from 'sentry/utils/list/useListItemCheckboxState'; import {fetchMutation} from 'sentry/utils/queryClient'; +import {replayListApiOptions} from 'sentry/utils/replays/replayListApiOptions'; import {useOrganization} from 'sentry/utils/useOrganization'; -import type { - HydratedReplayRecord, - ReplayListRecord, -} from 'sentry/views/explore/replays/types'; +import type {ReplayListRecord} from 'sentry/views/explore/replays/types'; interface Props { deselectAll: () => void; - queryKeyRef: ListCheckboxQueryKeyRef; + queryOptionsRef: ListCheckboxQueryKeyRef; replays: ReplayListRecord[]; selectedIds: string[]; } @@ -28,7 +25,7 @@ export function ReplayBulkViewedActions({ deselectAll, replays, selectedIds, - queryKeyRef, + queryOptionsRef, }: Props) { const organization = useOrganization(); const queryClient = useQueryClient(); @@ -55,10 +52,14 @@ export function ReplayBulkViewedActions({ ); if (succeededIds.size) { - if (queryKeyRef.current) { - // eslint-disable-next-line @sentry/no-query-data-type-parameters - queryClient.setQueryData>( - queryKeyRef.current, + if (queryOptionsRef.current) { + const replayListOptions = replayListApiOptions({ + options: queryOptionsRef.current, + organization, + queryReferrer: 'replayList', + }); + queryClient.setQueryData( + replayListOptions.queryKey, old => old && { ...old, diff --git a/static/app/components/replays/table/replayTableHeader.tsx b/static/app/components/replays/table/replayTableHeader.tsx index c4ca2cc931af6f..8db731ffc6d50c 100644 --- a/static/app/components/replays/table/replayTableHeader.tsx +++ b/static/app/components/replays/table/replayTableHeader.tsx @@ -12,7 +12,6 @@ import { } from 'sentry/components/replays/table/replayTableColumns'; import {SimpleTable} from 'sentry/components/tables/simpleTable'; import {t, tct, tn} from 'sentry/locale'; -import {parseQueryKey} from 'sentry/utils/api/apiQueryKey'; import type {Sort} from 'sentry/utils/discover/fields'; import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState'; import type {ReplayListRecord} from 'sentry/views/explore/replays/types'; @@ -42,9 +41,7 @@ export function ReplayTableHeader({ selectAll, selectedIds, } = listItemCheckboxState; - const queryOptions = queryKeyRef.current - ? parseQueryKey(queryKeyRef.current).options - : undefined; + const queryOptions = queryKeyRef.current; const queryString = queryOptions?.query?.query as string | undefined; const headerStyle: React.CSSProperties = stickyHeader @@ -89,13 +86,13 @@ export function ReplayTableHeader({ {selectedIds !== 'all' && ( )} diff --git a/static/app/utils/list/useListItemCheckboxState.tsx b/static/app/utils/list/useListItemCheckboxState.tsx index a99f1529e51b58..4e23badd94e5e9 100644 --- a/static/app/utils/list/useListItemCheckboxState.tsx +++ b/static/app/utils/list/useListItemCheckboxState.tsx @@ -9,11 +9,10 @@ import { useState, } from 'react'; +import type {QueryKeyEndpointOptions} from 'sentry/utils/api/apiQueryKey'; import {toArray} from 'sentry/utils/array/toArray'; -import type {ApiQueryKey, InfiniteApiQueryKey} from 'sentry/utils/queryClient'; -type ListCheckboxQueryKeyValue = undefined | ApiQueryKey | InfiniteApiQueryKey; -export type ListCheckboxQueryKeyRef = RefObject; +export type ListCheckboxQueryKeyRef = RefObject; interface PublicProps { /** @@ -27,12 +26,15 @@ interface PublicProps { knownIds: string[]; /** - * The query key that fetches the list. + * The cache-key that identifies the query & results. * - * The selection will be reset when then query key changes. Therefore be + * When the key changes, the selection will be reset. Therefore be * mindful of query params like `cursor` creating a new query key. + * + * This is not the same as ApiQueryKey. But you could use: + * `safeParseQueryKey(apiQueryKey)?.options`. */ - queryKey: ListCheckboxQueryKeyValue; + queryKey: undefined | QueryKeyEndpointOptions; } interface InternalProps { @@ -118,16 +120,12 @@ export interface ListItemCheckboxState { const defaultQueryKeyRef: ListCheckboxQueryKeyRef = {current: undefined}; -const ListItemCheckboxContext = createContext<{ - hits: number; - knownIds: string[]; - queryKeyRef: ListCheckboxQueryKeyRef; - setState?: Dispatch>; - state?: State; -}>({ +const ListItemCheckboxContext = createContext({ hits: 0, knownIds: [], queryKeyRef: defaultQueryKeyRef, + setState: () => {}, + state: {ids: new Set()}, }); export function ListItemCheckboxProvider({ @@ -137,10 +135,7 @@ export function ListItemCheckboxProvider({ queryKey, }: { children: React.ReactNode; - hits: number; - knownIds: string[]; - queryKey: ListCheckboxQueryKeyValue; -}) { +} & PublicProps) { const [state, setState] = useState({ids: new Set()}); const queryKeyRef = useRef(queryKey); diff --git a/static/app/views/explore/replays/list/replayIndexTable.tsx b/static/app/views/explore/replays/list/replayIndexTable.tsx index 499623e6e3f508..cae548ef86035e 100644 --- a/static/app/views/explore/replays/list/replayIndexTable.tsx +++ b/static/app/views/explore/replays/list/replayIndexTable.tsx @@ -11,7 +11,11 @@ import {ReplayTable} from 'sentry/components/replays/table/replayTable'; import {useReplayTableSort} from 'sentry/components/replays/table/useReplayTableSort'; import {usePlaylistQuery} from 'sentry/components/replays/usePlaylistQuery'; import {t, tct} from 'sentry/locale'; -import {type ApiQueryKey, parseQueryKey} from 'sentry/utils/api/apiQueryKey'; +import { + type ApiQueryKey, + parseQueryKey, + safeParseQueryKey, +} from 'sentry/utils/api/apiQueryKey'; import {ListItemCheckboxProvider} from 'sentry/utils/list/useListItemCheckboxState'; import {MIN_REPLAY_CLICK_SDK} from 'sentry/utils/replays/sdkVersions'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; @@ -82,7 +86,7 @@ export function ReplayIndexTable({ replay.id)} - queryKey={queryKey} + queryKey={safeParseQueryKey(queryKey)?.options} > {needsSDKUpdateForClickSearch ? ( diff --git a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx index 3fb658852079b9..e0eea652a4a43d 100644 --- a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx +++ b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx @@ -33,6 +33,7 @@ import {IconSearch} from 'sentry/icons/iconSearch'; import {t, tct} from 'sentry/locale'; import {ProjectsStore} from 'sentry/stores/projectsStore'; import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; +import {safeParseQueryKey} from 'sentry/utils/api/apiQueryKey'; import {ListItemCheckboxProvider} from 'sentry/utils/list/useListItemCheckboxState'; import type {ApiQueryKey} from 'sentry/utils/queryClient'; import {getCodingAgentSelectQueryOptions} from 'sentry/utils/seer/preferredAgent'; @@ -169,6 +170,7 @@ export function SeerProjectTable() { const queryKey = [ 'seer-projects', {query: {query: searchTerm, sort, agent: agentFilter}}, + {infinite: false}, ] as unknown as ApiQueryKey; const sortedProjects = useMemo(() => { @@ -273,7 +275,7 @@ export function SeerProjectTable() { project.id)} - queryKey={queryKey} + queryKey={safeParseQueryKey(queryKey)?.options} > diff --git a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx index 50d7de9d23898e..29511c077da659 100644 --- a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx +++ b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx @@ -15,7 +15,6 @@ import {SimpleTable} from 'sentry/components/tables/simpleTable'; import {t, tct, tn} from 'sentry/locale'; import type {Organization} from 'sentry/types/organization'; import type {Project} from 'sentry/types/project'; -import {parseQueryKey} from 'sentry/utils/api/apiQueryKey'; import type {Sort} from 'sentry/utils/discover/fields'; import { useListItemCheckboxContext, @@ -118,9 +117,7 @@ export function ProjectTableHeader({ selectAll, selectedIds, } = listItemCheckboxState; - const queryOptions = queryKeyRef.current - ? parseQueryKey(queryKeyRef.current).options - : undefined; + const queryOptions = queryKeyRef.current; const queryString = queryOptions?.query?.query as string | undefined; const projectIds = useMemo( diff --git a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx index d438ba4aaaa879..b3ed90184c23ca 100644 --- a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx +++ b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx @@ -24,6 +24,7 @@ import {IconSearch} from 'sentry/icons/iconSearch'; import {t, tct} from 'sentry/locale'; import type {RepositoryWithSettings} from 'sentry/types/integrations'; import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; +import {safeParseQueryKey} from 'sentry/utils/api/apiQueryKey'; import {getSeerOnboardingCheckQueryOptions} from 'sentry/utils/getSeerOnboardingCheckQueryOptions'; import { ListItemCheckboxProvider, @@ -200,7 +201,7 @@ export function SeerRepoTable() { { From 6ee5bb4ff29d36a8065aaa1a85d8a05d1df36d76 Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Wed, 6 May 2026 11:45:49 -0700 Subject: [PATCH 2/9] Use the provider in feedbackList and simplify away the useListItemCheckboxContext hook --- .../components/feedback/list/feedbackList.tsx | 23 +++++------- .../feedback/list/feedbackListHeader.tsx | 29 ++++++--------- .../feedback/list/feedbackListItem.tsx | 20 +++++------ .../utils/list/useListItemCheckboxState.tsx | 36 +++---------------- 4 files changed, 31 insertions(+), 77 deletions(-) diff --git a/static/app/components/feedback/list/feedbackList.tsx b/static/app/components/feedback/list/feedbackList.tsx index 4b9d8800e7d989..f01231f1376668 100644 --- a/static/app/components/feedback/list/feedbackList.tsx +++ b/static/app/components/feedback/list/feedbackList.tsx @@ -1,4 +1,4 @@ -import {Fragment, useMemo} from 'react'; +import {useMemo} from 'react'; import styled from '@emotion/styled'; import {useInfiniteQuery} from '@tanstack/react-query'; import uniqBy from 'lodash/uniqBy'; @@ -19,7 +19,7 @@ import {t} from 'sentry/locale'; import type {ApiResponse} from 'sentry/utils/api/apiFetch'; import {safeParseQueryKey} from 'sentry/utils/api/apiQueryKey'; import type {FeedbackIssueListItem} from 'sentry/utils/feedback/types'; -import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState'; +import {ListItemCheckboxProvider} from 'sentry/utils/list/useListItemCheckboxState'; function NoFeedback() { return ( @@ -44,15 +44,14 @@ export function FeedbackList({onItemSelect}: Props) { () => uniqBy(queryResult.data?.pages.flatMap(page => page.json) ?? [], 'id'), [queryResult.data?.pages] ); - const checkboxState = useListItemCheckboxContext({ - hits: Number(queryResult.data?.pages[0]?.headers['X-Hits'] ?? issues.length), - knownIds: issues.map(issue => issue.id), - queryKey: safeParseQueryKey(listApiOptions.queryKey)?.options, - }); return ( - - + issue.id)} + queryKey={safeParseQueryKey(listApiOptions.queryKey)?.options} + > + { - checkboxState.toggleSelected(item.id); - }} onItemSelect={() => onItemSelect(itemIndex)} /> @@ -95,7 +90,7 @@ export function FeedbackList({onItemSelect}: Props) { /> - + ); } diff --git a/static/app/components/feedback/list/feedbackListHeader.tsx b/static/app/components/feedback/list/feedbackListHeader.tsx index 7113d6014fb6f9..30852a7560560b 100644 --- a/static/app/components/feedback/list/feedbackListHeader.tsx +++ b/static/app/components/feedback/list/feedbackListHeader.tsx @@ -12,26 +12,17 @@ import {useFeedbackHasNewItems} from 'sentry/components/feedback/useFeedbackHasN import {useMailbox} from 'sentry/components/feedback/useMailbox'; import {IconRefresh} from 'sentry/icons'; import {t} from 'sentry/locale'; -import type {ListItemCheckboxState} from 'sentry/utils/list/useListItemCheckboxState'; +import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState'; -interface Props extends Pick< - ListItemCheckboxState, - | 'countSelected' - | 'deselectAll' - | 'isAllSelected' - | 'isAnySelected' - | 'selectAll' - | 'selectedIds' -> {} - -export function FeedbackListHeader({ - countSelected, - deselectAll, - isAllSelected, - isAnySelected, - selectAll, - selectedIds, -}: Props) { +export function FeedbackListHeader() { + const { + countSelected, + deselectAll, + isAllSelected, + isAnySelected, + selectAll, + selectedIds, + } = useListItemCheckboxContext(); const [mailbox, setMailbox] = useMailbox(); const {listPrefetchApiOptions, resetListHeadTime} = useFeedbackApiOptions(); diff --git a/static/app/components/feedback/list/feedbackListItem.tsx b/static/app/components/feedback/list/feedbackListItem.tsx index cd8e9a397177f3..61888c6284190e 100644 --- a/static/app/components/feedback/list/feedbackListItem.tsx +++ b/static/app/components/feedback/list/feedbackListItem.tsx @@ -17,6 +17,7 @@ import type {Group} from 'sentry/types/group'; import {trackAnalytics} from 'sentry/utils/analytics'; import {feedbackHasLinkedError} from 'sentry/utils/feedback/hasLinkedError'; import {type FeedbackIssueListItem} from 'sentry/utils/feedback/types'; +import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState'; import {decodeScalar} from 'sentry/utils/queryString'; import {useReplayCountForFeedbacks} from 'sentry/utils/replayCount/useReplayCountForFeedbacks'; import {useLocationQuery} from 'sentry/utils/url/useLocationQuery'; @@ -26,9 +27,7 @@ import {makeFeedbackPathname} from 'sentry/views/feedback/pathnames'; interface Props { feedbackItem: FeedbackIssueListItem; - isSelected: 'all-selected' | boolean; onItemSelect: () => void; - onSelect: (isSelected: boolean) => void; } function useIsSelectedFeedback({feedbackItem}: {feedbackItem: FeedbackIssueListItem}) { @@ -39,12 +38,9 @@ function useIsSelectedFeedback({feedbackItem}: {feedbackItem: FeedbackIssueListI return feedbackId === feedbackItem.id; } -export function FeedbackListItem({ - feedbackItem, - isSelected, - onSelect, - onItemSelect, -}: Props) { +export function FeedbackListItem({feedbackItem, onItemSelect}: Props) { + const {isSelected, toggleSelected} = useListItemCheckboxContext(); + const organization = useOrganization(); const isOpen = useIsSelectedFeedback({feedbackItem}); const {feedbackHasReplay} = useReplayCountForFeedbacks(); @@ -84,10 +80,10 @@ export function FeedbackListItem({ }} > { - onSelect(e.target.checked); + disabled={isSelected(feedbackItem.id) === 'all-selected'} + checked={isSelected(feedbackItem.id) !== false} + onChange={() => { + toggleSelected(feedbackItem.id); }} /> diff --git a/static/app/utils/list/useListItemCheckboxState.tsx b/static/app/utils/list/useListItemCheckboxState.tsx index 4e23badd94e5e9..317b0888c57174 100644 --- a/static/app/utils/list/useListItemCheckboxState.tsx +++ b/static/app/utils/list/useListItemCheckboxState.tsx @@ -155,39 +155,11 @@ export function ListItemCheckboxProvider({ ); } -export function useListItemCheckboxContext(props?: PublicProps) { - const [localState, localSetState] = useState({ids: new Set()}); - const context = useContext(ListItemCheckboxContext); - - const setState = context.setState ?? localSetState; - const state = context.state ?? localState; - - const localQueryKeyRef = useRef(props?.queryKey); - const serializedPropsKey = JSON.stringify(props?.queryKey); - useEffect(() => { - if (props?.queryKey !== undefined) { - localQueryKeyRef.current = props.queryKey; - setState({ids: new Set()}); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [serializedPropsKey]); - - return useListItemCheckboxState({ - state, - setState, - hits: props?.hits ?? context.hits, - knownIds: props?.knownIds ?? context.knownIds, - queryKeyRef: props?.queryKey === undefined ? context.queryKeyRef : localQueryKeyRef, - }); -} +export function useListItemCheckboxContext(): ListItemCheckboxState { + const {state, setState, hits, knownIds, queryKeyRef} = useContext( + ListItemCheckboxContext + ); -function useListItemCheckboxState({ - hits, - knownIds, - queryKeyRef, - state, - setState, -}: MergedProps): ListItemCheckboxState { const selectAll = useCallback(() => { // Record that the virtual "all" list is enabled. setState({all: true}); From f96346a2e271e266b65de83d3686b9cffaf434e6 Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Wed, 6 May 2026 12:03:49 -0700 Subject: [PATCH 3/9] knip --- static/app/utils/queryClient.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/static/app/utils/queryClient.tsx b/static/app/utils/queryClient.tsx index bd599969c4f855..a706a7887a8a90 100644 --- a/static/app/utils/queryClient.tsx +++ b/static/app/utils/queryClient.tsx @@ -13,11 +13,7 @@ import type {ApiResponse} from 'sentry/utils/api/apiFetch'; import {apiFetch} from 'sentry/utils/api/apiFetch'; import {selectJson} from 'sentry/utils/api/apiOptions'; import {normalizeQueryKey} from 'sentry/utils/api/apiQueryKey'; -import type { - ApiQueryKey, - InfiniteApiQueryKey, - QueryKeyEndpointOptions, -} from 'sentry/utils/api/apiQueryKey'; +import type {ApiQueryKey, QueryKeyEndpointOptions} from 'sentry/utils/api/apiQueryKey'; import type {RequestError} from 'sentry/utils/requestError/requestError'; export type { @@ -25,10 +21,6 @@ export type { * @deprecated Use `import type {ApiQueryKey} from 'sentry/utils/api/apiQueryKey';` directly instead. */ ApiQueryKey, - /** - * @deprecated Use `import type {InfiniteApiQueryKey} from 'sentry/utils/api/apiQueryKey';` directlyinstead. - */ - InfiniteApiQueryKey, /** * @deprecated Use `import type {QueryKeyEndpointOptions} from 'sentry/utils/api/apiQueryKey';` directly instead. */ From 71faf308da713f082bd3398aa5acf90e0a772981 Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Wed, 6 May 2026 12:14:50 -0700 Subject: [PATCH 4/9] fix tests --- ...c.ts => useListItemCheckboxState.spec.tsx} | 66 ++++++++++++------- 1 file changed, 41 insertions(+), 25 deletions(-) rename static/app/utils/list/{useListItemCheckboxState.spec.ts => useListItemCheckboxState.spec.tsx} (85%) diff --git a/static/app/utils/list/useListItemCheckboxState.spec.ts b/static/app/utils/list/useListItemCheckboxState.spec.tsx similarity index 85% rename from static/app/utils/list/useListItemCheckboxState.spec.ts rename to static/app/utils/list/useListItemCheckboxState.spec.tsx index 82e2cd616fa25a..f955590d509b62 100644 --- a/static/app/utils/list/useListItemCheckboxState.spec.ts +++ b/static/app/utils/list/useListItemCheckboxState.spec.tsx @@ -1,17 +1,33 @@ +import {type ComponentProps, type PropsWithChildren} from 'react'; + import {act, renderHook} from 'sentry-test/reactTestingLibrary'; -import {getApiUrl} from 'sentry/utils/api/getApiUrl'; -import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState'; -import type {ApiQueryKey} from 'sentry/utils/queryClient'; +import type {QueryKeyEndpointOptions} from 'sentry/utils/api/apiQueryKey'; +import { + ListItemCheckboxProvider, + useListItemCheckboxContext, +} from 'sentry/utils/list/useListItemCheckboxState'; + +const queryKey: QueryKeyEndpointOptions = {query: {status: 'active'}}; + +type ProviderProps = ComponentProps; -const queryKey: ApiQueryKey = [getApiUrl('/api-tokens/')]; +function createWrapper(props: Omit) { + return function Wrapper({children}: PropsWithChildren) { + return ( + + {children} + + ); + }; +} describe('useListItemCheckboxContext', () => { describe('All hits are already known', () => { it('should return the correct initial state', () => { - const {result} = renderHook(() => - useListItemCheckboxContext({hits: 3, knownIds: ['1', '2', '3'], queryKey}) - ); + const {result} = renderHook(useListItemCheckboxContext, { + wrapper: createWrapper({hits: 3, knownIds: ['1', '2', '3']}), + }); expect(result.current).toEqual({ countSelected: 0, deselectAll: expect.any(Function), @@ -28,9 +44,9 @@ describe('useListItemCheckboxContext', () => { }); it('should allow selecting an individual item when all hits are known', () => { - const {result} = renderHook(() => - useListItemCheckboxContext({hits: 3, knownIds: ['1', '2', '3'], queryKey}) - ); + const {result} = renderHook(useListItemCheckboxContext, { + wrapper: createWrapper({hits: 3, knownIds: ['1', '2', '3']}), + }); // Initially nothing is selected expect(result.current.isSelected('1')).toBe(false); @@ -84,9 +100,9 @@ describe('useListItemCheckboxContext', () => { }); it('sets isAllSelected to true when all items are selected', () => { - const {result} = renderHook(() => - useListItemCheckboxContext({hits: 3, knownIds: ['1', '2', '3'], queryKey}) - ); + const {result} = renderHook(useListItemCheckboxContext, { + wrapper: createWrapper({hits: 3, knownIds: ['1', '2', '3']}), + }); // Initially nothing is selected expect(result.current.isSelected('1')).toBe(false); @@ -108,9 +124,9 @@ describe('useListItemCheckboxContext', () => { }); it('should allow selecting all items with selectAll', () => { - const {result} = renderHook(() => - useListItemCheckboxContext({hits: 3, knownIds: ['1', '2', '3'], queryKey}) - ); + const {result} = renderHook(useListItemCheckboxContext, { + wrapper: createWrapper({hits: 3, knownIds: ['1', '2', '3']}), + }); // Initially nothing is selected expect(result.current.isSelected('1')).toBe(false); @@ -152,9 +168,9 @@ describe('useListItemCheckboxContext', () => { describe('More hits to load', () => { it('should return the correct initial state', () => { - const {result} = renderHook(() => - useListItemCheckboxContext({hits: 10, knownIds: ['1', '2', '3'], queryKey}) - ); + const {result} = renderHook(useListItemCheckboxContext, { + wrapper: createWrapper({hits: 10, knownIds: ['1', '2', '3']}), + }); expect(result.current).toEqual({ countSelected: 0, deselectAll: expect.any(Function), @@ -171,9 +187,9 @@ describe('useListItemCheckboxContext', () => { }); it('should allow selecting individual items when there are more hits to load', () => { - const {result} = renderHook(() => - useListItemCheckboxContext({hits: 10, knownIds: ['1', '2', '3'], queryKey}) - ); + const {result} = renderHook(useListItemCheckboxContext, { + wrapper: createWrapper({hits: 10, knownIds: ['1', '2', '3']}), + }); // Initially nothing is selected expect(result.current.isSelected('1')).toBe(false); @@ -241,9 +257,9 @@ describe('useListItemCheckboxContext', () => { }); it('should allow selecting all items with selectAll', () => { - const {result} = renderHook(() => - useListItemCheckboxContext({hits: 10, knownIds: ['1', '2', '3'], queryKey}) - ); + const {result} = renderHook(useListItemCheckboxContext, { + wrapper: createWrapper({hits: 10, knownIds: ['1', '2', '3']}), + }); // Initially nothing is selected expect(result.current.isSelected('1')).toBe(false); From b296ada25e9120b4cb3c9fb1405c461f60c3dbb1 Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Wed, 6 May 2026 12:30:46 -0700 Subject: [PATCH 5/9] fix: Update test to use renamed queryOptionsRef prop in ReplayBulkViewedActions --- .../table/replayBulkViewedActions.spec.tsx | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/static/app/components/replays/table/replayBulkViewedActions.spec.tsx b/static/app/components/replays/table/replayBulkViewedActions.spec.tsx index eec077618c3376..bd786435a5a3a9 100644 --- a/static/app/components/replays/table/replayBulkViewedActions.spec.tsx +++ b/static/app/components/replays/table/replayBulkViewedActions.spec.tsx @@ -6,8 +6,6 @@ import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrar import {ReplayBulkViewedActions} from 'sentry/components/replays/table/replayBulkViewedActions'; import {ProjectsStore} from 'sentry/stores/projectsStore'; import {trackAnalytics} from 'sentry/utils/analytics'; -import type {ApiQueryKey} from 'sentry/utils/api/apiQueryKey'; -import {getApiUrl} from 'sentry/utils/api/getApiUrl'; import type {ListCheckboxQueryKeyRef} from 'sentry/utils/list/useListItemCheckboxState'; import type {ReplayListRecord} from 'sentry/views/explore/replays/types'; @@ -51,22 +49,11 @@ describe('ReplayBulkViewedActions', () => { const replay = createReplay(); const deselectAll = jest.fn(); - const apiUrl = getApiUrl( - '/projects/$organizationIdOrSlug/$projectIdOrSlug/replays/$replayId/viewed-by/', - { - path: { - organizationIdOrSlug: organization.id, - projectIdOrSlug: 2, - replayId: replay.id, - }, - } - ); - const queryKey: ApiQueryKey = [apiUrl, {}, {infinite: false}]; - const queryKeyRef = {current: queryKey}; + const queryOptionsRef: ListCheckboxQueryKeyRef = {current: {query: {}}}; const renderWithOrganization = ( overrides: { - queryKeyRef?: ListCheckboxQueryKeyRef; + queryOptionsRef?: ListCheckboxQueryKeyRef; replays?: ReplayListRecord[]; selectedIds?: string[]; } = {} @@ -74,7 +61,7 @@ describe('ReplayBulkViewedActions', () => { render( , From cc365eddc64c27dd3a0f1fd6a3ba64c1de9e0925 Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Thu, 7 May 2026 14:11:21 -0700 Subject: [PATCH 6/9] rename all the things --- .../components/feedback/list/feedbackList.tsx | 2 +- .../table/replayBulkViewedActions.spec.tsx | 6 +- .../replays/table/replayBulkViewedActions.tsx | 8 +-- .../replays/table/replayTableHeader.tsx | 10 ++-- .../list/useListItemCheckboxState.spec.tsx | 10 ++-- .../utils/list/useListItemCheckboxState.tsx | 58 +++++++++---------- .../explore/replays/list/replayIndexTable.tsx | 12 ++-- .../projectTable/seerProjectTable.tsx | 2 +- .../projectTable/seerProjectTableHeader.tsx | 6 +- .../components/repoTable/seerRepoTable.tsx | 2 +- .../repoTable/seerRepoTableHeader.tsx | 6 +- 11 files changed, 59 insertions(+), 63 deletions(-) diff --git a/static/app/components/feedback/list/feedbackList.tsx b/static/app/components/feedback/list/feedbackList.tsx index f01231f1376668..07bf6f3837c8f1 100644 --- a/static/app/components/feedback/list/feedbackList.tsx +++ b/static/app/components/feedback/list/feedbackList.tsx @@ -49,7 +49,7 @@ export function FeedbackList({onItemSelect}: Props) { issue.id)} - queryKey={safeParseQueryKey(listApiOptions.queryKey)?.options} + endpointOptions={safeParseQueryKey(listApiOptions.queryKey)?.options} > diff --git a/static/app/components/replays/table/replayBulkViewedActions.spec.tsx b/static/app/components/replays/table/replayBulkViewedActions.spec.tsx index bd786435a5a3a9..87b35c58752906 100644 --- a/static/app/components/replays/table/replayBulkViewedActions.spec.tsx +++ b/static/app/components/replays/table/replayBulkViewedActions.spec.tsx @@ -49,11 +49,11 @@ describe('ReplayBulkViewedActions', () => { const replay = createReplay(); const deselectAll = jest.fn(); - const queryOptionsRef: ListCheckboxQueryKeyRef = {current: {query: {}}}; + const endpointOptionsRef: ListCheckboxQueryKeyRef = {current: {query: {}}}; const renderWithOrganization = ( overrides: { - queryOptionsRef?: ListCheckboxQueryKeyRef; + endpointOptionsRef?: ListCheckboxQueryKeyRef; replays?: ReplayListRecord[]; selectedIds?: string[]; } = {} @@ -61,7 +61,7 @@ describe('ReplayBulkViewedActions', () => { render( , diff --git a/static/app/components/replays/table/replayBulkViewedActions.tsx b/static/app/components/replays/table/replayBulkViewedActions.tsx index 53c58da72c4e70..e4b1be7c387af7 100644 --- a/static/app/components/replays/table/replayBulkViewedActions.tsx +++ b/static/app/components/replays/table/replayBulkViewedActions.tsx @@ -16,7 +16,7 @@ import type {ReplayListRecord} from 'sentry/views/explore/replays/types'; interface Props { deselectAll: () => void; - queryOptionsRef: ListCheckboxQueryKeyRef; + endpointOptionsRef: ListCheckboxQueryKeyRef; replays: ReplayListRecord[]; selectedIds: string[]; } @@ -25,7 +25,7 @@ export function ReplayBulkViewedActions({ deselectAll, replays, selectedIds, - queryOptionsRef, + endpointOptionsRef, }: Props) { const organization = useOrganization(); const queryClient = useQueryClient(); @@ -52,9 +52,9 @@ export function ReplayBulkViewedActions({ ); if (succeededIds.size) { - if (queryOptionsRef.current) { + if (endpointOptionsRef.current) { const replayListOptions = replayListApiOptions({ - options: queryOptionsRef.current, + options: endpointOptionsRef.current, organization, queryReferrer: 'replayList', }); diff --git a/static/app/components/replays/table/replayTableHeader.tsx b/static/app/components/replays/table/replayTableHeader.tsx index 8db731ffc6d50c..6b2a769a0bbea0 100644 --- a/static/app/components/replays/table/replayTableHeader.tsx +++ b/static/app/components/replays/table/replayTableHeader.tsx @@ -37,12 +37,12 @@ export function ReplayTableHeader({ deselectAll, isAllSelected, isAnySelected, - queryKeyRef, + endpointOptionsRef, selectAll, selectedIds, } = listItemCheckboxState; - const queryOptions = queryKeyRef.current; - const queryString = queryOptions?.query?.query as string | undefined; + const endpointOptions = endpointOptionsRef.current; + const queryString = endpointOptions?.query?.query as string | undefined; const headerStyle: React.CSSProperties = stickyHeader ? {position: 'sticky', top: 0} @@ -86,13 +86,13 @@ export function ReplayTableHeader({ {selectedIds !== 'all' && ( )} diff --git a/static/app/utils/list/useListItemCheckboxState.spec.tsx b/static/app/utils/list/useListItemCheckboxState.spec.tsx index f955590d509b62..ecff32c27ee3bb 100644 --- a/static/app/utils/list/useListItemCheckboxState.spec.tsx +++ b/static/app/utils/list/useListItemCheckboxState.spec.tsx @@ -8,14 +8,14 @@ import { useListItemCheckboxContext, } from 'sentry/utils/list/useListItemCheckboxState'; -const queryKey: QueryKeyEndpointOptions = {query: {status: 'active'}}; +const endpointOptions: QueryKeyEndpointOptions = {query: {status: 'active'}}; type ProviderProps = ComponentProps; -function createWrapper(props: Omit) { +function createWrapper(props: Omit) { return function Wrapper({children}: PropsWithChildren) { return ( - + {children} ); @@ -36,7 +36,7 @@ describe('useListItemCheckboxContext', () => { isAnySelected: false, isSelected: expect.any(Function), knownIds: ['1', '2', '3'], - queryKeyRef: {current: queryKey}, + queryKeyRef: {current: endpointOptions}, selectAll: expect.any(Function), selectedIds: [], toggleSelected: expect.any(Function), @@ -179,7 +179,7 @@ describe('useListItemCheckboxContext', () => { isAnySelected: false, isSelected: expect.any(Function), knownIds: ['1', '2', '3'], - queryKeyRef: {current: queryKey}, + queryKeyRef: {current: endpointOptions}, selectAll: expect.any(Function), selectedIds: [], toggleSelected: expect.any(Function), diff --git a/static/app/utils/list/useListItemCheckboxState.tsx b/static/app/utils/list/useListItemCheckboxState.tsx index 317b0888c57174..5a3f24dae481d5 100644 --- a/static/app/utils/list/useListItemCheckboxState.tsx +++ b/static/app/utils/list/useListItemCheckboxState.tsx @@ -15,16 +15,6 @@ import {toArray} from 'sentry/utils/array/toArray'; export type ListCheckboxQueryKeyRef = RefObject; interface PublicProps { - /** - * The total number of items the query could return - */ - hits: number; - - /** - * The number of items that are currently loaded into the browser - */ - knownIds: string[]; - /** * The cache-key that identifies the query & results. * @@ -34,15 +24,25 @@ interface PublicProps { * This is not the same as ApiQueryKey. But you could use: * `safeParseQueryKey(apiQueryKey)?.options`. */ - queryKey: undefined | QueryKeyEndpointOptions; + endpointOptions: undefined | QueryKeyEndpointOptions; + + /** + * The total number of items the query could return + */ + hits: number; + + /** + * The number of items that are currently loaded into the browser + */ + knownIds: string[]; } interface InternalProps { - queryKeyRef: ListCheckboxQueryKeyRef; + endpointOptionsRef: ListCheckboxQueryKeyRef; setState: Dispatch>; state: State; } -type MergedProps = Omit & InternalProps; +type MergedProps = Omit & InternalProps; /** * We can either have a list of ids, or have all selected. @@ -61,6 +61,13 @@ export interface ListItemCheckboxState { */ deselectAll: () => void; + /** + * Stable ref to the query key that fetches the list. + * + * Read `.current` to access the value. + */ + endpointOptionsRef: ListCheckboxQueryKeyRef; + /** * The total number of items the query could return */ @@ -94,13 +101,6 @@ export interface ListItemCheckboxState { */ knownIds: string[]; - /** - * Stable ref to the query key that fetches the list. - * - * Read `.current` to access the value. - */ - queryKeyRef: ListCheckboxQueryKeyRef; - /** * Record that all are selected, wether or not all feedback ids are loaded or not */ @@ -123,7 +123,7 @@ const defaultQueryKeyRef: ListCheckboxQueryKeyRef = {current: undefined}; const ListItemCheckboxContext = createContext({ hits: 0, knownIds: [], - queryKeyRef: defaultQueryKeyRef, + endpointOptionsRef: defaultQueryKeyRef, setState: () => {}, state: {ids: new Set()}, }); @@ -132,23 +132,23 @@ export function ListItemCheckboxProvider({ children, hits, knownIds, - queryKey, + endpointOptions, }: { children: React.ReactNode; } & PublicProps) { const [state, setState] = useState({ids: new Set()}); - const queryKeyRef = useRef(queryKey); + const endpointOptionsRef = useRef(endpointOptions); - const serializedQueryKey = JSON.stringify(queryKey); + const serializedEndpointOptions = JSON.stringify(endpointOptions); useEffect(() => { - queryKeyRef.current = queryKey; + endpointOptionsRef.current = endpointOptions; setState({ids: new Set()}); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [serializedQueryKey]); + }, [serializedEndpointOptions]); return ( {children} @@ -156,7 +156,7 @@ export function ListItemCheckboxProvider({ } export function useListItemCheckboxContext(): ListItemCheckboxState { - const {state, setState, hits, knownIds, queryKeyRef} = useContext( + const {state, setState, hits, knownIds, endpointOptionsRef} = useContext( ListItemCheckboxContext ); @@ -248,7 +248,7 @@ export function useListItemCheckboxContext(): ListItemCheckboxState { isAnySelected, isSelected, knownIds, - queryKeyRef, + endpointOptionsRef, selectAll, selectedIds, toggleSelected, diff --git a/static/app/views/explore/replays/list/replayIndexTable.tsx b/static/app/views/explore/replays/list/replayIndexTable.tsx index cae548ef86035e..fd2c9b646f6e74 100644 --- a/static/app/views/explore/replays/list/replayIndexTable.tsx +++ b/static/app/views/explore/replays/list/replayIndexTable.tsx @@ -11,11 +11,7 @@ import {ReplayTable} from 'sentry/components/replays/table/replayTable'; import {useReplayTableSort} from 'sentry/components/replays/table/useReplayTableSort'; import {usePlaylistQuery} from 'sentry/components/replays/usePlaylistQuery'; import {t, tct} from 'sentry/locale'; -import { - type ApiQueryKey, - parseQueryKey, - safeParseQueryKey, -} from 'sentry/utils/api/apiQueryKey'; +import {type ApiQueryKey, safeParseQueryKey} from 'sentry/utils/api/apiQueryKey'; import {ListItemCheckboxProvider} from 'sentry/utils/list/useListItemCheckboxState'; import {MIN_REPLAY_CLICK_SDK} from 'sentry/utils/replays/sdkVersions'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; @@ -60,9 +56,9 @@ export function ReplayIndexTable({ const {allMobileProj} = useAllMobileProj({}); const columns = useReplayIndexTableColumns({allMobileProj, tableDimensions}); - const {options} = parseQueryKey(queryKey); + const endpointOptions = safeParseQueryKey(queryKey)?.options; const needsSDKUpdateForClickSearch = useNeedsSDKUpdateForClickSearch({ - search: options?.query?.query as string | undefined, + search: endpointOptions?.query?.query as string | undefined, }); const needsJetpackComposePiiWarning = useNeedsJetpackComposePiiNotice({ @@ -86,7 +82,7 @@ export function ReplayIndexTable({ replay.id)} - queryKey={safeParseQueryKey(queryKey)?.options} + endpointOptions={endpointOptions} > {needsSDKUpdateForClickSearch ? ( diff --git a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx index e0eea652a4a43d..39ecb0a9874dea 100644 --- a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx +++ b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx @@ -275,7 +275,7 @@ export function SeerProjectTable() { project.id)} - queryKey={safeParseQueryKey(queryKey)?.options} + endpointOptions={safeParseQueryKey(queryKey)?.options} > diff --git a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx index 29511c077da659..70984a187f093e 100644 --- a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx +++ b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTableHeader.tsx @@ -113,12 +113,12 @@ export function ProjectTableHeader({ countSelected, isAllSelected, isAnySelected, - queryKeyRef, + endpointOptionsRef, selectAll, selectedIds, } = listItemCheckboxState; - const queryOptions = queryKeyRef.current; - const queryString = queryOptions?.query?.query as string | undefined; + const endpointOptions = endpointOptionsRef.current; + const queryString = endpointOptions?.query?.query as string | undefined; const projectIds = useMemo( () => (selectedIds === 'all' ? projects.map(project => project.id) : selectedIds), diff --git a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx index b3ed90184c23ca..29e2629b30ff40 100644 --- a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx +++ b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx @@ -201,7 +201,7 @@ export function SeerRepoTable() { { if (selectedIds === 'all') { From f1251a2a7de45f0324e38885f9541c9590a9a557 Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Thu, 7 May 2026 14:15:26 -0700 Subject: [PATCH 7/9] remove the `as unknown as ApiQueryKey` fake queryKey. kind of the whole point of this --- .../components/projectTable/seerProjectTable.tsx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx index 39ecb0a9874dea..3df0dc3d396806 100644 --- a/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx +++ b/static/gsApp/views/seerAutomation/components/projectTable/seerProjectTable.tsx @@ -33,9 +33,7 @@ import {IconSearch} from 'sentry/icons/iconSearch'; import {t, tct} from 'sentry/locale'; import {ProjectsStore} from 'sentry/stores/projectsStore'; import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; -import {safeParseQueryKey} from 'sentry/utils/api/apiQueryKey'; import {ListItemCheckboxProvider} from 'sentry/utils/list/useListItemCheckboxState'; -import type {ApiQueryKey} from 'sentry/utils/queryClient'; import {getCodingAgentSelectQueryOptions} from 'sentry/utils/seer/preferredAgent'; import { getFilteredCodingAgentName, @@ -167,12 +165,6 @@ export function SeerProjectTable() { parseAsSort.withDefault({field: 'project', kind: 'asc'}) ); - const queryKey = [ - 'seer-projects', - {query: {query: searchTerm, sort, agent: agentFilter}}, - {infinite: false}, - ] as unknown as ApiQueryKey; - const sortedProjects = useMemo(() => { return projects.toSorted((a, b) => { if (sort.field === 'project') { @@ -275,7 +267,9 @@ export function SeerProjectTable() { project.id)} - endpointOptions={safeParseQueryKey(queryKey)?.options} + endpointOptions={{ + query: {query: searchTerm, sort, agent: agentFilter}, + }} > From bb5883ef7140c7483fb73dd756bb7e9eb8ca2ee9 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 12 May 2026 18:00:48 +0000 Subject: [PATCH 8/9] fix list checkbox context test expectation Co-authored-by: Ryan Albrecht --- static/app/utils/list/useListItemCheckboxState.spec.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/app/utils/list/useListItemCheckboxState.spec.tsx b/static/app/utils/list/useListItemCheckboxState.spec.tsx index ecff32c27ee3bb..f94b1b74fd7c0f 100644 --- a/static/app/utils/list/useListItemCheckboxState.spec.tsx +++ b/static/app/utils/list/useListItemCheckboxState.spec.tsx @@ -36,7 +36,7 @@ describe('useListItemCheckboxContext', () => { isAnySelected: false, isSelected: expect.any(Function), knownIds: ['1', '2', '3'], - queryKeyRef: {current: endpointOptions}, + endpointOptionsRef: {current: endpointOptions}, selectAll: expect.any(Function), selectedIds: [], toggleSelected: expect.any(Function), @@ -179,7 +179,7 @@ describe('useListItemCheckboxContext', () => { isAnySelected: false, isSelected: expect.any(Function), knownIds: ['1', '2', '3'], - queryKeyRef: {current: endpointOptions}, + endpointOptionsRef: {current: endpointOptions}, selectAll: expect.any(Function), selectedIds: [], toggleSelected: expect.any(Function), From 782e427e915bb54b0f6d28508b7a9c1bc9c14f1f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 12 May 2026 18:08:53 +0000 Subject: [PATCH 9/9] fix replay table header checkbox state mock Co-authored-by: Ryan Albrecht --- static/app/components/replays/table/replayTableHeader.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/components/replays/table/replayTableHeader.spec.tsx b/static/app/components/replays/table/replayTableHeader.spec.tsx index c82ed934d1c8f4..8dfe977b22e38f 100644 --- a/static/app/components/replays/table/replayTableHeader.spec.tsx +++ b/static/app/components/replays/table/replayTableHeader.spec.tsx @@ -30,7 +30,7 @@ function baseListCheckboxState(overrides: Partial) { isAnySelected: false, isSelected: () => false, knownIds: ['a', 'b'], - queryKeyRef: {current: undefined}, + endpointOptionsRef: {current: undefined}, selectAll: jest.fn(), selectedIds: [], toggleSelected: jest.fn(),