Skip to content

Commit ccf9ea6

Browse files
authored
chore: Migrate useSelfHostedSeatsAndLicense to TS Query V5 (#3577)
1 parent ab1389b commit ccf9ea6

File tree

5 files changed

+92
-67
lines changed

5 files changed

+92
-67
lines changed

src/services/selfHosted/useSelfHostedSeatsAndLicense.test.tsx renamed to src/services/selfHosted/SelfHostedSeatsAndLicenseQueryOpts.test.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
1+
import {
2+
QueryClientProvider as QueryClientProviderV5,
3+
QueryClient as QueryClientV5,
4+
useQuery as useQueryV5,
5+
} from '@tanstack/react-queryV5'
26
import { renderHook, waitFor } from '@testing-library/react'
37
import { graphql, HttpResponse } from 'msw'
48
import { setupServer } from 'msw/node'
59
import { type MockInstance } from 'vitest'
610

7-
import { useSelfHostedSeatsAndLicense } from './useSelfHostedSeatsAndLicense'
11+
import { SelfHostedSeatsAndLicenseQueryOpts } from './SelfHostedSeatsAndLicenseQueryOpts'
812

913
const mockSelfHostedLicense = {
1014
config: {
@@ -16,12 +20,14 @@ const mockSelfHostedLicense = {
1620

1721
const mockUnsuccessfulParseError = {}
1822

19-
const queryClient = new QueryClient({
23+
const queryClientV5 = new QueryClientV5({
2024
defaultOptions: { queries: { retry: false } },
2125
})
2226

2327
const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
24-
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
28+
<QueryClientProviderV5 client={queryClientV5}>
29+
{children}
30+
</QueryClientProviderV5>
2531
)
2632

2733
const server = setupServer()
@@ -30,7 +36,7 @@ beforeAll(() => {
3036
})
3137

3238
afterEach(() => {
33-
queryClient.clear()
39+
queryClientV5.clear()
3440
server.resetHandlers()
3541
})
3642

@@ -61,7 +67,10 @@ describe('useSelfHostedSeatsAndLicense', () => {
6167
it('returns the license details', async () => {
6268
setup({})
6369
const { result } = renderHook(
64-
() => useSelfHostedSeatsAndLicense({ provider: 'gh' }),
70+
() =>
71+
useQueryV5(
72+
SelfHostedSeatsAndLicenseQueryOpts({ provider: 'gh' })
73+
),
6574
{ wrapper }
6675
)
6776

@@ -91,7 +100,8 @@ describe('useSelfHostedSeatsAndLicense', () => {
91100
it('throws a 404', async () => {
92101
setup({ isUnsuccessfulParseError: true })
93102
const { result } = renderHook(
94-
() => useSelfHostedSeatsAndLicense({ provider: 'gh' }),
103+
() =>
104+
useQueryV5(SelfHostedSeatsAndLicenseQueryOpts({ provider: 'gh' })),
95105
{ wrapper }
96106
)
97107

Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useQuery } from '@tanstack/react-query'
1+
import { queryOptions as queryOptionsV5 } from '@tanstack/react-queryV5'
22
import { z } from 'zod'
33

44
import Api from 'shared/api'
5+
import { rejectNetworkError } from 'shared/api/helpers'
56

67
export const SelfHostedSeatsAndLicenseSchema = z
78
.object({
@@ -19,32 +20,24 @@ export const SelfHostedSeatsAndLicenseSchema = z
1920
})
2021
.nullable()
2122

22-
export interface UseSelfHostedSeatsAndLicenseArgs {
23-
provider: string
24-
opts?: {
25-
enabled: boolean
26-
}
27-
}
28-
29-
const query = `
30-
query SelfHostedSeatsAndLicense {
31-
config {
32-
seatsUsed
33-
seatsLimit
34-
selfHostedLicense {
35-
expirationDate
36-
}
23+
const query = `query SelfHostedSeatsAndLicense {
24+
config {
25+
seatsUsed
26+
seatsLimit
27+
selfHostedLicense {
28+
expirationDate
3729
}
3830
}
39-
`
31+
}`
32+
33+
export interface SelfHostedSeatsAndLicenseQueryArgs {
34+
provider: string
35+
}
4036

41-
export const useSelfHostedSeatsAndLicense = ({
37+
export const SelfHostedSeatsAndLicenseQueryOpts = ({
4238
provider,
43-
opts = {
44-
enabled: true,
45-
},
46-
}: UseSelfHostedSeatsAndLicenseArgs) =>
47-
useQuery({
39+
}: SelfHostedSeatsAndLicenseQueryArgs) =>
40+
queryOptionsV5({
4841
queryKey: ['SelfHostedSeatsAndLicense', provider, query],
4942
queryFn: ({ signal }) =>
5043
Api.graphql({
@@ -55,13 +48,14 @@ export const useSelfHostedSeatsAndLicense = ({
5548
const parsedRes = SelfHostedSeatsAndLicenseSchema.safeParse(res?.data)
5649

5750
if (!parsedRes.success) {
58-
return Promise.reject({
51+
return rejectNetworkError({
5952
status: 404,
60-
data: null,
53+
data: {},
54+
dev: `SelfHostedSeatsAndLicenseQueryOpts - 404 Failed to parse`,
55+
error: parsedRes.error,
6156
})
6257
}
6358

6459
return parsedRes.data?.config ?? null
6560
}),
66-
...(!!opts && opts),
6761
})

src/services/selfHosted/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
export * from './useSelfHostedCurrentUser'
2-
export * from './useSelfHostedSeatsAndLicense'

src/shared/GlobalBanners/SelfHostedLicenseExpiration/SelfHostedLicenseExpiration.test.tsx

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2+
import {
3+
QueryClientProvider as QueryClientProviderV5,
4+
QueryClient as QueryClientV5,
5+
} from '@tanstack/react-queryV5'
26
import { render, screen, waitFor } from '@testing-library/react'
37
import userEvent from '@testing-library/user-event'
48
import { graphql, HttpResponse } from 'msw'
@@ -15,45 +19,54 @@ vi.mock('config')
1519
const queryClient = new QueryClient({
1620
defaultOptions: { queries: { retry: false, suspense: true } },
1721
})
18-
const server = setupServer()
1922

23+
const queryClientV5 = new QueryClientV5({
24+
defaultOptions: { queries: { retry: false } },
25+
})
26+
27+
const wrapper =
28+
(initialEntries = ['/gh/test-org']): React.FC<React.PropsWithChildren> =>
29+
({ children }) => (
30+
<QueryClientProviderV5 client={queryClientV5}>
31+
<QueryClientProvider client={queryClient}>
32+
<MemoryRouter initialEntries={initialEntries}>
33+
<Suspense fallback={<p>Loading</p>}>
34+
<Route path="/:provider/:owner">{children}</Route>
35+
</Suspense>
36+
</MemoryRouter>
37+
</QueryClientProvider>
38+
</QueryClientProviderV5>
39+
)
40+
41+
const server = setupServer()
2042
beforeAll(() => {
2143
server.listen()
2244
})
2345

2446
afterEach(() => {
2547
queryClient.clear()
48+
queryClientV5.clear()
2649
server.resetHandlers()
2750
})
2851

2952
afterAll(() => {
3053
server.close()
3154
})
3255

33-
const wrapper =
34-
(initialEntries = ['/gh/test-org']) =>
35-
({ children }: { children: React.ReactNode }) => (
36-
<QueryClientProvider client={queryClient}>
37-
<MemoryRouter initialEntries={initialEntries}>
38-
<Suspense fallback={<p>Loading</p>}>
39-
<Route path="/:provider/:owner">{children}</Route>
40-
</Suspense>
41-
</MemoryRouter>
42-
</QueryClientProvider>
43-
)
56+
interface SetupArgs {
57+
isUndefined?: boolean
58+
seatsLimit?: number | null
59+
seatsUsed?: number | null
60+
expirationDate?: string | null
61+
}
4462

4563
describe('SelfHostedLicenseExpiration', () => {
4664
function setup({
4765
isUndefined = false,
4866
seatsLimit = 50,
4967
seatsUsed = 10,
5068
expirationDate = '2020-05-09T00:00:00',
51-
}: {
52-
isUndefined?: boolean
53-
seatsLimit?: number | null
54-
seatsUsed?: number | null
55-
expirationDate?: string | null
56-
}) {
69+
}: SetupArgs) {
5770
const user = userEvent.setup({ delay: null })
5871

5972
server.use(

src/shared/GlobalBanners/SelfHostedLicenseExpiration/SelfHostedLicenseExpiration.tsx

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { useSuspenseQuery as useSuspenseQueryV5 } from '@tanstack/react-queryV5'
12
import { differenceInCalendarDays } from 'date-fns'
23
import { useState } from 'react'
34
import { useParams } from 'react-router-dom'
45

56
import config from 'config'
67

7-
import { useSelfHostedSeatsAndLicense } from 'services/selfHosted/useSelfHostedSeatsAndLicense'
8+
import { SelfHostedSeatsAndLicenseQueryOpts } from 'services/selfHosted/SelfHostedSeatsAndLicenseQueryOpts'
89
import { Provider } from 'shared/api/helpers'
910
import Banner from 'ui/Banner'
1011
import Button from 'ui/Button'
@@ -56,31 +57,25 @@ interface URLParams {
5657
const SelfHostedLicenseExpiration = () => {
5758
const { provider } = useParams<URLParams>()
5859
const [isModalOpen, setIsModalOpen] = useState(false)
59-
const isSelfHosted = !!config.IS_SELF_HOSTED
60-
const isDedicatedNamespace = !!config.IS_DEDICATED_NAMESPACE
61-
const { data } = useSelfHostedSeatsAndLicense({
62-
provider,
63-
opts: { enabled: !!provider && isSelfHosted && isDedicatedNamespace },
64-
})
60+
const { data } = useSuspenseQueryV5(
61+
SelfHostedSeatsAndLicenseQueryOpts({
62+
provider,
63+
})
64+
)
6565

6666
const licenseExpirationDate = data?.selfHostedLicense?.expirationDate
6767
const seatsUsed = data?.seatsUsed
6868
const seatsLimit = data?.seatsLimit
6969

70-
if (
71-
!isSelfHosted ||
72-
!isDedicatedNamespace ||
73-
!licenseExpirationDate ||
74-
!seatsUsed ||
75-
!seatsLimit
76-
) {
70+
if (!licenseExpirationDate || !seatsUsed || !seatsLimit) {
7771
return null
7872
}
7973

8074
const dateDiff = differenceInCalendarDays(
8175
new Date(licenseExpirationDate),
8276
new Date()
8377
)
78+
8479
const isSeatsLimitReached = seatsUsed === seatsLimit
8580
const isLicenseExpired = dateDiff < 0
8681
const isLicenseExpiringWithin30Days = dateDiff < 31 && dateDiff >= 0
@@ -122,4 +117,18 @@ const SelfHostedLicenseExpiration = () => {
122117
)
123118
}
124119

125-
export default SelfHostedLicenseExpiration
120+
// This wrapper is just so we don't make a request to the API if we're not on a
121+
// self-hosted instance, this is because we're useSuspenseQuery is not
122+
// toggle'ble through a `enabled` field like useQuery
123+
function SelfHostedLicenseExpirationWrapper() {
124+
const isSelfHosted = !!config.IS_SELF_HOSTED
125+
const isDedicatedNamespace = !!config.IS_DEDICATED_NAMESPACE
126+
127+
if (!isSelfHosted || !isDedicatedNamespace) {
128+
return null
129+
}
130+
131+
return <SelfHostedLicenseExpiration />
132+
}
133+
134+
export default SelfHostedLicenseExpirationWrapper

0 commit comments

Comments
 (0)