diff --git a/src/pages/AdminSettings/AdminMembers/MemberList/MemberTable.tsx b/src/pages/AdminSettings/AdminMembers/MemberList/MemberTable.tsx
index 78219968ba..4d903f1ca6 100644
--- a/src/pages/AdminSettings/AdminMembers/MemberList/MemberTable.tsx
+++ b/src/pages/AdminSettings/AdminMembers/MemberList/MemberTable.tsx
@@ -4,9 +4,9 @@ import {
useQueryClient,
} from '@tanstack/react-query'
import {
- useSuspenseQuery as useSuspenseQueryV5,
useInfiniteQuery as useInfiniteQueryV5,
useQueryClient as useQueryClientV5,
+ useSuspenseQuery as useSuspenseQueryV5,
} from '@tanstack/react-queryV5'
import {
createColumnHelper,
diff --git a/src/pages/AnalyticsPage/AnalyticsPage.jsx b/src/pages/AnalyticsPage/AnalyticsPage.jsx
index def8f61a06..bd4118e6b4 100644
--- a/src/pages/AnalyticsPage/AnalyticsPage.jsx
+++ b/src/pages/AnalyticsPage/AnalyticsPage.jsx
@@ -2,7 +2,7 @@ import { useParams } from 'react-router-dom'
import NotFound from 'pages/NotFound'
import { useLocationParams } from 'services/navigation'
-import { orderingOptions } from 'services/repos'
+import { orderingOptions } from 'services/repos/orderingOptions'
import { useOwner } from 'services/user'
import ReposTable from 'shared/ListRepo/ReposTable'
diff --git a/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.jsx b/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.jsx
index 1deefe59d5..dd17c6a5bc 100644
--- a/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.jsx
+++ b/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.jsx
@@ -1,8 +1,9 @@
+import { useInfiniteQuery as useInfiniteQueryV5 } from '@tanstack/react-queryV5'
import PropTypes from 'prop-types'
import { useMemo, useRef, useState } from 'react'
import { useParams } from 'react-router-dom'
-import { useRepos } from 'services/repos'
+import { ReposQueryOpts } from 'services/repos/ReposQueryOpts'
import { TierNames, useTier } from 'services/tier'
import A from 'ui/A'
import DateRangePicker from 'ui/DateRangePicker'
@@ -60,16 +61,17 @@ function RepoSelector({
isLoading,
fetchNextPage,
hasNextPage,
- } = useRepos({
- provider,
- owner,
- sortItem,
- activated: active,
- term: search,
- first: Infinity,
- suspense: false,
- isPublic: shouldDisplayPublicReposOnly,
- })
+ } = useInfiniteQueryV5(
+ ReposQueryOpts({
+ provider,
+ owner,
+ sortItem,
+ activated: active,
+ term: search,
+ first: Infinity,
+ isPublic: shouldDisplayPublicReposOnly,
+ })
+ )
const reposSelectData = useMemo(() => {
const data = reposData?.pages?.map((page) => page?.repos).flat()
diff --git a/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.test.jsx b/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.test.jsx
index 05d9f8c78e..560a6d807b 100644
--- a/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.test.jsx
+++ b/src/pages/AnalyticsPage/ChartSelectors/ChartSelectors.test.jsx
@@ -1,7 +1,10 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import {
+ QueryClientProvider as QueryClientProviderV5,
+ QueryClient as QueryClientV5,
+} from '@tanstack/react-queryV5'
import { act, render, screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import { subDays } from 'date-fns'
import { graphql, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { Suspense } from 'react'
@@ -25,7 +28,6 @@ global.ResizeObserver = ResizeObserverMock
const mocks = vi.hoisted(() => ({
useIntersection: vi.fn(),
- useRepos: vi.fn(),
}))
vi.mock('react-use', async () => {
@@ -36,46 +38,71 @@ vi.mock('react-use', async () => {
}
})
-vi.mock('services/repos', async () => {
- const actual = await vi.importActual('services/repos')
- return {
- ...actual,
- useRepos: mocks.useRepos,
- }
-})
-
const repositories = [
{
+ name: 'Repo name 1',
+ active: true,
+ activated: true,
+ coverageAnalytics: {
+ lines: 99,
+ percentCovered: null,
+ },
private: false,
+ updatedAt: '2021-04-22T14:09:39.822872+00:00',
author: {
username: 'owner1',
},
- name: 'Repo name 1',
- latestCommitAt: subDays(new Date(), 3),
- coverage: 43,
- activated: true,
+ repositoryConfig: {
+ indicationRange: {
+ upperRange: 80,
+ lowerRange: 60,
+ },
+ },
+ latestCommitAt: null,
+ coverageEnabled: true,
+ bundleAnalysisEnabled: true,
},
{
+ name: 'Repo name 3',
+ active: false,
+ activated: true,
+ coverageAnalytics: {
+ lines: 99,
+ percentCovered: null,
+ },
private: false,
+ updatedAt: '2021-04-22T14:09:39.826948+00:00',
author: {
username: 'owner2',
},
- name: 'Repo name 3',
- latestCommitAt: subDays(new Date(), 4),
- coverage: 35,
- activated: false,
+ repositoryConfig: {
+ indicationRange: {
+ upperRange: 80,
+ lowerRange: 60,
+ },
+ },
+ latestCommitAt: null,
+ coverageEnabled: true,
+ bundleAnalysisEnabled: true,
},
]
-const queryClient = new QueryClient()
+const queryClient = new QueryClient({
+ defaultOptions: { queries: { retry: false } },
+})
+const queryClientV5 = new QueryClientV5({
+ defaultOptions: { queries: { retry: false } },
+})
const wrapper = ({ children }) => (
-
-
-
- Suspense
}>{children}
-
-
-
+
+
+
+
+ Suspense}>{children}
+
+
+
+
)
const server = setupServer()
@@ -86,6 +113,7 @@ beforeAll(() => {
afterEach(() => {
queryClient.clear()
+ queryClientV5.clear()
server.resetHandlers()
})
@@ -102,34 +130,42 @@ describe('ChartSelectors', () => {
function setup({ hasNextPage = false, tierValue = TierNames.PRO }) {
// https://github.com/testing-library/user-event/issues/1034
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime })
-
const fetchNextPage = vi.fn()
-
- mocks.useRepos.mockReturnValue({
- data: {
- pages: [
- {
- repos: repositories,
- pageInfo: {
- hasNextPage: true,
- endCursor: 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=',
- },
- },
- ],
- },
- fetchNextPage,
- hasNextPage,
- })
+ const searchTerm = vi.fn()
server.use(
graphql.query('OwnerTier', () => {
return HttpResponse.json({
data: { owner: { plan: { tierName: tierValue } } },
})
+ }),
+ graphql.query('ReposForOwner', ({ variables }) => {
+ if (variables?.filters?.term) {
+ searchTerm(variables.filters.term)
+ }
+
+ if (variables?.after) {
+ fetchNextPage()
+ }
+
+ return HttpResponse.json({
+ data: {
+ owner: {
+ username: 'owner',
+ repositories: {
+ edges: [{ node: repositories[0] }, { node: repositories[1] }],
+ pageInfo: {
+ hasNextPage,
+ endCursor: 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=',
+ },
+ },
+ },
+ },
+ })
})
)
- return { fetchNextPage, user }
+ return { fetchNextPage, user, searchTerm }
}
describe('renders component', () => {
@@ -148,7 +184,7 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const datePicker = screen.getByText('Pick a date')
+ const datePicker = await screen.findByText('Pick a date')
expect(datePicker).toBeInTheDocument()
})
@@ -208,13 +244,13 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- let datePicker = screen.getByText('Pick a date')
+ let datePicker = await screen.findByText('Pick a date')
await act(async () => {
await user.click(datePicker)
})
- const gridCells = screen.getAllByRole('gridcell', { name: '31' })
- const date = within(gridCells[0]).getByText('31')
+ const gridCells = await screen.findAllByRole('gridcell', { name: '31' })
+ const date = await within(gridCells[0]).findByText('31')
await act(async () => {
await user.click(date)
})
@@ -252,13 +288,13 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- let datePicker = screen.getByText('Mar 31, 2022 - Mar 31, 2022')
+ let datePicker = await screen.findByText('Mar 31, 2022 - Mar 31, 2022')
await act(async () => {
await user.click(datePicker)
})
- let gridCells = screen.getAllByRole('gridcell', { name: '31' })
- let date = within(gridCells[0]).getByText('31')
+ let gridCells = await screen.findAllByRole('gridcell', { name: '31' })
+ let date = await within(gridCells[0]).findByText('31')
await act(async () => {
await user.click(date)
})
@@ -282,13 +318,13 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const multiselect = screen.getByText('All Repos')
+ const multiselect = await screen.findByText('All Repos')
await user.click(multiselect)
- const repo1 = screen.getByText('Repo name 1')
+ const repo1 = await screen.findByText('Repo name 1')
expect(repo1).toBeInTheDocument()
- const repo3 = screen.getByText('Repo name 3')
+ const repo3 = await screen.findByText('Repo name 3')
expect(repo3).toBeInTheDocument()
})
@@ -308,13 +344,13 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const multiselect = screen.getByText('1 Repo selected')
+ const multiselect = await screen.findByText('1 Repo selected')
await user.click(multiselect)
- const repo1 = screen.getByText('Repo name 3')
+ const repo1 = await screen.findByText('Repo name 3')
await user.click(repo1)
- const multiSelectUpdated = screen.getByText('2 Repos selected')
+ const multiSelectUpdated = await screen.findByText('2 Repos selected')
expect(multiSelectUpdated).toBeInTheDocument()
})
@@ -334,10 +370,10 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const multiselect = screen.getByText('All Repos')
+ const multiselect = await screen.findByText('All Repos')
await user.click(multiselect)
- const repo1 = screen.getByText('Repo name 1')
+ const repo1 = await screen.findByText('Repo name 1')
await user.click(repo1)
await waitFor(() =>
@@ -364,15 +400,15 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const multiselect = screen.getByText('All Repos')
+ const multiselect = await screen.findByText('All Repos')
await user.click(multiselect)
- const searchBox = screen.getByPlaceholderText('Search for Repos')
+ const searchBox = await screen.findByPlaceholderText('Search for Repos')
expect(searchBox).toBeInTheDocument()
})
it('updates the textbox value when typing', async () => {
- const { user } = setup({})
+ const { user, searchTerm } = setup({})
render(
{
{ wrapper }
)
- const multiselect = screen.getByText('All Repos')
+ const multiselect = await screen.findByText('All Repos')
await user.click(multiselect)
- const searchBox = screen.getByPlaceholderText('Search for Repos')
+ const searchBox = await screen.findByPlaceholderText('Search for Repos')
await user.type(searchBox, 'codecov')
- const searchBoxUpdated = screen.getByPlaceholderText('Search for Repos')
+ const searchBoxUpdated =
+ await screen.findByPlaceholderText('Search for Repos')
expect(searchBoxUpdated).toHaveAttribute('value', 'codecov')
await waitFor(() => {
- expect(mocks.useRepos).toHaveBeenCalledWith({
- activated: true,
- first: Infinity,
- owner: 'codecov',
- provider: 'gh',
- sortItem: {
- direction: 'ASC',
- ordering: 'NAME',
- },
- suspense: false,
- term: 'codecov',
- isPublic: null,
- })
+ expect(searchTerm).toHaveBeenCalledWith('codecov')
})
})
})
@@ -434,7 +459,7 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const multiselect = screen.getByText('All Repos')
+ const multiselect = await screen.findByText('All Repos')
await user.click(multiselect)
await waitFor(() => expect(fetchNextPage).toHaveBeenCalled())
@@ -458,7 +483,7 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const multiselect = screen.getByText('All Repos')
+ const multiselect = await screen.findByText('All Repos')
await user.click(multiselect)
expect(fetchNextPage).not.toHaveBeenCalled()
@@ -484,7 +509,7 @@ describe('ChartSelectors', () => {
{ wrapper }
)
- const clearFilters = screen.getByRole('button', {
+ const clearFilters = await screen.findByRole('button', {
name: 'Clear filters',
})
await user.click(clearFilters)
@@ -521,21 +546,6 @@ describe('ChartSelectors', () => {
const upgradeLink = await screen.findByRole('link', { name: 'Upgrade' })
expect(upgradeLink).toBeInTheDocument()
expect(upgradeLink).toHaveAttribute('href', '/plan/gh/codecov/upgrade')
- await waitFor(() => {
- expect(mocks.useRepos).toHaveBeenCalledWith({
- activated: true,
- first: Infinity,
- owner: 'codecov',
- provider: 'gh',
- sortItem: {
- direction: 'ASC',
- ordering: 'NAME',
- },
- suspense: false,
- term: '',
- isPublic: true,
- })
- })
})
})
})
diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.tsx
index 1c4d5b5828..88d03cf807 100644
--- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.tsx
+++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.tsx
@@ -8,7 +8,7 @@ import cs from 'classnames'
import { useEffect } from 'react'
import { useInView } from 'react-intersection-observer'
-import { OrderingDirection } from 'services/repos'
+import { OrderingDirection } from 'services/repos/orderingOptions'
import { useTableDefaultSort } from 'shared/ContentsTable/useTableDefaultSort'
import { Row } from 'shared/ContentsTable/utils'
import Icon from 'ui/Icon'
diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.tsx
index 1d4b26ac61..b40d3b9394 100644
--- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.tsx
+++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.tsx
@@ -8,7 +8,7 @@ import cs from 'classnames'
import { useEffect } from 'react'
import { useInView } from 'react-intersection-observer'
-import { OrderingDirection } from 'services/repos'
+import { OrderingDirection } from 'services/repos/orderingOptions'
import { useTableDefaultSort } from 'shared/ContentsTable/useTableDefaultSort'
import { Row } from 'shared/ContentsTable/utils'
import Icon from 'ui/Icon'
diff --git a/src/services/repos/useRepos.test.tsx b/src/services/repos/ReposQueryOpts.test.tsx
similarity index 80%
rename from src/services/repos/useRepos.test.tsx
rename to src/services/repos/ReposQueryOpts.test.tsx
index 9ff02393eb..0ec7a126c7 100644
--- a/src/services/repos/useRepos.test.tsx
+++ b/src/services/repos/ReposQueryOpts.test.tsx
@@ -1,23 +1,27 @@
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import {
+ QueryClientProvider as QueryClientProviderV5,
+ QueryClient as QueryClientV5,
+ useInfiniteQuery as useInfiniteQueryV5,
+} from '@tanstack/react-queryV5'
import { renderHook, waitFor } from '@testing-library/react'
import { graphql, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { MemoryRouter, Route } from 'react-router-dom'
import { MockInstance } from 'vitest'
-import { useRepos } from './useRepos'
+import { ReposQueryOpts } from './ReposQueryOpts'
-const queryClient = new QueryClient({
+const queryClientV5 = new QueryClientV5({
defaultOptions: { queries: { retry: false } },
})
const wrapper =
(initialEntries = '/gh'): React.FC =>
({ children }) => (
-
+
{children}
-
+
)
const repo1 = {
@@ -74,7 +78,7 @@ beforeAll(() => {
})
afterEach(() => {
- queryClient.clear()
+ queryClientV5.clear()
server.resetHandlers()
})
@@ -82,7 +86,7 @@ afterAll(() => {
server.close()
})
-describe('useRepos', () => {
+describe('ReposQueryOpts', () => {
function setup({ invalidResponse = false } = {}) {
server.use(
graphql.query('ReposForOwner', (info) => {
@@ -95,16 +99,8 @@ describe('useRepos', () => {
username: 'codecov',
repositories: {
edges: info.variables.after
- ? [
- {
- node: repo2,
- },
- ]
- : [
- {
- node: repo1,
- },
- ],
+ ? [{ node: repo2 }]
+ : [{ node: repo1 }],
pageInfo: {
hasNextPage: info.variables.after ? false : true,
endCursor: info.variables.after
@@ -123,10 +119,9 @@ describe('useRepos', () => {
it('returns repositories of the owner', async () => {
setup()
const { result } = renderHook(
- () => useRepos({ provider: '', owner: 'codecov' }),
- {
- wrapper: wrapper(),
- }
+ () =>
+ useInfiniteQueryV5(ReposQueryOpts({ provider: '', owner: 'codecov' })),
+ { wrapper: wrapper() }
)
await waitFor(() => {
@@ -146,10 +141,8 @@ describe('useRepos', () => {
it('returns next set of repositories', async () => {
setup()
const { result } = renderHook(
- () => useRepos({ provider: '', owner: '' }),
- {
- wrapper: wrapper(),
- }
+ () => useInfiniteQueryV5(ReposQueryOpts({ provider: '', owner: '' })),
+ { wrapper: wrapper() }
)
await waitFor(() => result.current.isFetching)
@@ -190,13 +183,17 @@ describe('useRepos', () => {
it('throws an error', async () => {
setup({ invalidResponse: true })
const { result } = renderHook(
- () => useRepos({ provider: '', owner: 'owner1' }),
+ () =>
+ useInfiniteQueryV5(ReposQueryOpts({ provider: '', owner: 'owner1' })),
{ wrapper: wrapper() }
)
await waitFor(() =>
expect(result.current.error).toEqual(
- expect.objectContaining({ status: 404 })
+ expect.objectContaining({
+ status: 404,
+ dev: 'ReposQueryOpts - 404 Failed to parse schema',
+ })
)
)
})
diff --git a/src/services/repos/useRepos.tsx b/src/services/repos/ReposQueryOpts.tsx
similarity index 74%
rename from src/services/repos/useRepos.tsx
rename to src/services/repos/ReposQueryOpts.tsx
index 73ac854710..0523e6cb86 100644
--- a/src/services/repos/useRepos.tsx
+++ b/src/services/repos/ReposQueryOpts.tsx
@@ -1,11 +1,17 @@
-import { useInfiniteQuery } from '@tanstack/react-query'
+import { infiniteQueryOptions as infiniteQueryOptionsV5 } from '@tanstack/react-queryV5'
import { z } from 'zod'
import { RepositoryConfigSchema } from 'services/repo/useRepoConfig'
import Api from 'shared/api'
+import { rejectNetworkError } from 'shared/api/helpers'
import { mapEdges } from 'shared/utils/graphql'
-import { orderingOptions } from './orderingOptions'
+import {
+ nonActiveOrderingOptions,
+ OrderingDirection,
+ orderingOptions,
+ TeamOrdering,
+} from './orderingOptions'
const RepositorySchema = z
.object({
@@ -30,7 +36,7 @@ const RepositorySchema = z
})
.nullable()
-export type RepositoryResult = z.infer
+type RepositoryResult = z.infer
const RequestSchema = z.object({
owner: z
@@ -101,7 +107,7 @@ const query = `query ReposForOwner(
}
}`
-interface UseReposArgs {
+interface ReposQueryArgs {
provider: string
owner: string
activated?: boolean
@@ -115,7 +121,7 @@ interface UseReposArgs {
isPublic?: true | false | null
}
-export function useRepos({
+function ReposQueryOpts({
provider,
owner,
activated,
@@ -124,8 +130,7 @@ export function useRepos({
first = 20,
repoNames,
isPublic = null, // by default, get both public and private repos
- ...options
-}: UseReposArgs) {
+}: ReposQueryArgs) {
const variables = {
filters: { activated, term, repoNames, isPublic },
ordering: sortItem?.ordering,
@@ -133,7 +138,7 @@ export function useRepos({
first,
}
- return useInfiniteQuery({
+ return infiniteQueryOptionsV5({
queryKey: ['repos', provider, owner, variables],
queryFn: ({ pageParam, signal }) => {
return Api.graphql({
@@ -143,27 +148,37 @@ export function useRepos({
variables: {
...variables,
owner,
- after: pageParam,
+ after: pageParam === '' ? undefined : pageParam,
},
}).then((res) => {
const parsedRes = RequestSchema.safeParse(res?.data)
if (!parsedRes.success) {
- return Promise.reject({
+ return rejectNetworkError({
status: 404,
- data: null,
+ data: {},
+ dev: 'ReposQueryOpts - 404 Failed to parse schema',
+ error: parsedRes.error,
})
}
- const owner = parsedRes?.data?.owner
return {
- repos: mapEdges(owner?.repositories),
- pageInfo: owner?.repositories?.pageInfo,
+ repos: mapEdges(parsedRes?.data?.owner?.repositories),
+ pageInfo: parsedRes?.data?.owner?.repositories?.pageInfo,
}
})
},
- suspense: false,
- getNextPageParam: (data) =>
- data?.pageInfo?.hasNextPage ? data.pageInfo.endCursor : undefined,
- ...options,
+ initialPageParam: '',
+ getNextPageParam: (data) => {
+ return data?.pageInfo?.hasNextPage ? data.pageInfo.endCursor : null
+ },
})
}
+
+export {
+ type RepositoryResult,
+ ReposQueryOpts,
+ orderingOptions,
+ OrderingDirection,
+ TeamOrdering,
+ nonActiveOrderingOptions,
+}
diff --git a/src/services/repos/ReposTeamQueryOpts.test.tsx b/src/services/repos/ReposTeamQueryOpts.test.tsx
index 7fc2e9711a..a3346823c0 100644
--- a/src/services/repos/ReposTeamQueryOpts.test.tsx
+++ b/src/services/repos/ReposTeamQueryOpts.test.tsx
@@ -100,7 +100,7 @@ afterAll(() => {
server.close()
})
-describe('useReposTeam', () => {
+describe('ReposTeamQueryOpts', () => {
function setup({ invalidResponse = false } = {}) {
server.use(
graphql.query('GetReposTeam', (info) => {
@@ -156,7 +156,7 @@ describe('useReposTeam', () => {
},
},
],
- pageParams: [undefined],
+ pageParams: [''],
})
)
})
@@ -200,7 +200,7 @@ describe('useReposTeam', () => {
pageInfo: { hasNextPage: false, endCursor: 'aa' },
},
],
- pageParams: [undefined, 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA='],
+ pageParams: ['', 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA='],
})
)
})
diff --git a/src/services/repos/ReposTeamQueryOpts.tsx b/src/services/repos/ReposTeamQueryOpts.tsx
index fba98fdc2e..5c0697d0b0 100644
--- a/src/services/repos/ReposTeamQueryOpts.tsx
+++ b/src/services/repos/ReposTeamQueryOpts.tsx
@@ -136,7 +136,7 @@ function ReposTeamQueryOpts({
variables: {
...variables,
owner,
- after: pageParam,
+ after: pageParam === '' ? undefined : pageParam,
},
}).then((res) => {
const parsedRes = RequestSchema.safeParse(res?.data)
@@ -159,7 +159,7 @@ function ReposTeamQueryOpts({
}
})
},
- initialPageParam: undefined as string | undefined,
+ initialPageParam: '',
getNextPageParam: (data) => {
if (data?.pageInfo?.hasNextPage) {
return data.pageInfo.endCursor
diff --git a/src/services/repos/index.ts b/src/services/repos/index.ts
deleted file mode 100644
index ae1f8c951b..0000000000
--- a/src/services/repos/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './useRepos'
-export * from './orderingOptions'
diff --git a/src/shared/ListRepo/ListRepo.jsx b/src/shared/ListRepo/ListRepo.jsx
index 3c33e5e4f6..0fe9dddccd 100644
--- a/src/shared/ListRepo/ListRepo.jsx
+++ b/src/shared/ListRepo/ListRepo.jsx
@@ -4,7 +4,7 @@ import { Suspense, useContext } from 'react'
import { useParams } from 'react-router-dom'
import { useLocationParams } from 'services/navigation'
-import { orderingOptions } from 'services/repos'
+import { orderingOptions } from 'services/repos/orderingOptions'
import { TierNames, useTier } from 'services/tier'
import { useUser } from 'services/user'
import { ActiveContext } from 'shared/context'
diff --git a/src/shared/ListRepo/OrgControlTable/OrgControlTable.test.jsx b/src/shared/ListRepo/OrgControlTable/OrgControlTable.test.jsx
index a613b06d20..fed7066106 100644
--- a/src/shared/ListRepo/OrgControlTable/OrgControlTable.test.jsx
+++ b/src/shared/ListRepo/OrgControlTable/OrgControlTable.test.jsx
@@ -1,7 +1,7 @@
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import { orderingOptions } from 'services/repos'
+import { orderingOptions } from 'services/repos/orderingOptions'
import OrgControlTable from './OrgControlTable'
diff --git a/src/shared/ListRepo/ReposTable/ReposTable.test.tsx b/src/shared/ListRepo/ReposTable/ReposTable.test.tsx
index 0df200bfcc..8da3d49564 100644
--- a/src/shared/ListRepo/ReposTable/ReposTable.test.tsx
+++ b/src/shared/ListRepo/ReposTable/ReposTable.test.tsx
@@ -1,4 +1,8 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import {
+ QueryClientProvider as QueryClientProviderV5,
+ QueryClient as QueryClientV5,
+} from '@tanstack/react-queryV5'
import {
render,
screen,
@@ -19,10 +23,6 @@ import ReposTable from './ReposTable'
import { repoDisplayOptions } from '../ListRepo'
-const queryClient = new QueryClient({
- defaultOptions: { queries: { retry: false } },
-})
-const server = setupServer()
const mockRepositories = (
{
coverageEnabled = true,
@@ -151,16 +151,12 @@ const mockUser = {
},
}
-beforeAll(() => {
- server.listen()
- console.error = () => {}
+const queryClient = new QueryClient({
+ defaultOptions: { queries: { retry: false } },
})
-afterEach(() => {
- queryClient.clear()
- server.resetHandlers()
+const queryClientV5 = new QueryClientV5({
+ defaultOptions: { queries: { retry: false } },
})
-afterAll(() => server.close)
-
const wrapper =
(
repoDisplay: string,
@@ -168,17 +164,31 @@ const wrapper =
path: string = '/:provider'
): React.FC =>
({ children }) => (
-
-
-
-
- {children}
-
-
-
-
+
+
+
+
+
+ {children}
+
+
+
+
+
)
+const server = setupServer()
+beforeAll(() => {
+ server.listen()
+ console.error = () => {}
+})
+afterEach(() => {
+ queryClient.clear()
+ queryClientV5.clear()
+ server.resetHandlers()
+})
+afterAll(() => server.close)
+
interface SetupArgs {
edges?: any[]
isCurrentUserPartOfOrg?: boolean
diff --git a/src/shared/ListRepo/ReposTable/ReposTable.tsx b/src/shared/ListRepo/ReposTable/ReposTable.tsx
index 4a3ba962fa..d0ca39b46d 100644
--- a/src/shared/ListRepo/ReposTable/ReposTable.tsx
+++ b/src/shared/ListRepo/ReposTable/ReposTable.tsx
@@ -1,3 +1,4 @@
+import { useInfiniteQuery as useInfiniteQueryV5 } from '@tanstack/react-queryV5'
import {
flexRender,
getCoreRowModel,
@@ -13,7 +14,10 @@ import { useParams } from 'react-router-dom'
import config from 'config'
-import { OrderingDirection, useRepos } from 'services/repos'
+import {
+ OrderingDirection,
+ ReposQueryOpts,
+} from 'services/repos/ReposQueryOpts'
import { TierNames, useTier } from 'services/tier'
import { useOwner, useUser } from 'services/user'
import { ActiveContext } from 'shared/context'
@@ -134,23 +138,27 @@ const ReposTable = ({
hasNextPage,
isLoading: isReposLoading,
isFetchingNextPage,
- } = useRepos({
- provider,
- owner,
- activated,
- sortItem: getOrderingDirection(sorting),
- term: searchValue,
- repoNames: filterValues,
- isPublic: shouldDisplayPublicReposOnly,
- })
+ } = useInfiniteQueryV5(
+ ReposQueryOpts({
+ provider,
+ owner,
+ activated,
+ sortItem: getOrderingDirection(sorting),
+ term: searchValue,
+ repoNames: filterValues,
+ isPublic: shouldDisplayPublicReposOnly,
+ })
+ )
// fetch demo repo(s)
- const { data: demoReposData } = useRepos({
- provider: DEMO_REPO.provider,
- owner: DEMO_REPO.owner,
- activated,
- repoNames: [DEMO_REPO.repo],
- })
+ const { data: demoReposData } = useInfiniteQueryV5(
+ ReposQueryOpts({
+ provider: DEMO_REPO.provider,
+ owner: DEMO_REPO.owner,
+ activated,
+ repoNames: [DEMO_REPO.repo],
+ })
+ )
const isMyOwnerPage = currentUser?.user?.username === owner
diff --git a/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx b/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx
index e52b691da0..fa247d41f7 100644
--- a/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx
+++ b/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx
@@ -1,6 +1,6 @@
import { createColumnHelper } from '@tanstack/react-table'
-import { RepositoryResult } from 'services/repos'
+import { RepositoryResult } from 'services/repos/ReposQueryOpts'
import { formatTimeToNow } from 'shared/utils/dates'
import TotalsNumber from 'ui/TotalsNumber'
diff --git a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.tsx b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.tsx
index 4d78b98db9..7fdbf23fa6 100644
--- a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.tsx
+++ b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.tsx
@@ -10,7 +10,7 @@ import { graphql, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { MemoryRouter, Route } from 'react-router-dom'
-import { OrderingDirection, TeamOrdering } from 'services/repos'
+import { OrderingDirection, TeamOrdering } from 'services/repos/orderingOptions'
import { ActiveContext } from 'shared/context'
import ReposTableTeam, { getSortingOption } from './ReposTableTeam'
diff --git a/src/shared/utils/demo.ts b/src/shared/utils/demo.ts
index d933cb90c9..4f5a1b9e9f 100644
--- a/src/shared/utils/demo.ts
+++ b/src/shared/utils/demo.ts
@@ -1,4 +1,6 @@
-import { useRepos } from 'services/repos'
+import { ReposQueryOpts } from 'services/repos/ReposQueryOpts'
+
+import { ExtractInfiniteQueryDataType } from './queries'
export const DEMO_REPO = {
provider: 'github',
@@ -7,31 +9,33 @@ export const DEMO_REPO = {
displayName: 'Codecov demo',
}
-type UseReposData = ReturnType['data']
+type ReposQueryData = ExtractInfiniteQueryDataType
export function formatDemoRepos(
- demoReposData: UseReposData,
+ demoReposData: ReposQueryData | undefined,
searchValue: string
) {
- return (
- demoReposData?.pages
- .flatMap((page) => page.repos)
- .filter(isNotNull)
- .map(
- // tag the repo as demo and overwrite its display name
- (repo) => ({
- ...repo,
- isDemo: true,
- name: DEMO_REPO.displayName,
- })
- )
- .filter(
- // filter if name does not match the search value
- (repo: { name: string }) =>
- !searchValue ||
- repo.name.toLowerCase().includes(searchValue.toLowerCase())
- ) ?? []
- )
+ if (!demoReposData) {
+ return []
+ }
+
+ return demoReposData?.pages
+ .flatMap((page) => page.repos)
+ .filter(isNotNull)
+ .map(
+ // tag the repo as demo and overwrite its display name
+ (repo) => ({
+ ...repo,
+ isDemo: true,
+ name: DEMO_REPO.displayName,
+ })
+ )
+ .filter(
+ // filter if name does not match the search value
+ (repo: { name: string }) =>
+ !searchValue ||
+ repo.name.toLowerCase().includes(searchValue.toLowerCase())
+ )
}
// isNotNull can be used in filter to exclude null elements while conveying to
diff --git a/src/shared/utils/queries.ts b/src/shared/utils/queries.ts
new file mode 100644
index 0000000000..87e8648de5
--- /dev/null
+++ b/src/shared/utils/queries.ts
@@ -0,0 +1,50 @@
+import {
+ InfiniteData,
+ UseInfiniteQueryOptions,
+ UseQueryOptions,
+} from '@tanstack/react-queryV5'
+
+type AnyFunction = (...args: any) => any
+
+type KnownInfiniteQueryFnReturn<
+ T extends (...args: any) => UseInfiniteQueryOptions,
+> = NonNullable['queryFn']>
+
+/**
+ * Extracts the infinite query data from a query function - **Only works for TanStack Query V5**.
+ *
+ * @param T - The query function to extract the infinite query data from.
+ * @returns The type of infinite query data.
+ *
+ * @example
+ * ```ts
+ * import { InfiniteQueryOpts } from './InfiniteQueryOpts'
+ *
+ * type ReturnData = ExtractInfiniteQueryDataType
+ * ```
+ */
+export type ExtractInfiniteQueryDataType = InfiniteData<
+ Awaited>>
+>
+
+// -----------------------------------------------------------------------------
+
+type KnownQueryFnReturn UseQueryOptions> =
+ NonNullable['queryFn']>
+
+/**
+ * Extracts the query data from a query function - **Only works for TanStack Query V5**.
+ *
+ * @param T - The query function to extract the query data from.
+ * @returns The type of the query data.
+ *
+ * @example
+ * ```ts
+ * import { QueryOpts } from './QueryOpts'
+ *
+ * type ReturnData = ExtractQueryDataType
+ * ```
+ */
+export type ExtractQueryDataType = Awaited<
+ ReturnType>
+>