diff --git a/static/app/components/events/autofix/preferences/hooks/useOrganizationRepositories.ts b/static/app/components/events/autofix/preferences/hooks/useOrganizationRepositories.ts deleted file mode 100644 index e5a2e8e492e3c2..00000000000000 --- a/static/app/components/events/autofix/preferences/hooks/useOrganizationRepositories.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {useCallback, useEffect, useMemo, useRef} from 'react'; - -import type {Repository} from 'sentry/types/integrations'; -import {getApiUrl} from 'sentry/utils/api/getApiUrl'; -import {useFetchSequentialPages} from 'sentry/utils/api/useFetchSequentialPages'; -import type {ApiQueryKey} from 'sentry/utils/queryClient'; -import {useOrganization} from 'sentry/utils/useOrganization'; - -interface Props { - query?: Record; -} - -/** - * @deprecated Use organizationRepositoriesInfiniteOptions instead. - */ -export function useOrganizationRepositories({query = {}} = {} as Props) { - const queryRef = useRef>(query); - useEffect(() => { - queryRef.current = query; - }, [query]); - - const organization = useOrganization(); - - const getQueryKey = useCallback( - ({cursor, per_page}: {cursor: string; per_page: number}): ApiQueryKey => [ - getApiUrl('/organizations/$organizationIdOrSlug/repos/', { - path: { - organizationIdOrSlug: organization.slug, - }, - }), - {query: {...queryRef.current, cursor, per_page}}, - ], - [organization.slug] - ); - - const {pages, isFetching, ...rest} = useFetchSequentialPages({ - getQueryKey, - perPage: 100, - enabled: true, - }); - - const data = useMemo(() => { - const flattenedRepos = pages.flat(); - const uniqueReposMap = new Map(); - flattenedRepos.forEach(repo => { - if (repo.externalId && !uniqueReposMap.has(repo.externalId)) { - uniqueReposMap.set(repo.externalId, repo); - } - }); - return Array.from(uniqueReposMap.values()); - }, [pages]); - - return useMemo( - () => ({ - ...rest, - data, - isFetching, - }), - [data, isFetching, rest] - ); -} diff --git a/static/app/views/settings/projectSeer/addAutofixRepoModal.tsx b/static/app/views/settings/projectSeer/addAutofixRepoModal.tsx index 2314f6fbe1adb1..3090adb57f12b0 100644 --- a/static/app/views/settings/projectSeer/addAutofixRepoModal.tsx +++ b/static/app/views/settings/projectSeer/addAutofixRepoModal.tsx @@ -1,5 +1,6 @@ import {Fragment, useCallback, useMemo, useRef, useState, type ChangeEvent} from 'react'; import styled from '@emotion/styled'; +import {useInfiniteQuery} from '@tanstack/react-query'; import {useVirtualizer} from '@tanstack/react-virtual'; import {Alert} from '@sentry/scraps/alert'; @@ -9,10 +10,11 @@ import {Flex, Stack} from '@sentry/scraps/layout'; import {Link} from '@sentry/scraps/link'; import type {ModalRenderProps} from 'sentry/actionCreators/modal'; -import {useOrganizationRepositories} from 'sentry/components/events/autofix/preferences/hooks/useOrganizationRepositories'; import {LoadingIndicator} from 'sentry/components/loadingIndicator'; import {IconSearch} from 'sentry/icons'; import {t, tct, tn} from 'sentry/locale'; +import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; +import {organizationRepositoriesInfiniteOptions} from 'sentry/utils/repositories/repoQueryOptions'; import {useOrganization} from 'sentry/utils/useOrganization'; import {MAX_REPOS_LIMIT} from 'sentry/views/settings/projectSeer/constants'; @@ -37,10 +39,14 @@ export function AddAutofixRepoModal({ Footer, closeModal, }: Props) { - const {data: repositories, isFetching: isFetchingRepositories} = - useOrganizationRepositories(); - const organization = useOrganization(); + const result = useInfiniteQuery({ + ...organizationRepositoriesInfiniteOptions({organization}), + select: ({pages}) => pages.flatMap(page => page.json), + }); + useFetchAllPages({result}); + const {data: repositories, isFetching: isFetchingRepositories} = result; + const [modalSearchQuery, setModalSearchQuery] = useState(''); const [showMaxLimitAlert, setShowMaxLimitAlert] = useState(false); const [modalSelectedRepoIds, setModalSelectedRepoIds] = diff --git a/static/app/views/settings/projectSeer/autofixRepositories.tsx b/static/app/views/settings/projectSeer/autofixRepositories.tsx index 13598f786ad67a..3b22299151430d 100644 --- a/static/app/views/settings/projectSeer/autofixRepositories.tsx +++ b/static/app/views/settings/projectSeer/autofixRepositories.tsx @@ -1,6 +1,7 @@ import {useCallback, useEffect, useMemo, useState} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; +import {useInfiniteQuery} from '@tanstack/react-query'; import {Alert} from '@sentry/scraps/alert'; import {Button} from '@sentry/scraps/button'; @@ -10,7 +11,6 @@ import {Tooltip} from '@sentry/scraps/tooltip'; import {openModal} from 'sentry/actionCreators/modal'; import {DropdownMenu} from 'sentry/components/dropdownMenu'; -import {useOrganizationRepositories} from 'sentry/components/events/autofix/preferences/hooks/useOrganizationRepositories'; import {useProjectSeerPreferences} from 'sentry/components/events/autofix/preferences/hooks/useProjectSeerPreferences'; import {useUpdateProjectSeerPreferences} from 'sentry/components/events/autofix/preferences/hooks/useUpdateProjectSeerPreferences'; import type { @@ -25,6 +25,8 @@ import {IconAdd} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; import {PluginIcon} from 'sentry/plugins/components/pluginIcon'; import type {Project} from 'sentry/types/project'; +import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; +import {organizationRepositoriesInfiniteOptions} from 'sentry/utils/repositories/repoQueryOptions'; import {useOrganization} from 'sentry/utils/useOrganization'; import {AddAutofixRepoModal} from './addAutofixRepoModal'; @@ -38,8 +40,12 @@ interface ProjectSeerProps { export function AutofixRepositories({project}: ProjectSeerProps) { const theme = useTheme(); const organization = useOrganization(); - const {data: repositories, isFetching: isFetchingRepositories} = - useOrganizationRepositories(); + const result = useInfiniteQuery({ + ...organizationRepositoriesInfiniteOptions({organization}), + select: ({pages}) => pages.flatMap(page => page.json), + }); + useFetchAllPages({result}); + const {data: repositories, isFetching: isFetchingRepositories} = result; const { preference, codeMappingRepos, diff --git a/static/gsApp/views/seerAutomation/components/projectDetails/autofixRepositoriesList.tsx b/static/gsApp/views/seerAutomation/components/projectDetails/autofixRepositoriesList.tsx index 213f8b381131a4..66028b2fcb7c46 100644 --- a/static/gsApp/views/seerAutomation/components/projectDetails/autofixRepositoriesList.tsx +++ b/static/gsApp/views/seerAutomation/components/projectDetails/autofixRepositoriesList.tsx @@ -1,5 +1,6 @@ import {useCallback, useMemo} from 'react'; import styled from '@emotion/styled'; +import {useInfiniteQuery} from '@tanstack/react-query'; import seerConfigBug1 from 'getsentry-images/spot/seer-config-bug-1.svg'; import {Button} from '@sentry/scraps/button'; @@ -9,7 +10,6 @@ import {Heading} from '@sentry/scraps/text'; import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator'; import {openModal} from 'sentry/actionCreators/modal'; -import {useOrganizationRepositories} from 'sentry/components/events/autofix/preferences/hooks/useOrganizationRepositories'; import {useUpdateProjectSeerPreferences} from 'sentry/components/events/autofix/preferences/hooks/useUpdateProjectSeerPreferences'; import type { ProjectSeerPreferences, @@ -22,6 +22,8 @@ import {IconAdd} from 'sentry/icons/iconAdd'; import {t, tct} from 'sentry/locale'; import type {Organization} from 'sentry/types/organization'; import type {Project} from 'sentry/types/project'; +import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; +import {organizationRepositoriesInfiniteOptions} from 'sentry/utils/repositories/repoQueryOptions'; import {useOrganization} from 'sentry/utils/useOrganization'; import {AddAutofixRepoModal} from 'sentry/views/settings/projectSeer/addAutofixRepoModal'; @@ -57,9 +59,12 @@ const getTableHeaders = (organization: Organization): React.ReactNode[] => [ export function AutofixRepositories({canWrite, preference, project}: Props) { const organization = useOrganization(); - - const {data: repositories, isFetching: isFetchingRepositories} = - useOrganizationRepositories(); + const result = useInfiniteQuery({ + ...organizationRepositoriesInfiniteOptions({organization}), + select: ({pages}) => pages.flatMap(page => page.json), + }); + useFetchAllPages({result}); + const {data: repositories, isFetching: isFetchingRepositories} = result; const {mutate: updateProjectSeerPreferences} = useUpdateProjectSeerPreferences(project); diff --git a/static/gsApp/views/seerAutomation/onboarding/onboardingLegacy.tsx b/static/gsApp/views/seerAutomation/onboarding/onboardingLegacy.tsx index 2e528aa18bf0af..dc89d615d0892d 100644 --- a/static/gsApp/views/seerAutomation/onboarding/onboardingLegacy.tsx +++ b/static/gsApp/views/seerAutomation/onboarding/onboardingLegacy.tsx @@ -15,7 +15,6 @@ import { import {openModal} from 'sentry/actionCreators/modal'; import {hasEveryAccess} from 'sentry/components/acl/access'; import {ClippedBox} from 'sentry/components/clippedBox'; -import {useOrganizationRepositories} from 'sentry/components/events/autofix/preferences/hooks/useOrganizationRepositories'; import {useProjectSeerPreferences} from 'sentry/components/events/autofix/preferences/hooks/useProjectSeerPreferences'; import {useUpdateProjectSeerPreferences} from 'sentry/components/events/autofix/preferences/hooks/useUpdateProjectSeerPreferences'; import type {SeerRepoDefinition} from 'sentry/components/events/autofix/types'; @@ -35,8 +34,10 @@ import {IconChevron, IconSearch} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; import type {Repository} from 'sentry/types/integrations'; import type {Project} from 'sentry/types/project'; +import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; import {makeDetailedProjectQueryKey} from 'sentry/utils/project/useDetailedProject'; -import {useQueryClient} from 'sentry/utils/queryClient'; +import {useInfiniteQuery, useQueryClient} from 'sentry/utils/queryClient'; +import {organizationRepositoriesInfiniteOptions} from 'sentry/utils/repositories/repoQueryOptions'; import {useApi} from 'sentry/utils/useApi'; import {useNavigate} from 'sentry/utils/useNavigate'; import {useOrganization} from 'sentry/utils/useOrganization'; @@ -202,8 +203,13 @@ function ProjectsWithoutRepos({ onProjectSuccess: (projectId: string) => void; projects: Project[]; }) { - const {data: repositories, isFetching: isFetchingRepositories} = - useOrganizationRepositories(); + const organization = useOrganization(); + const result = useInfiniteQuery({ + ...organizationRepositoriesInfiniteOptions({organization}), + select: ({pages}) => pages.flatMap(page => page.json), + }); + useFetchAllPages({result}); + const {data: repositories, isFetching: isFetchingRepositories} = result; const [projectStates, setProjectStates] = useState({}); const [successfullyConnectedProjects, setSuccessfullyConnectedProjects] = useState(