From b612f3ec86e856d8c0077d102f859b3c044d60e2 Mon Sep 17 00:00:00 2001 From: tibs245 Date: Mon, 9 Feb 2026 21:06:45 +0100 Subject: [PATCH 1/2] refactor(backup-agent): add custom query client possibility ref: #BKP-849 Signed-off-by: Thibault Barske --- .../src/test-utils/testWrapperBuilder.tsx | 10 +++++++--- .../src/test-utils/testWrapperProviders.tsx | 12 +++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/manager/modules/backup-agent/src/test-utils/testWrapperBuilder.tsx b/packages/manager/modules/backup-agent/src/test-utils/testWrapperBuilder.tsx index 162e26163622..66aa02bb9394 100644 --- a/packages/manager/modules/backup-agent/src/test-utils/testWrapperBuilder.tsx +++ b/packages/manager/modules/backup-agent/src/test-utils/testWrapperBuilder.tsx @@ -1,5 +1,7 @@ import React from 'react'; +import { QueryClient } from '@tanstack/react-query'; + import { BackupAgentProviderProps } from '@/BackupAgent.context'; import { @@ -14,13 +16,14 @@ import { type BuilderConfig = { withI18next: boolean; withQueryClient: boolean; + withCustomQueryClient?: QueryClient; withShellContext: boolean; withAppContext: boolean; appContext?: BackupAgentProviderProps; }; type TestWrapperBuilder = { withI18next: () => TestWrapperBuilder; - withQueryClient: () => TestWrapperBuilder; + withQueryClient: (queryClient?: QueryClient) => TestWrapperBuilder; withShellContext: () => TestWrapperBuilder; withAppContext: (customAppContext?: BackupAgentProviderProps) => TestWrapperBuilder; build: () => Promise>; @@ -35,7 +38,7 @@ export const testWrapperBuilder = (): TestWrapperBuilder => { const build = async (): Promise> => { const providers: TestProvider[] = []; if (config.withI18next) await addI18nextProvider(providers); - if (config.withQueryClient) addQueryClientProvider(providers); + if (config.withQueryClient) addQueryClientProvider(providers, config.withCustomQueryClient); if (config.withShellContext) await addShellContextProvider(providers); if (config.withAppContext) addAppContextProvider(providers, config.appContext); return createProviderWrapper(providers); @@ -45,8 +48,9 @@ export const testWrapperBuilder = (): TestWrapperBuilder => { config.withI18next = true; return builder; }, - withQueryClient: () => { + withQueryClient: (queryClient?: QueryClient) => { config.withQueryClient = true; + config.withCustomQueryClient = queryClient; return builder; }, withShellContext: () => { diff --git a/packages/manager/modules/backup-agent/src/test-utils/testWrapperProviders.tsx b/packages/manager/modules/backup-agent/src/test-utils/testWrapperProviders.tsx index 32e1fa840692..bc03bd63488a 100644 --- a/packages/manager/modules/backup-agent/src/test-utils/testWrapperProviders.tsx +++ b/packages/manager/modules/backup-agent/src/test-utils/testWrapperProviders.tsx @@ -32,10 +32,16 @@ export const addI18nextProvider = async (providers: TestProvider[]) => { } providers.push(({ children }) => {children}); }; -export const addQueryClientProvider = (providers: TestProvider[]) => { - const queryClient = new QueryClient({ - defaultOptions: { queries: { retry: false }, mutations: { retry: false } }, +export const createQueryClientTest = () => + new QueryClient({ + defaultOptions: { queries: { retry: false, staleTime: Infinity }, mutations: { retry: false } }, }); + +export const addQueryClientProvider = ( + providers: TestProvider[], + customQueryClient?: QueryClient, +) => { + const queryClient = customQueryClient ?? createQueryClientTest(); providers.push(({ children }) => ( {children} )); From 3ff7f91b662c22ecc03387a79091d6a42660681a Mon Sep 17 00:00:00 2001 From: tibs245 Date: Mon, 9 Feb 2026 22:43:37 +0100 Subject: [PATCH 2/2] refactor(backup-agent): refator use queries ref: #BKP-849 Signed-off-by: Thibault Barske --- .../src/pages/first-order/FirstOrder.page.tsx | 7 +- .../FirstOrderConfirmationModal.page.tsx | 9 +- .../src/pages/onboarding/Onboarding.page.tsx | 15 +-- .../src/pages/onboarding/Onboarding.spec.tsx | 45 +++++---- .../manager/modules/backup-agent/package.json | 28 +++--- .../ResourceLocationCell.component.tsx | 8 +- .../ResourceLocationCell.component.test.tsx | 59 ++++++------ .../ResourceRegionCell.component.tsx | 8 +- .../ResourceRegionCell.component.test.tsx | 59 ++++++------ .../GeneralInformationTile.component.tsx | 11 ++- .../__tests__/GeneralInformationTile.test.tsx | 37 +++++--- .../src/data/api/agents/agents.requests.ts | 10 +- .../data/api/baremetal/baremetals.requests.ts | 12 ++- .../src/data/api/billing/vaultConsumption.ts | 1 - .../src/data/hooks/agents/getAgentDetails.ts | 46 --------- .../src/data/hooks/agents/getAgents.ts | 30 ------ .../data/hooks/agents/getDownloadLinkAgent.ts | 39 -------- .../src/data/hooks/agents/postAgent.ts | 50 ---------- .../src/data/hooks/agents/putAgent.ts | 50 ---------- .../src/data/hooks/agents/useDeleteAgent.ts | 42 --------- .../agoraService/useAgoraServiceIdOptions.ts | 19 ---- .../data/hooks/backup/useBackupServicesId.ts | 26 ----- .../hooks/baremetal/useBaremetalDetails.ts | 29 ------ .../data/hooks/baremetal/useBaremetalsList.ts | 21 ----- .../consumption/useServiceConsumption.ts | 21 ----- .../data/hooks/location/getLocationDetails.ts | 15 --- .../hooks/tenants/useBackupTenantDetails.ts | 34 ------- .../data/hooks/tenants/useBackupTenants.ts | 15 --- .../src/data/hooks/tenants/useDeleteTenant.ts | 35 ------- .../tenants/useVspcTenantBackupPolicies.ts | 26 ----- .../hooks/tenants/useVspcTenantDetails.ts | 32 ------- .../src/data/hooks/tenants/useVspcTenantId.ts | 23 ----- .../src/data/hooks/tenants/useVspcTenants.ts | 35 ------- .../useAddConfigurationVSPCTenantAgent.ts | 39 ++++++++ .../src/data/hooks/useDeleteTenantAgent.ts | 41 ++++++++ .../src/data/hooks/useDeleteVSPCTenant.ts | 30 ++++++ .../src/data/hooks/useDeleteVault.ts | 26 +++++ .../useEditConfigurationVSPCTenantAgent.ts | 39 ++++++++ .../src/data/hooks/vaults/getVault.ts | 21 ----- .../src/data/hooks/vaults/getVaultDetails.ts | 39 -------- .../src/data/hooks/vaults/useDeleteVault.ts | 29 ------ .../src/data/queries/agents.queries.ts | 58 ++++++++++++ .../src/data/queries/baremetals.queries.ts | 24 +++++ .../src/data/queries/consumption.queries.ts | 28 ++++++ .../src/data/queries/locations.queries.ts | 18 ++++ .../src/data/queries/queryKeys.ts | 35 +++++++ .../src/data/queries/services.queries.ts | 38 ++++++++ .../src/data/queries/tenants.queries.ts | 76 +++++++++++++++ .../src/data/queries/vaults.queries.ts | 36 +++++++ .../__tests__/consumption.selectors.test.ts | 37 ++++++++ .../__tests__/vaults.selectors.test.ts | 27 ++++++ .../data/selectors/consumption.selectors.ts | 8 ++ .../src/data/selectors/vaults.selectors.ts | 8 ++ .../src/pages/MainLayout.component.tsx | 7 +- .../pages/billing/listing/Listing.page.tsx | 10 +- .../BillingPriceCell.components.tsx | 7 +- .../BillingUsageCell.components.tsx | 7 +- .../BillingPriceCell.component.test.tsx | 50 +++++----- .../BillingUsageCell.component.test.tsx | 63 ++++++------- .../dashboard/agent/AgentsListing.page.tsx | 16 ++-- .../AgentDataLocationCell.component.tsx | 17 +++- .../AgentDataLocationCell.component.test.tsx | 71 +++++++------- .../AddConfiguration.page.tsx | 32 +++++-- .../__tests__/AddConfiguration.test.tsx | 94 +++++++------------ .../agent/delete/DeleteAgent.page.tsx | 8 +- .../agent/download/AgentDownload.page.tsx | 18 +++- .../download/__tests__/AgentDownload.test.tsx | 62 ++++-------- .../EditConfiguration.page.tsx | 18 ++-- .../__tests__/EditConfiguration.test.tsx | 94 +++++++++---------- .../dashboard/delete/DeleteTenant.page.tsx | 9 +- .../GeneralInformation.page.tsx | 7 +- .../GeneralInformationTenantTile.test.tsx | 36 ++++--- ...GeneralInformationTenantTile.component.tsx | 8 +- .../SubscriptionTile.component.tsx | 6 +- .../_hooks/useTenantBackupStats.ts | 13 ++- .../vaults/dashboard/VaultDashboard.page.tsx | 12 ++- .../dashboard/buckets/VaultBuckets.page.tsx | 23 ++--- .../GeneralInformation.page.tsx | 7 +- .../GeneralInformationVaultTile.test.tsx | 61 ++++++------ .../__tests__/SubscriptionTile.test.tsx | 42 +++------ .../GeneralInformationVaultTile.component.tsx | 16 +++- .../SubscriptionTile.component.tsx | 8 +- .../_components/BillingType.component.tsx | 15 +-- .../ConsumptionDetails.component.tsx | 15 +-- .../__tests__/BillingType.test.tsx | 31 +++--- .../__tests__/ConsumptionDetails.test.tsx | 31 ++---- .../pages/vaults/delete/DeleteVault.page.tsx | 8 +- .../src/pages/vaults/listing/Listing.page.tsx | 6 +- 88 files changed, 1213 insertions(+), 1269 deletions(-) delete mode 100644 packages/manager/modules/backup-agent/src/data/api/billing/vaultConsumption.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/agents/getAgentDetails.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/agents/getAgents.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/agents/getDownloadLinkAgent.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/agents/postAgent.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/agents/putAgent.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/agents/useDeleteAgent.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/agoraService/useAgoraServiceIdOptions.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/backup/useBackupServicesId.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalDetails.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalsList.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/consumption/useServiceConsumption.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/location/getLocationDetails.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenantDetails.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenants.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/tenants/useDeleteTenant.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantBackupPolicies.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantDetails.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantId.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenants.ts create mode 100644 packages/manager/modules/backup-agent/src/data/hooks/useAddConfigurationVSPCTenantAgent.ts create mode 100644 packages/manager/modules/backup-agent/src/data/hooks/useDeleteTenantAgent.ts create mode 100644 packages/manager/modules/backup-agent/src/data/hooks/useDeleteVSPCTenant.ts create mode 100644 packages/manager/modules/backup-agent/src/data/hooks/useDeleteVault.ts create mode 100644 packages/manager/modules/backup-agent/src/data/hooks/useEditConfigurationVSPCTenantAgent.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/vaults/getVault.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/vaults/getVaultDetails.ts delete mode 100644 packages/manager/modules/backup-agent/src/data/hooks/vaults/useDeleteVault.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/agents.queries.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/baremetals.queries.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/consumption.queries.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/locations.queries.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/queryKeys.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/services.queries.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/tenants.queries.ts create mode 100644 packages/manager/modules/backup-agent/src/data/queries/vaults.queries.ts create mode 100644 packages/manager/modules/backup-agent/src/data/selectors/__tests__/consumption.selectors.test.ts create mode 100644 packages/manager/modules/backup-agent/src/data/selectors/__tests__/vaults.selectors.test.ts create mode 100644 packages/manager/modules/backup-agent/src/data/selectors/consumption.selectors.ts create mode 100644 packages/manager/modules/backup-agent/src/data/selectors/vaults.selectors.ts diff --git a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/FirstOrder.page.tsx b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/FirstOrder.page.tsx index e5dcefb4dcf5..d156e6f75003 100644 --- a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/FirstOrder.page.tsx +++ b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/FirstOrder.page.tsx @@ -1,6 +1,7 @@ import { Outlet, useNavigate } from 'react-router-dom'; import { zodResolver } from '@hookform/resolvers/zod'; +import { useQuery } from '@tanstack/react-query'; import { Controller, SubmitHandler, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { z } from 'zod'; @@ -8,7 +9,7 @@ import { z } from 'zod'; import { OdsButton, OdsCombobox, OdsFormField } from '@ovhcloud/ods-components/react'; import { BaremetalOption } from '@ovh-ux/backup-agent/components/CommonFields/BaremetalOption/BaremetalOption.component'; -import { useBaremetalsList } from '@ovh-ux/backup-agent/data/hooks/baremetal/useBaremetalsList'; +import { baremetalsQueries } from '@ovh-ux/backup-agent/data/queries/baremetals.queries'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; import { OnboardingDescription } from '@/components/onboarding/onboardingDescription/OnboardingDescription.component'; @@ -32,7 +33,7 @@ export default function FirstOrderPage() { const { productName, title } = useOnboardingContent(); const img = useOnboardingHeroImage(); - const { flattenData, isLoading } = useBaremetalsList(); + const { data: baremetals, isPending: isLoading } = useQuery(baremetalsQueries.all()); const navigate = useNavigate(); const { @@ -84,7 +85,7 @@ export default function FirstOrderPage() { onOdsBlur={field.onBlur} onOdsChange={field.onChange} > - {flattenData?.map(({ name, ip, iam: { displayName } }) => ( + {baremetals?.map(({ name, ip, iam: { displayName } }) => ( ))} diff --git a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/confirmation/FirstOrderConfirmationModal.page.tsx b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/confirmation/FirstOrderConfirmationModal.page.tsx index 98ad3b1269f5..d2286edc3449 100644 --- a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/confirmation/FirstOrderConfirmationModal.page.tsx +++ b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/first-order/confirmation/FirstOrderConfirmationModal.page.tsx @@ -2,11 +2,12 @@ import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; +import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsButton, OdsMessage, OdsModal, OdsSpinner } from '@ovhcloud/ods-components/react'; -import { useBaremetalDetails } from '@ovh-ux/backup-agent/data/hooks/baremetal/useBaremetalDetails'; +import { baremetalsQueries } from '@ovh-ux/backup-agent/data/queries/baremetals.queries'; import { useRequiredParams } from '@ovh-ux/backup-agent/hooks/useRequiredParams'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; @@ -27,9 +28,9 @@ const FirstOrderConfirmationModal = () => { const { baremetalName } = useRequiredParams('baremetalName'); // Disable refetch to avoid creating multiple carts - const { data: baremetal, isPending: isBaremetalPending } = useBaremetalDetails({ - serviceName: baremetalName, - }); + const { data: baremetal, isPending: isBaremetalPending } = useQuery( + baremetalsQueries.detail(baremetalName), + ); const { mutate: createCart, diff --git a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.page.tsx b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.page.tsx index f14268281516..fa41e0d24ece 100644 --- a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.page.tsx +++ b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.page.tsx @@ -2,13 +2,13 @@ import { useMemo } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { Trans, useTranslation } from 'react-i18next'; import { OdsMessage } from '@ovhcloud/ods-components/react'; -import { useBaremetalsList } from '@ovh-ux/backup-agent/data/hooks/baremetal/useBaremetalsList'; -import { useBackupVaultsListOptions } from '@ovh-ux/backup-agent/data/hooks/vaults/getVault'; +import { baremetalsQueries } from '@ovh-ux/backup-agent/data/queries/baremetals.queries'; +import { vaultsQueries } from '@ovh-ux/backup-agent/data/queries/vaults.queries'; import { useGuideUtils } from '@ovh-ux/backup-agent/hooks/useGuideUtils.ts'; import { urls as backupAgentUrls } from '@ovh-ux/backup-agent/routes/routes.constants'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; @@ -26,7 +26,8 @@ export default function OnboardingPage() { const { t } = useTranslation(['onboarding', NAMESPACES.ACTIONS, NAMESPACES.ONBOARDING]); const { productName, title, tiles } = useOnboardingContent(); const links = useGuideUtils(); - const { flattenData, isPending } = useBaremetalsList({ pageSize: 1 }); + const queryClient = useQueryClient(); + const { data: baremetals, isPending } = useQuery(baremetalsQueries.all()); const isOrderSuccess = searchParams.get('orderSuccess') === 'true'; const { data: isBackupAgentReady, @@ -34,7 +35,7 @@ export default function OnboardingPage() { isSuccess: isVaultSuccess, isError: isVaultError, } = useQuery({ - ...useBackupVaultsListOptions(), + ...vaultsQueries.withClient(queryClient).list(), retry: false, select: (vaults) => vaults.filter(({ currentState: { status } }) => status === 'READY').length >= 1, @@ -92,8 +93,8 @@ export default function OnboardingPage() { isOrderLoading={isPending} orderHref={urls.firstOrder} moreInfoHref={links.website} - isOrderDisabled={!flattenData?.length || !isVaultError || isVaultPending || isOrderSuccess} - tooltipContent={!flattenData?.length ? t('no_baremetal_available') : undefined} + isOrderDisabled={!baremetals?.length || !isVaultError || isVaultPending || isOrderSuccess} + tooltipContent={!baremetals?.length ? t('no_baremetal_available') : undefined} > {validTiles.map(({ id, key, linkKey }) => { const href = links[linkKey]; diff --git a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.spec.tsx b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.spec.tsx index 5ad74cbe39c9..694a18d0b49f 100644 --- a/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.spec.tsx +++ b/packages/manager/apps/bmc-backup-agent-baremetal/src/pages/onboarding/Onboarding.spec.tsx @@ -30,15 +30,13 @@ vi.mock('react-i18next', () => ({ }), })); -const { useBaremetalsListMock, useQueryMock } = vi.hoisted(() => ({ - useBaremetalsListMock: vi - .fn() - .mockReturnValue({ data: undefined, isPending: true, isError: false }), +const { useQueryMock } = vi.hoisted(() => ({ useQueryMock: vi.fn().mockReturnValue({ data: undefined, isPending: false, isError: false }), })); vi.mock('@tanstack/react-query', () => ({ useQuery: useQueryMock, + useQueryClient: vi.fn(), })); vi.mock('@ovh-ux/manager-react-shell-client', async () => ({ @@ -46,17 +44,13 @@ vi.mock('@ovh-ux/manager-react-shell-client', async () => ({ useNavigationGetUrl: vi.fn().mockReturnValue({ isPending: false, data: '' }), })); -vi.mock('@ovh-ux/backup-agent/data/hooks/baremetal/useBaremetalsList', () => { - return { - useBaremetalsList: useBaremetalsListMock, - }; -}); +vi.mock('@ovh-ux/backup-agent/data/queries/baremetals.queries', () => ({ + baremetalsQueries: { all: vi.fn() }, +})); -vi.mock('@ovh-ux/backup-agent/data/hooks/vaults/getVault', () => { - return { - useBackupVaultsListOptions: vi.fn(), - }; -}); +vi.mock('@ovh-ux/backup-agent/data/queries/vaults.queries', () => ({ + vaultsQueries: { withClient: vi.fn().mockReturnValue({ list: vi.fn() }) }, +})); // --- Mock manager-react-components --- interface OnboardingLayoutProps { @@ -136,6 +130,7 @@ vi.mock('@ovh-ux/backup-agent/hooks/useGuideUtils.ts', () => ({ describe('FirstOrderPage', () => { beforeAll(() => { + // useQuery is called twice: 1st for baremetals, 2nd for vaults useQueryMock.mockReturnValue({ data: mockVaults, isPending: false, @@ -171,16 +166,18 @@ describe('FirstOrderPage', () => { ])( 'renders onboarding and expected disabled if no baremetal : $expectedDisabled', async (mock, expectedDisabled) => { - useBaremetalsListMock.mockReturnValue({ - flattenData: mock, - isPending: false, - isError: false, - }); - useQueryMock.mockReturnValue({ - flattenData: undefined, - isPending: false, - isError: true, - }); + // useQuery is called twice: 1st for baremetals, 2nd for vaults + useQueryMock + .mockReturnValueOnce({ + data: mock, + isPending: false, + isError: false, + }) + .mockReturnValueOnce({ + data: undefined, + isPending: false, + isError: true, + }); render(); diff --git a/packages/manager/modules/backup-agent/package.json b/packages/manager/modules/backup-agent/package.json index 48badbd8b2eb..f847f751d4e6 100644 --- a/packages/manager/modules/backup-agent/package.json +++ b/packages/manager/modules/backup-agent/package.json @@ -21,20 +21,20 @@ "import": "./dist/src/routes/routes.constants", "require": "./dist/src/routes/routes.constants.js" }, - "./data/hooks/baremetal/useBaremetalsList": { - "types": "./dist/types/src/data/hooks/baremetal/useBaremetalsList.d.ts", - "import": "./dist/src/data/hooks/baremetal/useBaremetalsList", - "require": "./dist/src/data/hooks/baremetal/useBaremetalsList.js" - }, - "./data/hooks/baremetal/useBaremetalDetails": { - "types": "./dist/types/src/data/hooks/baremetal/useBaremetalDetails.d.ts", - "import": "./dist/src/data/hooks/baremetal/useBaremetalDetails", - "require": "./dist/src/data/hooks/baremetal/useBaremetalDetails.js" - }, - "./data/hooks/vaults/getVault": { - "types": "./dist/types/src/data/hooks/vaults/getVault.d.ts", - "import": "./dist/src/data/hooks/vaults/getVault", - "require": "./dist/src/data/hooks/vaults/getVault.js" + "./data/queries/baremetals.queries": { + "types": "./dist/types/src/data/queries/baremetals.queries.d.ts", + "import": "./dist/src/data/queries/baremetals.queries", + "require": "./dist/src/data/queries/baremetals.queries.js" + }, + "./data/queries/vaults.queries": { + "types": "./dist/types/src/data/queries/vaults.queries.d.ts", + "import": "./dist/src/data/queries/vaults.queries", + "require": "./dist/src/data/queries/vaults.queries.js" + }, + "./data/queries/queryKeys": { + "types": "./dist/types/src/data/queries/queryKeys.d.ts", + "import": "./dist/src/data/queries/queryKeys", + "require": "./dist/src/data/queries/queryKeys.js" }, "./mocks/baremetals/baremetals.mocks": { "types": "./dist/types/src/mocks/baremetals/baremetals.mocks.d.ts", diff --git a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/ResourceLocationCell.component.tsx b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/ResourceLocationCell.component.tsx index ea0e349b2082..5e953033a582 100644 --- a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/ResourceLocationCell.component.tsx +++ b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/ResourceLocationCell.component.tsx @@ -1,19 +1,21 @@ import React from 'react'; +import { useQuery } from '@tanstack/react-query'; + import { OdsSkeleton } from '@ovhcloud/ods-components/react'; import { DataGridTextCell } from '@ovh-ux/manager-react-components'; -import { useLocationDetails } from '@/data/hooks/location/getLocationDetails'; +import { locationsQueries } from '@/data/queries/locations.queries'; export type ResourceLocationCellProps = { region: string; }; export const ResourceLocationCell = ({ region }: ResourceLocationCellProps) => { - const { data, isLoading, isError } = useLocationDetails(region); + const { data, isPending, isError } = useQuery(locationsQueries.detail(region)); - if (isLoading) return ; + if (isPending) return ; if (isError) return {region}; return {data?.location}; diff --git a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/__tests__/ResourceLocationCell.component.test.tsx b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/__tests__/ResourceLocationCell.component.test.tsx index 919b30374cd6..4488cc742b15 100644 --- a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/__tests__/ResourceLocationCell.component.test.tsx +++ b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceLocationCell/__tests__/ResourceLocationCell.component.test.tsx @@ -1,64 +1,69 @@ import React from 'react'; +import { QueryClient } from '@tanstack/react-query'; import { render, screen, waitFor } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockLocations } from '@/mocks/location/locations'; import { mockVaults } from '@/mocks/vaults/vaults.mock'; import { DataGridTextCellMock } from '@/test-utils/mocks/manager-react-components'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { ResourceLocationCell } from '../ResourceLocationCell.component'; -const { mockLocationDetails } = vi.hoisted(() => { - return { - mockLocationDetails: vi.fn(), - }; -}); - -vi.mock('@/data/hooks/location/getLocationDetails', () => ({ - useLocationDetails: mockLocationDetails, -})); - vi.mock('@ovh-ux/manager-react-components', () => ({ DataGridTextCell: DataGridTextCellMock, })); describe('ResourceLocationCell', () => { + let queryClient: QueryClient; + const vault = mockVaults[0]!; + const region = vault.currentState.region; + + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + + beforeEach(() => { + queryClient = createQueryClientTest(); + }); + it('renders resourceName from currentState', async () => { - mockLocationDetails.mockReturnValue({ - data: mockLocations[0], - isLoading: false, - isError: false, - }); - const vault = { ...mockVaults[0]! }; + queryClient.setQueryData(queryKeys.locations.detail(region), mockLocations[0]); + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); await waitFor(() => expect(screen.getByTestId('cell')).toHaveTextContent(mockLocations[0]!.location), ); - expect(mockLocationDetails).toHaveBeenCalledWith(mockVaults[0]!.currentState.region); }); it('renders during loading', async () => { - mockLocationDetails.mockReturnValue({ data: null, isLoading: true, isError: false }); - const vault = mockVaults[0]!; + // Don't seed the cache so the query stays in loading state - const { container } = render(); + const wrapper = await buildWrapper(); + + const { container } = render(, { wrapper }); await waitFor(() => expect(container.querySelector('ods-skeleton')).toBeVisible()); - expect(mockLocationDetails).toHaveBeenCalledWith(mockVaults[0]!.currentState.region); }); it('renders during error', async () => { - mockLocationDetails.mockReturnValue({ data: null, isLoading: false, isError: true }); - const vault = mockVaults[0]!; + // Seed the cache with an error state + queryClient.setQueryDefaults(queryKeys.locations.detail(region), { retry: false }); + await queryClient.prefetchQuery({ + queryKey: queryKeys.locations.detail(region), + queryFn: () => Promise.reject(new Error('fail')), + }); + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); await waitFor(() => - expect(screen.getByTestId('cell')).toHaveTextContent(mockVaults[0]!.currentState.region), + expect(screen.getByTestId('cell')).toHaveTextContent(vault.currentState.region), ); - expect(mockLocationDetails).toHaveBeenCalledWith(mockVaults[0]!.currentState.region); }); }); diff --git a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/ResourceRegionCell.component.tsx b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/ResourceRegionCell.component.tsx index 4e46a0007fd1..a45c59d539fb 100644 --- a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/ResourceRegionCell.component.tsx +++ b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/ResourceRegionCell.component.tsx @@ -1,19 +1,21 @@ import React from 'react'; +import { useQuery } from '@tanstack/react-query'; + import { OdsSkeleton } from '@ovhcloud/ods-components/react'; import { DataGridTextCell } from '@ovh-ux/manager-react-components'; -import { useLocationDetails } from '@/data/hooks/location/getLocationDetails'; +import { locationsQueries } from '@/data/queries/locations.queries'; export type ResourceRegionCellProps = { region: string; }; export const ResourceRegionCell = ({ region }: ResourceRegionCellProps) => { - const { data, isLoading, isError } = useLocationDetails(region); + const { data, isPending, isError } = useQuery(locationsQueries.detail(region)); - if (isLoading) return ; + if (isPending) return ; if (isError) return {region}; return {data?.name}; diff --git a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/__tests__/ResourceRegionCell.component.test.tsx b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/__tests__/ResourceRegionCell.component.test.tsx index 0ea9037c760b..a4a7574b4405 100644 --- a/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/__tests__/ResourceRegionCell.component.test.tsx +++ b/packages/manager/modules/backup-agent/src/components/CommonCells/ResourceRegionCell/__tests__/ResourceRegionCell.component.test.tsx @@ -1,64 +1,69 @@ import React from 'react'; +import { QueryClient } from '@tanstack/react-query'; import { render, screen, waitFor } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockLocations } from '@/mocks/location/locations'; import { mockVaults } from '@/mocks/vaults/vaults.mock'; import { DataGridTextCellMock } from '@/test-utils/mocks/manager-react-components'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { ResourceRegionCell } from '../ResourceRegionCell.component'; -const { mockLocationDetails } = vi.hoisted(() => { - return { - mockLocationDetails: vi.fn(), - }; -}); - -vi.mock('@/data/hooks/location/getLocationDetails', () => ({ - useLocationDetails: mockLocationDetails, -})); - vi.mock('@ovh-ux/manager-react-components', () => ({ DataGridTextCell: DataGridTextCellMock, })); describe('ResourceRegionCell', () => { + let queryClient: QueryClient; + const vault = mockVaults[0]!; + const region = vault.currentState.region; + + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + + beforeEach(() => { + queryClient = createQueryClientTest(); + }); + it('renders resourceName from currentState', async () => { - mockLocationDetails.mockReturnValue({ - data: mockLocations[0], - isLoading: false, - isError: false, - }); - const vault = mockVaults[0]!; + queryClient.setQueryData(queryKeys.locations.detail(region), mockLocations[0]); + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); await waitFor(() => expect(screen.getByTestId('cell')).toHaveTextContent(mockLocations[0]!.name), ); - expect(mockLocationDetails).toHaveBeenCalledWith(mockVaults[0]!.currentState.region); }); it('renders during loading', async () => { - mockLocationDetails.mockReturnValue({ data: null, isLoading: true, isError: false }); - const vault = mockVaults[0]!; + // Don't seed the cache so the query stays in loading state - const { container } = render(); + const wrapper = await buildWrapper(); + + const { container } = render(, { wrapper }); await waitFor(() => expect(container.querySelector('ods-skeleton')).toBeVisible()); - expect(mockLocationDetails).toHaveBeenCalledWith(mockVaults[0]!.currentState.region); }); it('renders during error', async () => { - mockLocationDetails.mockReturnValue({ data: null, isLoading: false, isError: true }); - const vault = mockVaults[0]!; + // Seed the cache with an error state + queryClient.setQueryDefaults(queryKeys.locations.detail(region), { retry: false }); + await queryClient.prefetchQuery({ + queryKey: queryKeys.locations.detail(region), + queryFn: () => Promise.reject(new Error('fail')), + }); + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); await waitFor(() => - expect(screen.getByTestId('cell')).toHaveTextContent(mockVaults[0]!.currentState.region), + expect(screen.getByTestId('cell')).toHaveTextContent(vault.currentState.region), ); - expect(mockLocationDetails).toHaveBeenCalledWith(mockVaults[0]!.currentState.region); }); }); diff --git a/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component.tsx b/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component.tsx index f5a570e10bf5..9a399d070cd3 100644 --- a/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component.tsx +++ b/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component.tsx @@ -1,3 +1,4 @@ +import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsSkeleton, OdsText } from '@ovhcloud/ods-components/react'; @@ -6,7 +7,7 @@ import { NAMESPACES } from '@ovh-ux/manager-common-translations'; import { ManagerTile } from '@ovh-ux/manager-react-components'; import { ResourceStatusBadge } from '@/components/ResourceStatusBadge/ResourceStatusBadge.component'; -import { useLocationDetails } from '@/data/hooks/location/getLocationDetails'; +import { locationsQueries } from '@/data/queries/locations.queries'; import { Resource } from '@/types/Resource.type'; import { WithRegion } from '@/types/Utils.type'; @@ -27,9 +28,11 @@ export function GeneralInformationTile({ NAMESPACES.REGION, 'dashboard', ]); - const { data: locationData, isLoading: isLocationLoading } = useLocationDetails( - resourceDetails?.currentState.region, - ); + const region = resourceDetails?.currentState.region; + const { data: locationData, isPending: isLocationLoading } = useQuery({ + ...locationsQueries.detail(region!), + enabled: !!region, + }); return ( diff --git a/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/__tests__/GeneralInformationTile.test.tsx b/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/__tests__/GeneralInformationTile.test.tsx index 29c3e9371cba..645d4451f73c 100644 --- a/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/__tests__/GeneralInformationTile.test.tsx +++ b/packages/manager/modules/backup-agent/src/components/CommonTiles/GeneralInformationsTile/__tests__/GeneralInformationTile.test.tsx @@ -1,10 +1,14 @@ +import { QueryClient } from '@tanstack/react-query'; import { render, screen } from '@testing-library/react'; import { vi } from 'vitest'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockLocations } from '@/mocks/location/locations'; import { mockVaults } from '@/mocks/vaults/vaults.mock'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { GeneralInformationTile } from '../GeneralInformationTile.component'; @@ -16,15 +20,6 @@ const LABELS_VISIBLES = [ `${NAMESPACES.REGION}:region`, ]; -const { useBackupVaultDetailsMock, useLocationDetailsMock } = vi.hoisted(() => ({ - useBackupVaultDetailsMock: vi.fn(), - useLocationDetailsMock: vi.fn(), -})); - -vi.mock('@/data/hooks/location/getLocationDetails', () => ({ - useLocationDetails: useLocationDetailsMock, -})); - vi.mock('react-i18next', () => ({ useTranslation: vi.fn().mockReturnValue({ t: vi.fn().mockImplementation((key: string) => key), @@ -32,10 +27,23 @@ vi.mock('react-i18next', () => ({ })); describe('GeneralInformationTile', () => { + let queryClient: QueryClient; + const vault = mockVaults[0]!; + const region = vault.currentState.region; + + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + + beforeEach(() => { + queryClient = createQueryClientTest(); + queryClient.setQueryData(queryKeys.locations.detail(region), mockLocations[0]!); + }); + it('Should render GeneralInformationTile component', async () => { - useLocationDetailsMock.mockReturnValue({ data: mockLocations[0]!, isLoading: false }); + const wrapper = await buildWrapper(); + const { container } = render( - , + , + { wrapper }, ); await expect(container).toBeAccessible(); @@ -46,10 +54,11 @@ describe('GeneralInformationTile', () => { }); it('Should render GeneralInformationTile component', async () => { - useBackupVaultDetailsMock.mockReturnValue({ data: mockVaults[0]!, isLoading: true }); - useLocationDetailsMock.mockReturnValue({ data: mockLocations[0]!, isLoading: true }); + const wrapper = await buildWrapper(); + const { container } = render( - , + , + { wrapper }, ); await expect(container).toBeAccessible(); diff --git a/packages/manager/modules/backup-agent/src/data/api/agents/agents.requests.ts b/packages/manager/modules/backup-agent/src/data/api/agents/agents.requests.ts index eef69f75e989..b5f47de1201a 100644 --- a/packages/manager/modules/backup-agent/src/data/api/agents/agents.requests.ts +++ b/packages/manager/modules/backup-agent/src/data/api/agents/agents.requests.ts @@ -1,4 +1,4 @@ -import { ApiResponse, v2 } from '@ovh-ux/manager-core-api'; +import { ApiResponse, fetchIcebergV2, v2 } from '@ovh-ux/manager-core-api'; import { Agent } from '@/types/Agent.type'; import { AgentDownloadLinks } from '@/types/AgentDownloadLinks'; @@ -23,6 +23,14 @@ export type EditBackupAgentConfigParams = GetBackupAgentParams & { policy: string; }; +export const getBackupAgents = async (backupServicesId: string, vspcTenantId: string) => { + const { data } = await fetchIcebergV2>({ + route: getBackupAgentsRoute(backupServicesId, vspcTenantId), + pageSize: 9999, + }); + return data; +}; + export const getBackupAgentsDetails = async ({ backupServicesId, vspcTenantId, diff --git a/packages/manager/modules/backup-agent/src/data/api/baremetal/baremetals.requests.ts b/packages/manager/modules/backup-agent/src/data/api/baremetal/baremetals.requests.ts index 0befcf6c77ae..610af11fbc0e 100644 --- a/packages/manager/modules/backup-agent/src/data/api/baremetal/baremetals.requests.ts +++ b/packages/manager/modules/backup-agent/src/data/api/baremetal/baremetals.requests.ts @@ -1,7 +1,15 @@ -import { v6 } from '@ovh-ux/manager-core-api'; +import { fetchIcebergV6, v6 } from '@ovh-ux/manager-core-api'; import { Baremetal } from '@/types/Baremetal.type'; -import { getBaremetalDetailsRoute } from '@/utils/apiRoutes'; +import { BAREMETAL_LIST_ROUTE, getBaremetalDetailsRoute } from '@/utils/apiRoutes'; + +export const getBaremetals = async () => { + const { data } = await fetchIcebergV6({ + route: BAREMETAL_LIST_ROUTE, + pageSize: 9999, + }); + return data; +}; export const getBaremetalDetails = async (serviceName: string) => { const { data } = await v6.get(getBaremetalDetailsRoute(serviceName)); diff --git a/packages/manager/modules/backup-agent/src/data/api/billing/vaultConsumption.ts b/packages/manager/modules/backup-agent/src/data/api/billing/vaultConsumption.ts deleted file mode 100644 index abc21d6ec9cb..000000000000 --- a/packages/manager/modules/backup-agent/src/data/api/billing/vaultConsumption.ts +++ /dev/null @@ -1 +0,0 @@ -// Get all servicesId diff --git a/packages/manager/modules/backup-agent/src/data/hooks/agents/getAgentDetails.ts b/packages/manager/modules/backup-agent/src/data/hooks/agents/getAgentDetails.ts deleted file mode 100644 index f73dc0b182cc..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/agents/getAgentDetails.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { queryOptions, useQuery } from '@tanstack/react-query'; - -import { getBackupAgentsDetails } from '@/data/api/agents/agents.requests'; -import { useGetBackupServicesId } from '@/data/hooks/backup/useBackupServicesId'; -import { BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY } from '@/data/hooks/tenants/useVspcTenantDetails'; -import { useGetVspcTenantId } from '@/data/hooks/tenants/useVspcTenantId'; - -export type GetBackupAgentDetailsParams = { - backupAgentId: string; -}; - -export const BACKUP_VSPC_TENANT_AGENT_DETAILS_QUERY_KEY = (agentId: string) => [ - ...BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY(), - agentId, -]; - -export const useBackupVSPCTenantAgentDetailsOptions = ({ - backupAgentId, -}: GetBackupAgentDetailsParams) => { - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - - return queryOptions({ - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - - return getBackupAgentsDetails({ - backupServicesId: backupServicesId!, - vspcTenantId, - backupAgentId, - }); - }, - queryKey: BACKUP_VSPC_TENANT_AGENT_DETAILS_QUERY_KEY(backupAgentId), - enabled: !!backupAgentId, - }); -}; - -export const useBackupVSPCTenantAgentDetails = ({ agentId, ...options }: { agentId?: string }) => { - return useQuery({ - ...useBackupVSPCTenantAgentDetailsOptions({ - backupAgentId: agentId!, - }), - ...options, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/agents/getAgents.ts b/packages/manager/modules/backup-agent/src/data/hooks/agents/getAgents.ts deleted file mode 100644 index d5f1afced9b0..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/agents/getAgents.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { QueryKey } from '@tanstack/react-query'; - -import { useResourcesIcebergV2 } from '@ovh-ux/manager-react-components'; - -import { BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY } from '@/data/hooks/tenants/useVspcTenantDetails'; -import { Agent } from '@/types/Agent.type'; -import { AgentResource } from '@/types/Resource.type'; -import { getBackupAgentsRoute } from '@/utils/apiRoutes'; - -import { useBackupServicesId } from '../backup/useBackupServicesId'; -import { useVspcTenantId } from '../tenants/useVspcTenantId'; - -type UseBackupAgentListParams = { - pageSize?: number; -}; - -export const BACKUP_AGENTS_LIST_QUERY_KEY = () => - [...BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY(), 'agents'] as (QueryKey & string)[]; - -export const useBackupAgentList = ({ pageSize = 9999 }: UseBackupAgentListParams = {}) => { - const { data: backupServicesId } = useBackupServicesId(); - const { data: vspcTenantId } = useVspcTenantId(); - - return useResourcesIcebergV2>({ - route: getBackupAgentsRoute(backupServicesId!, vspcTenantId!), - queryKey: BACKUP_AGENTS_LIST_QUERY_KEY(), - enabled: !!backupServicesId && !!vspcTenantId, - pageSize, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/agents/getDownloadLinkAgent.ts b/packages/manager/modules/backup-agent/src/data/hooks/agents/getDownloadLinkAgent.ts deleted file mode 100644 index 3b87cb409871..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/agents/getDownloadLinkAgent.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { downloadLinkBackupAgent } from '@/data/api/agents/agents.requests'; -import { BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY } from '@/data/hooks/tenants/useVspcTenantDetails'; -import { OS } from '@/types/Os.type'; - -import { useGetBackupServicesId } from '../backup/useBackupServicesId'; -import { useGetVspcTenantId } from '../tenants/useVspcTenantId'; - -export const BACKUP_VSPC_TENANT_AGENT_DOWNLOAD_LINK_QUERY_KEY = () => [ - ...BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY(), - 'agent', -]; - -export const useBackupVSPCTenantAgentDownloadLink = ({ os, ...options }: { os?: OS | null }) => { - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - - return useQuery({ - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - - return downloadLinkBackupAgent(backupServicesId!, vspcTenantId); - }, - queryKey: BACKUP_VSPC_TENANT_AGENT_DOWNLOAD_LINK_QUERY_KEY(), - enabled: !!os, - select: (data) => { - switch (os) { - case 'WINDOWS': - return data.windowsUrl; - case 'LINUX': - default: - return data.linuxUrl; - } - }, - ...options, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/agents/postAgent.ts b/packages/manager/modules/backup-agent/src/data/hooks/agents/postAgent.ts deleted file mode 100644 index a8fe1d3eae91..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/agents/postAgent.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; - -import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; - -import { - AddBackupAgentConfigParams, - postConfigurationBackupAgents, -} from '@/data/api/agents/agents.requests'; -import { useGetBackupServicesId } from '@/data/hooks/backup/useBackupServicesId'; -import { useGetVspcTenantId } from '@/data/hooks/tenants/useVspcTenantId'; - -import { GET_VSPC_TENANTS_QUERY_KEY } from '../tenants/useVspcTenants'; - -type AddBackupConfigPayload = AddBackupAgentConfigParams; -type UseAddConfigurationVSPCTenantAgentParams = Partial< - UseMutationOptions< - ApiResponse, - ApiError, - Omit - > ->; -export const useAddConfigurationVSPCTenantAgent = ( - options: UseAddConfigurationVSPCTenantAgentParams = {}, -) => { - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ( - payload: Omit, - ) => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - - return postConfigurationBackupAgents({ - backupServicesId: backupServicesId!, - vspcTenantId, - ...payload, - }); - }, - ...options, - onSuccess: async (...params) => { - await queryClient.invalidateQueries({ - queryKey: GET_VSPC_TENANTS_QUERY_KEY, - }); - options.onSuccess?.(...params); - }, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/agents/putAgent.ts b/packages/manager/modules/backup-agent/src/data/hooks/agents/putAgent.ts deleted file mode 100644 index fa1661dd6a94..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/agents/putAgent.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; - -import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; - -import { - EditBackupAgentConfigParams, - editConfigurationBackupAgents, -} from '@/data/api/agents/agents.requests'; -import { useGetBackupServicesId } from '@/data/hooks/backup/useBackupServicesId'; -import { useGetVspcTenantId } from '@/data/hooks/tenants/useVspcTenantId'; - -import { GET_VSPC_TENANTS_QUERY_KEY } from '../tenants/useVspcTenants'; - -type EditBackupConfigPayload = EditBackupAgentConfigParams; -type UseEditConfigurationVSPCTenantAgentParams = Partial< - UseMutationOptions< - ApiResponse, - ApiError, - Omit - > ->; -export const useEditConfigurationVSPCTenantAgent = ( - options: UseEditConfigurationVSPCTenantAgentParams = {}, -) => { - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ( - payload: Omit, - ) => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - - return editConfigurationBackupAgents({ - backupServicesId: backupServicesId!, - vspcTenantId, - ...payload, - }); - }, - ...options, - onSuccess: async (...params) => { - await queryClient.invalidateQueries({ - queryKey: GET_VSPC_TENANTS_QUERY_KEY, - }); - options.onSuccess?.(...params); - }, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/agents/useDeleteAgent.ts b/packages/manager/modules/backup-agent/src/data/hooks/agents/useDeleteAgent.ts deleted file mode 100644 index 3fb07583057b..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/agents/useDeleteAgent.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; - -import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; - -import { deleteBackupAgent } from '@/data/api/agents/agents.requests'; -import { useGetBackupServicesId } from '@/data/hooks/backup/useBackupServicesId'; -import { useGetVspcTenantId } from '@/data/hooks/tenants/useVspcTenantId'; - -import { BACKUP_TENANTS_QUERY_KEY } from '../tenants/useBackupTenants'; - -type DeleteAgentParams = { - agentId: string; -}; - -type UseDeleteTenantAgentParams = Partial< - UseMutationOptions, ApiError, DeleteAgentParams> ->; - -export const useDeleteTenantAgent = (options: UseDeleteTenantAgentParams = {}) => { - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ agentId }) => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - return deleteBackupAgent({ - backupServicesId: backupServicesId!, - vspcTenantId, - backupAgentId: agentId, - }); - }, - ...options, - onSuccess: async (...params) => { - await queryClient.invalidateQueries({ - queryKey: BACKUP_TENANTS_QUERY_KEY, - }); - options.onSuccess?.(...params); - }, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/agoraService/useAgoraServiceIdOptions.ts b/packages/manager/modules/backup-agent/src/data/hooks/agoraService/useAgoraServiceIdOptions.ts deleted file mode 100644 index 0a99aae32ffd..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/agoraService/useAgoraServiceIdOptions.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { queryOptions, useQueryClient } from '@tanstack/react-query'; - -import { - getResourceServiceId, - getResourceServiceIdQueryKey, -} from '@ovh-ux/manager-module-common-api'; - -export const getAgoraServiceIdOptions = (resourceName: string) => - queryOptions({ - queryKey: getResourceServiceIdQueryKey({ resourceName }), - queryFn: () => getResourceServiceId({ resourceName }), - }); - -export const useGetAgoraServiceIdOptions = () => { - const queryClient = useQueryClient(); - - return (resourceName: string) => - queryClient.ensureQueryData(getAgoraServiceIdOptions(resourceName)); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/backup/useBackupServicesId.ts b/packages/manager/modules/backup-agent/src/data/hooks/backup/useBackupServicesId.ts deleted file mode 100644 index 82c8f2fc8b94..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/backup/useBackupServicesId.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { queryOptions, useQuery, useQueryClient } from '@tanstack/react-query'; - -import { getBackupServices } from '@/data/api/backup/backupServices.requests'; - -const ONE_DAY_HOURS_IN_MS = 1000 * 60 * 60 * 24; - -export const getBackupServicesOptions = () => { - return queryOptions({ - queryFn: () => getBackupServices(), - queryKey: ['backupServiceId'], - staleTime: ONE_DAY_HOURS_IN_MS, - }); -}; - -export const useBackupServicesId = () => { - return useQuery({ - ...getBackupServicesOptions(), - select: (data) => data[0]?.id, - }); -}; - -export const useGetBackupServicesId = () => { - const queryClient = useQueryClient(); - - return async () => (await queryClient.ensureQueryData(getBackupServicesOptions()))[0]?.id; -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalDetails.ts b/packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalDetails.ts deleted file mode 100644 index fd8668164ed3..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalDetails.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { queryOptions, useQuery } from '@tanstack/react-query'; - -import { getBaremetalDetails } from '@/data/api/baremetal/baremetals.requests'; - -import { BAREMETAL_QUERY_KEYS } from './useBaremetalsList'; - -export type GetBaremetalDetailsParams = { - serviceName: string; -}; - -export const BAREMETAL_DETAILS_QUERY_KEY = (serviceName: string) => [ - ...BAREMETAL_QUERY_KEYS.baremetals, - serviceName, -]; - -export const useBaremetalDetailsOptions = ({ serviceName }: GetBaremetalDetailsParams) => { - return queryOptions({ - queryFn: () => getBaremetalDetails(serviceName), - queryKey: BAREMETAL_DETAILS_QUERY_KEY(serviceName), - enabled: !!serviceName, - }); -}; - -export const useBaremetalDetails = ({ serviceName, ...options }: { serviceName?: string }) => { - return useQuery({ - ...useBaremetalDetailsOptions({ serviceName: serviceName! }), - ...options, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalsList.ts b/packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalsList.ts deleted file mode 100644 index fa50e7a8aaf9..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/baremetal/useBaremetalsList.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useResourcesIcebergV6 } from '@ovh-ux/manager-react-components'; - -import { Baremetal } from '@/types/Baremetal.type'; -import { BAREMETAL_LIST_ROUTE } from '@/utils/apiRoutes'; - -export const BAREMETAL_QUERY_KEYS = { - baremetals: ['baremetals'], -}; - -type UseBaremetalsListParams = { - pageSize: number; -}; - -export const useBaremetalsList = ( - { pageSize = 9999 }: UseBaremetalsListParams = { pageSize: 9000 }, -) => - useResourcesIcebergV6({ - route: BAREMETAL_LIST_ROUTE, - queryKey: BAREMETAL_QUERY_KEYS.baremetals, - pageSize, - }); diff --git a/packages/manager/modules/backup-agent/src/data/hooks/consumption/useServiceConsumption.ts b/packages/manager/modules/backup-agent/src/data/hooks/consumption/useServiceConsumption.ts deleted file mode 100644 index b1c003801a37..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/consumption/useServiceConsumption.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { queryOptions } from '@tanstack/react-query'; - -import { getServiceConsumption } from '@/data/api/services/consumption'; -import { useGetAgoraServiceIdOptions } from '@/data/hooks/agoraService/useAgoraServiceIdOptions'; - -export const SERVICE_CONSUMPTION_QUERY_KEY = ['services', 'consumption']; - -export const useGetServiceConsumptionOptions = () => { - const getAgoraServiceIdOptions = useGetAgoraServiceIdOptions(); - - return (resourceName: string) => - queryOptions({ - queryKey: [...SERVICE_CONSUMPTION_QUERY_KEY, resourceName], - queryFn: async () => { - const serviceIds = await getAgoraServiceIdOptions(resourceName); - - return getServiceConsumption(serviceIds.data[0]!); - }, - retry: false, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/location/getLocationDetails.ts b/packages/manager/modules/backup-agent/src/data/hooks/location/getLocationDetails.ts deleted file mode 100644 index e789a940f101..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/location/getLocationDetails.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { getLocationDetails } from '@/data/api/locations/location.requests'; - -export const LOCATION_QUERY_KEYS = { - location: ['location'], - locationByName: (locationName: string) => ['location', locationName], -}; - -export const useLocationDetails = (locationName?: string) => - useQuery({ - queryKey: LOCATION_QUERY_KEYS.locationByName(locationName!), - queryFn: () => getLocationDetails(locationName!), - enabled: !!locationName, - }); diff --git a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenantDetails.ts b/packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenantDetails.ts deleted file mode 100644 index 2a2095c0d8fc..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenantDetails.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { DefinedInitialDataOptions, useQuery } from '@tanstack/react-query'; - -import { getTenantDetails } from '@/data/api/tenants/tenants.requests'; -import { Resource } from '@/types/Resource.type'; -import { Tenant } from '@/types/Tenant.type'; -import { WithRegion } from '@/types/Utils.type'; -import { mapTenantResourceToTenantResourceWithRegion } from '@/utils/mappers/mapTenantToTenantWithRegion'; - -import { useGetBackupServicesId } from '../backup/useBackupServicesId'; -import { BACKUP_TENANTS_QUERY_KEY } from './useBackupTenants'; - -export const BACKUP_TENANT_DETAILS_QUERY_KEY = [...BACKUP_TENANTS_QUERY_KEY, 'details']; - -export const useBackupTenantDetails = ({ - ...options -}: Partial< - Omit< - DefinedInitialDataOptions, unknown, Resource>>, - 'queryKey' | 'queryFn' - > -> = {}) => { - const getBackupServiceId = useGetBackupServicesId(); - - return useQuery({ - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - return getTenantDetails(backupServicesId!); - }, - queryKey: BACKUP_TENANT_DETAILS_QUERY_KEY, - select: (data): Resource> => - mapTenantResourceToTenantResourceWithRegion(data), - ...options, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenants.ts b/packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenants.ts deleted file mode 100644 index 3497c1806769..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useBackupTenants.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { mapTenantResourceToTenantResourceWithRegion } from '@/utils/mappers/mapTenantToTenantWithRegion'; - -import { getBackupTenants } from '../../api/tenants/tenants.requests'; - -export const BACKUP_TENANTS_QUERY_KEY = ['backup', 'tenants']; - -export const useBackupTenants = () => - useQuery({ - queryKey: BACKUP_TENANTS_QUERY_KEY, - queryFn: () => getBackupTenants(), - select: (res) => - res.data.map((tenantResource) => mapTenantResourceToTenantResourceWithRegion(tenantResource)), - }); diff --git a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useDeleteTenant.ts b/packages/manager/modules/backup-agent/src/data/hooks/tenants/useDeleteTenant.ts deleted file mode 100644 index 6d73391ebfbd..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useDeleteTenant.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; - -import { ApiError } from '@ovh-ux/manager-core-api'; - -import { useGetBackupServicesId } from '@/data/hooks/backup/useBackupServicesId'; -import { useGetVspcTenantId } from '@/data/hooks/tenants/useVspcTenantId'; - -import { deleteVSPCTenant } from '../../api/tenants/tenants.requests'; -import { GET_VSPC_TENANTS_QUERY_KEY } from './useVspcTenants'; - -type UseDeleteVSPCTenantParams = Partial>; - -export const useDeleteVSPCTenant = ( - options: Omit = {}, -) => { - const queryClient = useQueryClient(); - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - - return useMutation({ - mutationFn: async () => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - - return deleteVSPCTenant(backupServicesId!, vspcTenantId); - }, - ...options, - onSuccess: async (...params) => { - await queryClient.invalidateQueries({ - queryKey: GET_VSPC_TENANTS_QUERY_KEY, - }); - options.onSuccess?.(...params); - }, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantBackupPolicies.ts b/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantBackupPolicies.ts deleted file mode 100644 index caa45532c9c7..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantBackupPolicies.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { getBackupPolicies } from '@/data/api/tenants/backupPolicies.requests'; -import { BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY } from '@/data/hooks/tenants/useVspcTenantDetails'; - -import { useGetBackupServicesId } from '../backup/useBackupServicesId'; -import { useGetVspcTenantId } from './useVspcTenantId'; - -export const BACKUP_TENANT_POLICIES_QUERY_KEY = () => [ - ...BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY(), - 'policies', -]; - -export const useBackupTenantPolicies = () => { - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - - return useQuery({ - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - return getBackupPolicies(backupServicesId!, vspcTenantId); - }, - queryKey: BACKUP_TENANT_POLICIES_QUERY_KEY(), - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantDetails.ts b/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantDetails.ts deleted file mode 100644 index a37f3f59cb61..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantDetails.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { QueryKey, queryOptions, useQuery } from '@tanstack/react-query'; - -import { getVSPCTenantDetails } from '@/data/api/tenants/tenants.requests'; - -import { useGetBackupServicesId } from '../backup/useBackupServicesId'; -import { useGetVspcTenantId } from './useVspcTenantId'; -import { GET_VSPC_TENANTS_QUERY_KEY } from './useVspcTenants'; - -export const BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY = (vspcTenantID?: string | QueryKey) => [ - ...GET_VSPC_TENANTS_QUERY_KEY, - vspcTenantID, -]; - -export const useGetBackupVSPCTenantDetailsOptions = () => { - const getBackupServiceId = useGetBackupServicesId(); - const getVspcTenantId = useGetVspcTenantId(); - - return () => - queryOptions({ - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - const vspcTenantId = await getVspcTenantId(); - - return getVSPCTenantDetails(backupServicesId!, vspcTenantId); - }, - queryKey: BACKUP_VSPC_TENANT_DETAILS_QUERY_KEY(), - }); -}; - -export const useBackupVSPCTenantDetails = () => { - return useQuery(useGetBackupVSPCTenantDetailsOptions()()); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantId.ts b/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantId.ts deleted file mode 100644 index 97943f381b9f..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenantId.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useQuery, useQueryClient } from '@tanstack/react-query'; - -import { useVSPCTenantsOptions } from '@/data/hooks/tenants/useVspcTenants'; - -export const useGetVspcTenantId = () => { - const queryClient = useQueryClient(); - const vspcTenantsOptions = useVSPCTenantsOptions(); - - return async () => { - const tenants = await queryClient.ensureQueryData(vspcTenantsOptions); - if (!tenants || tenants.length === 0) { - throw new Error('No VSPC Tenant found'); - } - return tenants[0]!.id; - }; -}; - -export const useVspcTenantId = () => { - return useQuery({ - ...useVSPCTenantsOptions(), - select: (data) => data[0]?.id, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenants.ts b/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenants.ts deleted file mode 100644 index af251aa4f8ea..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/tenants/useVspcTenants.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { queryOptions, useQuery } from '@tanstack/react-query'; - -import { useBackupVSPCTenantDetails } from '@/data/hooks/tenants/useVspcTenantDetails'; -import { countBackupAgents } from '@/utils/countBackupAgents'; - -import { getVSPCTenants } from '../../api/tenants/tenants.requests'; -import { useGetBackupServicesId } from '../backup/useBackupServicesId'; -import { BACKUP_TENANTS_QUERY_KEY } from './useBackupTenants'; - -export const GET_VSPC_TENANTS_QUERY_KEY = [...BACKUP_TENANTS_QUERY_KEY, 'vspc']; - -export const useVSPCTenantsOptions = () => { - const getBackupServiceId = useGetBackupServicesId(); - - return queryOptions({ - queryKey: GET_VSPC_TENANTS_QUERY_KEY, - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - return getVSPCTenants({ backupServicesId: backupServicesId! }); - }, - }); -}; - -export const useVSPCTenants = () => useQuery(useVSPCTenantsOptions()); - -export const useInstalledBackupAgents = () => { - const { data: vspcTenantDetails, isPending } = useBackupVSPCTenantDetails(); - - return { - installedBackupAgents: countBackupAgents( - vspcTenantDetails?.currentState ? [vspcTenantDetails.currentState] : [], - ), - isPending, - }; -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/useAddConfigurationVSPCTenantAgent.ts b/packages/manager/modules/backup-agent/src/data/hooks/useAddConfigurationVSPCTenantAgent.ts new file mode 100644 index 000000000000..f11415a11de2 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/hooks/useAddConfigurationVSPCTenantAgent.ts @@ -0,0 +1,39 @@ +import { type UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; + +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; + +import { + type AddBackupAgentConfigParams, + postConfigurationBackupAgents, +} from '@/data/api/agents/agents.requests'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { servicesQueries } from '@/data/queries/services.queries'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; + +type MutationPayload = Omit; + +export const useAddConfigurationVSPCTenantAgent = ({ + onSuccess, + ...options +}: Omit, ApiError, MutationPayload>, 'mutationFn'> = {}) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (payload: MutationPayload) => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const vspcTenantId = await tenantsQueries.withClient(queryClient).vspcTenantId(); + return postConfigurationBackupAgents({ + backupServicesId: backupServicesId!, + vspcTenantId, + ...payload, + }); + }, + onSuccess: async (...params) => { + await queryClient.invalidateQueries({ + queryKey: queryKeys.tenants.vspc.all(), + }); + onSuccess?.(...params); + }, + ...options, + }); +}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/useDeleteTenantAgent.ts b/packages/manager/modules/backup-agent/src/data/hooks/useDeleteTenantAgent.ts new file mode 100644 index 000000000000..601f0ac88759 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/hooks/useDeleteTenantAgent.ts @@ -0,0 +1,41 @@ +import { type UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; + +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; + +import { deleteBackupAgent } from '@/data/api/agents/agents.requests'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { servicesQueries } from '@/data/queries/services.queries'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; + +type DeleteAgentParams = { + agentId: string; +}; + +export const useDeleteTenantAgent = ({ + onSuccess, + ...options +}: Omit< + UseMutationOptions, ApiError, DeleteAgentParams>, + 'mutationFn' +> = {}) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({ agentId }: DeleteAgentParams) => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const vspcTenantId = await tenantsQueries.withClient(queryClient).vspcTenantId(); + return deleteBackupAgent({ + backupServicesId: backupServicesId!, + vspcTenantId, + backupAgentId: agentId, + }); + }, + onSuccess: async (...params) => { + await queryClient.invalidateQueries({ + queryKey: queryKeys.tenants.all, + }); + onSuccess?.(...params); + }, + ...options, + }); +}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/useDeleteVSPCTenant.ts b/packages/manager/modules/backup-agent/src/data/hooks/useDeleteVSPCTenant.ts new file mode 100644 index 000000000000..46c1951892d3 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/hooks/useDeleteVSPCTenant.ts @@ -0,0 +1,30 @@ +import { type UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; + +import { ApiError } from '@ovh-ux/manager-core-api'; + +import { deleteVSPCTenant } from '@/data/api/tenants/tenants.requests'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { servicesQueries } from '@/data/queries/services.queries'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; + +export const useDeleteVSPCTenant = ({ + onSuccess, + ...options +}: Omit, 'mutationFn'> = {}) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const vspcTenantId = await tenantsQueries.withClient(queryClient).vspcTenantId(); + return deleteVSPCTenant(backupServicesId!, vspcTenantId); + }, + onSuccess: async (...params) => { + await queryClient.invalidateQueries({ + queryKey: queryKeys.tenants.vspc.all(), + }); + onSuccess?.(...params); + }, + ...options, + }); +}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/useDeleteVault.ts b/packages/manager/modules/backup-agent/src/data/hooks/useDeleteVault.ts new file mode 100644 index 000000000000..da1079365762 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/hooks/useDeleteVault.ts @@ -0,0 +1,26 @@ +import { type UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; + +import { ApiError } from '@ovh-ux/manager-core-api'; + +import { deleteVault } from '@/data/api/vaults/vault.requests'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { servicesQueries } from '@/data/queries/services.queries'; + +export const useDeleteVault = ({ + onSuccess, + ...options +}: Omit, 'mutationFn'> = {}) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (vaultId: string) => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + return deleteVault(backupServicesId!, vaultId); + }, + onSuccess: async (...params) => { + await queryClient.invalidateQueries({ queryKey: queryKeys.vaults.all }); + onSuccess?.(...params); + }, + ...options, + }); +}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/useEditConfigurationVSPCTenantAgent.ts b/packages/manager/modules/backup-agent/src/data/hooks/useEditConfigurationVSPCTenantAgent.ts new file mode 100644 index 000000000000..7979e0f101ef --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/hooks/useEditConfigurationVSPCTenantAgent.ts @@ -0,0 +1,39 @@ +import { type UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; + +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; + +import { + type EditBackupAgentConfigParams, + editConfigurationBackupAgents, +} from '@/data/api/agents/agents.requests'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { servicesQueries } from '@/data/queries/services.queries'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; + +type MutationPayload = Omit; + +export const useEditConfigurationVSPCTenantAgent = ({ + onSuccess, + ...options +}: Omit, ApiError, MutationPayload>, 'mutationFn'> = {}) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (payload: MutationPayload) => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const vspcTenantId = await tenantsQueries.withClient(queryClient).vspcTenantId(); + return editConfigurationBackupAgents({ + backupServicesId: backupServicesId!, + vspcTenantId, + ...payload, + }); + }, + onSuccess: async (...params) => { + await queryClient.invalidateQueries({ + queryKey: queryKeys.tenants.vspc.all(), + }); + onSuccess?.(...params); + }, + ...options, + }); +}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/vaults/getVault.ts b/packages/manager/modules/backup-agent/src/data/hooks/vaults/getVault.ts deleted file mode 100644 index 53f2bb6b8dfd..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/vaults/getVault.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { queryOptions, useQuery } from '@tanstack/react-query'; - -import { getVaults } from '@/data/api/vaults/vault.requests'; - -import { useGetBackupServicesId } from '../backup/useBackupServicesId'; - -export const BACKUP_VAULTS_LIST_QUERY_KEY = ['backup', 'vaults']; - -export const useBackupVaultsListOptions = () => { - const getBackupServiceId = useGetBackupServicesId(); - return queryOptions({ - queryKey: BACKUP_VAULTS_LIST_QUERY_KEY, - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - - return getVaults(backupServicesId!); - }, - }); -}; - -export const useBackupVaultsList = () => useQuery(useBackupVaultsListOptions()); diff --git a/packages/manager/modules/backup-agent/src/data/hooks/vaults/getVaultDetails.ts b/packages/manager/modules/backup-agent/src/data/hooks/vaults/getVaultDetails.ts deleted file mode 100644 index 871a85396b40..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/vaults/getVaultDetails.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { DefinedInitialDataOptions, QueryKey, queryOptions, useQuery } from '@tanstack/react-query'; - -import { getVaultDetails } from '@/data/api/vaults/vault.requests'; -import { BACKUP_VAULTS_LIST_QUERY_KEY } from '@/data/hooks/vaults/getVault'; -import { VaultResource } from '@/types/Vault.type'; - -import { useGetBackupServicesId } from '../backup/useBackupServicesId'; - -export const BACKUP_VAULT_DETAILS_QUERY_KEY = (vaultId?: string | QueryKey) => - [...BACKUP_VAULTS_LIST_QUERY_KEY, 'details', vaultId] as QueryKey[]; - -export const useGetBackupVaultDetailsOptions = () => { - const getBackupServiceId = useGetBackupServicesId(); - - return ({ vaultId }: { vaultId?: string }) => - queryOptions({ - queryFn: async () => { - const backupServicesId = await getBackupServiceId(); - return getVaultDetails(backupServicesId!, vaultId!); - }, - queryKey: BACKUP_VAULT_DETAILS_QUERY_KEY(vaultId), - enabled: !!vaultId, - }); -}; - -export const useBackupVaultDetails = ({ - vaultId, -}: { - vaultId?: string; -} & Partial< - Omit< - DefinedInitialDataOptions, - 'queryKey' | 'queryFn' - > ->) => { - const getBackupVaultDetailsOptions = useGetBackupVaultDetailsOptions(); - - return useQuery(getBackupVaultDetailsOptions({ vaultId })); -}; diff --git a/packages/manager/modules/backup-agent/src/data/hooks/vaults/useDeleteVault.ts b/packages/manager/modules/backup-agent/src/data/hooks/vaults/useDeleteVault.ts deleted file mode 100644 index b3632edf770a..000000000000 --- a/packages/manager/modules/backup-agent/src/data/hooks/vaults/useDeleteVault.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'; - -import { ApiError } from '@ovh-ux/manager-core-api'; - -import { deleteVault } from '@/data/api/vaults/vault.requests'; -import { useGetBackupServicesId } from '@/data/hooks/backup/useBackupServicesId'; - -import { BACKUP_VAULTS_LIST_QUERY_KEY } from './getVault'; - -type UseDeleteVaultParams = Partial>; - -export const useDeleteVault = (options: UseDeleteVaultParams = {}) => { - const queryClient = useQueryClient(); - const getBackupServiceId = useGetBackupServicesId(); - - return useMutation({ - mutationFn: async (vaultId: string) => { - const backupServicesId = await getBackupServiceId(); - return deleteVault(backupServicesId!, vaultId); - }, - ...options, - onSuccess: async (...params) => { - await queryClient.invalidateQueries({ - queryKey: BACKUP_VAULTS_LIST_QUERY_KEY, - }); - options.onSuccess?.(...params); - }, - }); -}; diff --git a/packages/manager/modules/backup-agent/src/data/queries/agents.queries.ts b/packages/manager/modules/backup-agent/src/data/queries/agents.queries.ts new file mode 100644 index 000000000000..39b2d5936e00 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/agents.queries.ts @@ -0,0 +1,58 @@ +import { QueryClient, queryOptions } from '@tanstack/react-query'; + +import { + downloadLinkBackupAgent, + getBackupAgents, + getBackupAgentsDetails, +} from '@/data/api/agents/agents.requests'; + +import { queryKeys } from './queryKeys'; +import { servicesQueries } from './services.queries'; +import { tenantsQueries } from './tenants.queries'; + +// ─── Standalone functions (all need QueryClient for dependency resolution) ─── + +const list = (queryClient: QueryClient) => () => + queryOptions({ + queryKey: queryKeys.agents.all(), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const vspcTenantId = await tenantsQueries.withClient(queryClient).vspcTenantId(); + return getBackupAgents(backupServicesId!, vspcTenantId); + }, + }); + +const detail = (queryClient: QueryClient) => (agentId: string) => + queryOptions({ + queryKey: queryKeys.agents.detail(agentId), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const vspcTenantId = await tenantsQueries.withClient(queryClient).vspcTenantId(); + return getBackupAgentsDetails({ + backupServicesId: backupServicesId!, + vspcTenantId, + backupAgentId: agentId, + }); + }, + enabled: !!agentId, + }); + +const downloadLink = (queryClient: QueryClient) => () => + queryOptions({ + queryKey: queryKeys.agents.downloadLink(), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const vspcTenantId = await tenantsQueries.withClient(queryClient).vspcTenantId(); + return downloadLinkBackupAgent(backupServicesId!, vspcTenantId); + }, + }); + +// ─── Factory ─── + +const withClient = (queryClient: QueryClient) => ({ + list: list(queryClient), + detail: detail(queryClient), + downloadLink: downloadLink(queryClient), +}); + +export const agentsQueries = { withClient }; diff --git a/packages/manager/modules/backup-agent/src/data/queries/baremetals.queries.ts b/packages/manager/modules/backup-agent/src/data/queries/baremetals.queries.ts new file mode 100644 index 000000000000..5da364db16f8 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/baremetals.queries.ts @@ -0,0 +1,24 @@ +import { queryOptions } from '@tanstack/react-query'; + +import { getBaremetalDetails, getBaremetals } from '@/data/api/baremetal/baremetals.requests'; + +import { queryKeys } from './queryKeys'; + +// ─── Base queries (no QueryClient needed) ─── + +const all = () => + queryOptions({ + queryKey: queryKeys.baremetals.all, + queryFn: () => getBaremetals(), + }); + +const detail = (serviceName: string) => + queryOptions({ + queryKey: queryKeys.baremetals.detail(serviceName), + queryFn: () => getBaremetalDetails(serviceName), + enabled: !!serviceName, + }); + +// ─── Factory ─── + +export const baremetalsQueries = { all, detail }; diff --git a/packages/manager/modules/backup-agent/src/data/queries/consumption.queries.ts b/packages/manager/modules/backup-agent/src/data/queries/consumption.queries.ts new file mode 100644 index 000000000000..12728b2490a9 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/consumption.queries.ts @@ -0,0 +1,28 @@ +import { QueryClient, queryOptions } from '@tanstack/react-query'; + +import { getServiceConsumption } from '@/data/api/services/consumption'; + +import { queryKeys } from './queryKeys'; +import { servicesQueries } from './services.queries'; + +// ─── Standalone functions (need QueryClient for dependency resolution) ─── + +const byResource = (queryClient: QueryClient) => (resourceName: string) => + queryOptions({ + queryKey: queryKeys.consumption.byResource(resourceName), + queryFn: async () => { + const serviceIds = await queryClient.ensureQueryData( + servicesQueries.agoraServiceId(resourceName), + ); + return getServiceConsumption(serviceIds.data[0]!); + }, + retry: false, + }); + +// ─── Factory ─── + +const withClient = (queryClient: QueryClient) => ({ + byResource: byResource(queryClient), +}); + +export const consumptionQueries = { withClient }; diff --git a/packages/manager/modules/backup-agent/src/data/queries/locations.queries.ts b/packages/manager/modules/backup-agent/src/data/queries/locations.queries.ts new file mode 100644 index 000000000000..ccc09de8ab01 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/locations.queries.ts @@ -0,0 +1,18 @@ +import { queryOptions } from '@tanstack/react-query'; + +import { getLocationDetails } from '@/data/api/locations/location.requests'; + +import { queryKeys } from './queryKeys'; + +// ─── Base queries (no QueryClient needed) ─── + +const detail = (locationName: string) => + queryOptions({ + queryKey: queryKeys.locations.detail(locationName), + queryFn: () => getLocationDetails(locationName), + enabled: !!locationName, + }); + +// ─── Factory ─── + +export const locationsQueries = { detail }; diff --git a/packages/manager/modules/backup-agent/src/data/queries/queryKeys.ts b/packages/manager/modules/backup-agent/src/data/queries/queryKeys.ts new file mode 100644 index 000000000000..747e4fb04dca --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/queryKeys.ts @@ -0,0 +1,35 @@ +export const queryKeys = { + backupServices: { + all: ['backupServices'], + }, + tenants: { + all: ['backup', 'tenants'], + details: () => [...queryKeys.tenants.all, 'details'], + vspc: { + all: () => [...queryKeys.tenants.all, 'vspc'], + detail: (vspcTenantId?: string) => [...queryKeys.tenants.vspc.all(), vspcTenantId], + policies: () => [...queryKeys.tenants.vspc.detail(), 'policies'], + }, + }, + vaults: { + all: ['backup', 'vaults'], + detail: (vaultId?: string) => [...queryKeys.vaults.all, 'details', vaultId], + }, + agents: { + all: () => [...queryKeys.tenants.vspc.detail(), 'agents'], + detail: (agentId: string) => [...queryKeys.tenants.vspc.detail(), agentId], + downloadLink: () => [...queryKeys.tenants.vspc.detail(), 'agent'], + }, + locations: { + all: ['location'], + detail: (locationName: string) => [...queryKeys.locations.all, locationName], + }, + baremetals: { + all: ['baremetals'], + detail: (serviceName: string) => [...queryKeys.baremetals.all, serviceName], + }, + consumption: { + all: ['services', 'consumption'], + byResource: (resourceName: string) => [...queryKeys.consumption.all, resourceName], + }, +} as const; diff --git a/packages/manager/modules/backup-agent/src/data/queries/services.queries.ts b/packages/manager/modules/backup-agent/src/data/queries/services.queries.ts new file mode 100644 index 000000000000..2203935132c7 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/services.queries.ts @@ -0,0 +1,38 @@ +import { QueryClient, queryOptions } from '@tanstack/react-query'; + +import { + getResourceServiceId, + getResourceServiceIdQueryKey, +} from '@ovh-ux/manager-module-common-api'; + +import { getBackupServices } from '@/data/api/backup/backupServices.requests'; + +import { queryKeys } from './queryKeys'; + +const ONE_DAY_HOURS_IN_MS = 1000 * 60 * 60 * 24; + +// ─── Base queries (no QueryClient needed) ─── + +const all = () => + queryOptions({ + queryKey: queryKeys.backupServices.all, + queryFn: () => getBackupServices(), + staleTime: ONE_DAY_HOURS_IN_MS, + }); + +const agoraServiceId = (resourceName: string) => + queryOptions({ + queryKey: getResourceServiceIdQueryKey({ resourceName }), + queryFn: () => getResourceServiceId({ resourceName }), + }); + +// ─── Queries needing QueryClient ─── + +const withClient = (queryClient: QueryClient) => ({ + /** Resolves the first backupServicesId from cache (ensureQueryData). */ + backupServicesId: async () => (await queryClient.ensureQueryData(all()))[0]?.id, +}); + +// ─── Factory ─── + +export const servicesQueries = { all, agoraServiceId, withClient }; diff --git a/packages/manager/modules/backup-agent/src/data/queries/tenants.queries.ts b/packages/manager/modules/backup-agent/src/data/queries/tenants.queries.ts new file mode 100644 index 000000000000..625dec6cfe84 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/tenants.queries.ts @@ -0,0 +1,76 @@ +import { QueryClient, queryOptions } from '@tanstack/react-query'; + +import { getBackupPolicies } from '@/data/api/tenants/backupPolicies.requests'; +import { + getTenantDetails, + getVSPCTenantDetails, + getVSPCTenants, +} from '@/data/api/tenants/tenants.requests'; +import { Resource } from '@/types/Resource.type'; +import { Tenant } from '@/types/Tenant.type'; +import { WithRegion } from '@/types/Utils.type'; +import { mapTenantResourceToTenantResourceWithRegion } from '@/utils/mappers/mapTenantToTenantWithRegion'; + +import { queryKeys } from './queryKeys'; +import { servicesQueries } from './services.queries'; + +// ─── Standalone functions (all need QueryClient for dependency resolution) ─── + +const details = (queryClient: QueryClient) => () => + queryOptions({ + queryKey: queryKeys.tenants.details(), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + return getTenantDetails(backupServicesId!); + }, + select: (data): Resource> => + mapTenantResourceToTenantResourceWithRegion(data), + }); + +const vspcAll = (queryClient: QueryClient) => () => + queryOptions({ + queryKey: queryKeys.tenants.vspc.all(), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + return getVSPCTenants({ backupServicesId: backupServicesId! }); + }, + }); + +const vspcDetail = (queryClient: QueryClient) => () => + queryOptions({ + queryKey: queryKeys.tenants.vspc.detail(), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const tenants = await queryClient.ensureQueryData(vspcAll(queryClient)()); + const vspcTenantId = tenants[0]!.id; + return getVSPCTenantDetails(backupServicesId!, vspcTenantId); + }, + }); + +const vspcPolicies = (queryClient: QueryClient) => () => + queryOptions({ + queryKey: queryKeys.tenants.vspc.policies(), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + const tenants = await queryClient.ensureQueryData(vspcAll(queryClient)()); + const vspcTenantId = tenants[0]!.id; + return getBackupPolicies(backupServicesId!, vspcTenantId); + }, + }); + +// ─── Factory ─── + +const withClient = (queryClient: QueryClient) => ({ + details: details(queryClient), + vspcAll: vspcAll(queryClient), + vspcDetail: vspcDetail(queryClient), + vspcPolicies: vspcPolicies(queryClient), + /** Resolves the first vspcTenantId from cache (ensureQueryData). */ + vspcTenantId: async () => { + const tenants = await queryClient.ensureQueryData(vspcAll(queryClient)()); + if (!tenants?.length) throw new Error('No VSPC Tenant found'); + return tenants[0]!.id; + }, +}); + +export const tenantsQueries = { withClient }; diff --git a/packages/manager/modules/backup-agent/src/data/queries/vaults.queries.ts b/packages/manager/modules/backup-agent/src/data/queries/vaults.queries.ts new file mode 100644 index 000000000000..f5e8aed06f12 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/queries/vaults.queries.ts @@ -0,0 +1,36 @@ +import { QueryClient, queryOptions } from '@tanstack/react-query'; + +import { getVaultDetails, getVaults } from '@/data/api/vaults/vault.requests'; + +import { queryKeys } from './queryKeys'; +import { servicesQueries } from './services.queries'; + +// ─── Standalone functions (all need QueryClient for dependency resolution) ─── + +const list = (queryClient: QueryClient) => () => + queryOptions({ + queryKey: queryKeys.vaults.all, + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + return getVaults(backupServicesId!); + }, + }); + +const detail = (queryClient: QueryClient) => (vaultId: string) => + queryOptions({ + queryKey: queryKeys.vaults.detail(vaultId), + queryFn: async () => { + const backupServicesId = await servicesQueries.withClient(queryClient).backupServicesId(); + return getVaultDetails(backupServicesId!, vaultId); + }, + enabled: !!vaultId, + }); + +// ─── Factory ─── + +const withClient = (queryClient: QueryClient) => ({ + list: list(queryClient), + detail: detail(queryClient), +}); + +export const vaultsQueries = { withClient }; diff --git a/packages/manager/modules/backup-agent/src/data/selectors/__tests__/consumption.selectors.test.ts b/packages/manager/modules/backup-agent/src/data/selectors/__tests__/consumption.selectors.test.ts new file mode 100644 index 000000000000..b396ab8841c0 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/selectors/__tests__/consumption.selectors.test.ts @@ -0,0 +1,37 @@ +import { mockServiceConsumption } from '@/mocks/services/consumptions'; + +import { selectConsumptionPriceText, selectConsumptionQuantity } from '../consumption.selectors'; + +const consumptionsWithoutVaultPlan = mockServiceConsumption.filter( + (c) => c.planCode !== 'backup-vault-paygo-consumption', +); + +describe('consumption.selectors', () => { + describe('selectConsumptionQuantity', () => { + it('returns the quantity for VAULT_PLAN_CODE', () => { + expect(selectConsumptionQuantity(mockServiceConsumption)).toBe(500); + }); + + it('returns 0 when no matching plan code', () => { + expect(selectConsumptionQuantity(consumptionsWithoutVaultPlan)).toBe(0); + }); + + it('returns 0 for empty array', () => { + expect(selectConsumptionQuantity([])).toBe(0); + }); + }); + + describe('selectConsumptionPriceText', () => { + it('returns the price text for VAULT_PLAN_CODE', () => { + expect(selectConsumptionPriceText(mockServiceConsumption)).toBe('0.15 €'); + }); + + it('returns "-" when no matching plan code', () => { + expect(selectConsumptionPriceText(consumptionsWithoutVaultPlan)).toBe('-'); + }); + + it('returns "-" for empty array', () => { + expect(selectConsumptionPriceText([])).toBe('-'); + }); + }); +}); diff --git a/packages/manager/modules/backup-agent/src/data/selectors/__tests__/vaults.selectors.test.ts b/packages/manager/modules/backup-agent/src/data/selectors/__tests__/vaults.selectors.test.ts new file mode 100644 index 000000000000..3a890ebae9b7 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/selectors/__tests__/vaults.selectors.test.ts @@ -0,0 +1,27 @@ +import { mockVaults } from '@/mocks/vaults/vaults.mock'; + +import { selectVaultBuckets, selectVaultName, selectVaultRegion } from '../vaults.selectors'; + +describe('vaults.selectors', () => { + const vaultResource = mockVaults[0]!; + + describe('selectVaultBuckets', () => { + it('returns the buckets from vault resource', () => { + const buckets = selectVaultBuckets(vaultResource); + expect(buckets).toHaveLength(5); + expect(buckets[0]!.name).toBe('production-primary-bucket'); + }); + }); + + describe('selectVaultName', () => { + it('returns the vault name', () => { + expect(selectVaultName(vaultResource)).toBe('production-backup-vaults-primary'); + }); + }); + + describe('selectVaultRegion', () => { + it('returns the vault region', () => { + expect(selectVaultRegion(vaultResource)).toBe('eu-central-waw'); + }); + }); +}); diff --git a/packages/manager/modules/backup-agent/src/data/selectors/consumption.selectors.ts b/packages/manager/modules/backup-agent/src/data/selectors/consumption.selectors.ts new file mode 100644 index 000000000000..0d4af298b2ee --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/selectors/consumption.selectors.ts @@ -0,0 +1,8 @@ +import { VAULT_PLAN_CODE } from '@/module.constants'; +import { ServiceConsumption } from '@/types/Consumption.type'; + +export const selectConsumptionQuantity = (consumptions: ServiceConsumption[]): number => + consumptions.find((consumption) => consumption.planCode === VAULT_PLAN_CODE)?.quantity ?? 0; + +export const selectConsumptionPriceText = (consumptions: ServiceConsumption[]): string => + consumptions.find((consumption) => consumption.planCode === VAULT_PLAN_CODE)?.price.text ?? '-'; diff --git a/packages/manager/modules/backup-agent/src/data/selectors/vaults.selectors.ts b/packages/manager/modules/backup-agent/src/data/selectors/vaults.selectors.ts new file mode 100644 index 000000000000..c6121da7bc26 --- /dev/null +++ b/packages/manager/modules/backup-agent/src/data/selectors/vaults.selectors.ts @@ -0,0 +1,8 @@ +import { Bucket } from '@/types/Bucket.type'; +import { VaultResource } from '@/types/Vault.type'; + +export const selectVaultBuckets = (vault: VaultResource): Bucket[] => vault.currentState.buckets; + +export const selectVaultName = (vault: VaultResource): string => vault.currentState.name; + +export const selectVaultRegion = (vault: VaultResource): string => vault.currentState.region; diff --git a/packages/manager/modules/backup-agent/src/pages/MainLayout.component.tsx b/packages/manager/modules/backup-agent/src/pages/MainLayout.component.tsx index 8de148bab6c7..dd78eaad914d 100644 --- a/packages/manager/modules/backup-agent/src/pages/MainLayout.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/MainLayout.component.tsx @@ -2,7 +2,7 @@ import React, { Suspense, useContext, useMemo } from 'react'; import { NavLink, Outlet, useLocation } from 'react-router-dom'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsTab, OdsTabs } from '@ovhcloud/ods-components/react'; @@ -18,7 +18,7 @@ import { import { useOvhTracking } from '@ovh-ux/manager-react-shell-client'; import { BackupAgentContext } from '@/BackupAgent.context'; -import { useBackupVaultsListOptions } from '@/data/hooks/vaults/getVault'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; import { useMainGuideItem } from '@/hooks/useMainGuideItem'; import { LABELS } from '@/module.constants'; import { urls } from '@/routes/routes.constants'; @@ -32,6 +32,7 @@ export default function MainLayout() { const location = useLocation(); const { trackClick } = useOvhTracking(); + const queryClient = useQueryClient(); const tabs = useDashboardTabs(); const activeTab = useMemo( @@ -44,7 +45,7 @@ export default function MainLayout() { data: isBackupAgentReady, isError: isVautError, } = useQuery({ - ...useBackupVaultsListOptions(), + ...vaultsQueries.withClient(queryClient).list(), retry: false, select: (vaults) => vaults.filter((vault) => vault.currentState.status === 'READY').length >= 1, }); diff --git a/packages/manager/modules/backup-agent/src/pages/billing/listing/Listing.page.tsx b/packages/manager/modules/backup-agent/src/pages/billing/listing/Listing.page.tsx index 96dad2710f65..fb845978c289 100644 --- a/packages/manager/modules/backup-agent/src/pages/billing/listing/Listing.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/billing/listing/Listing.page.tsx @@ -1,5 +1,6 @@ import React, { Suspense } from 'react'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { Trans, useTranslation } from 'react-i18next'; import { OdsText } from '@ovhcloud/ods-components/react'; @@ -8,15 +9,16 @@ import { Datagrid, Links } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { ReloadButton } from '@/components/ReloadButton/ReloadButton.component'; -import { SERVICE_CONSUMPTION_QUERY_KEY } from '@/data/hooks/consumption/useServiceConsumption'; -import { BACKUP_VAULTS_LIST_QUERY_KEY, useBackupVaultsList } from '@/data/hooks/vaults/getVault'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; import { useGuideUtils } from '@/hooks/useGuideUtils'; import { useColumns } from './_hooks/useBillingListingColumns.hooks'; export default function ListingPage() { const { t } = useTranslation(BACKUP_AGENT_NAMESPACES.VAULT_LISTING); - const { data, isPending } = useBackupVaultsList(); + const queryClient = useQueryClient(); + const { data, isPending } = useQuery(vaultsQueries.withClient(queryClient).list()); const columns = useColumns(); const guide = useGuideUtils(); @@ -44,7 +46,7 @@ export default function ListingPage() {
} diff --git a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingPriceCell.components.tsx b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingPriceCell.components.tsx index fe5b88d0d7d8..6b73c66797a0 100644 --- a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingPriceCell.components.tsx +++ b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingPriceCell.components.tsx @@ -1,19 +1,20 @@ import React from 'react'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { OdsSkeleton } from '@ovhcloud/ods-components/react'; import { DataGridTextCell } from '@ovh-ux/manager-react-components'; -import { useGetServiceConsumptionOptions } from '@/data/hooks/consumption/useServiceConsumption'; +import { consumptionQueries } from '@/data/queries/consumption.queries'; import { VAULT_PLAN_CODE } from '@/module.constants'; export type BillingPriceCellProps = { vaultId: string }; export const BillingPriceCell = ({ vaultId }: BillingPriceCellProps) => { + const queryClient = useQueryClient(); const { data: priceText, isPending } = useQuery({ - ...useGetServiceConsumptionOptions()(vaultId), + ...consumptionQueries.withClient(queryClient).byResource(vaultId), select: (consumptions) => consumptions?.find((consumption) => consumption.planCode === VAULT_PLAN_CODE)?.price.text, }); diff --git a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingUsageCell.components.tsx b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingUsageCell.components.tsx index 84eb46686a2c..def59a511e94 100644 --- a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingUsageCell.components.tsx +++ b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/BillingUsageCell.components.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsSkeleton } from '@ovhcloud/ods-components/react'; @@ -8,15 +8,16 @@ import { OdsSkeleton } from '@ovhcloud/ods-components/react'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; import { DataGridTextCell } from '@ovh-ux/manager-react-components'; -import { useGetServiceConsumptionOptions } from '@/data/hooks/consumption/useServiceConsumption'; +import { consumptionQueries } from '@/data/queries/consumption.queries'; import { VAULT_PLAN_CODE } from '@/module.constants'; export type BillingUsageCellProps = { vaultId: string }; export const BillingUsageCell = ({ vaultId }: BillingUsageCellProps) => { const { t } = useTranslation([NAMESPACES.BYTES]); + const queryClient = useQueryClient(); const { data: consumptionQuantity, isPending } = useQuery({ - ...useGetServiceConsumptionOptions()(vaultId), + ...consumptionQueries.withClient(queryClient).byResource(vaultId), select: (consumptions) => consumptions.find((consumption) => consumption.planCode === VAULT_PLAN_CODE)?.quantity, }); diff --git a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingPriceCell.component.test.tsx b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingPriceCell.component.test.tsx index be2cf625f3d4..c8117d8d7af3 100644 --- a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingPriceCell.component.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingPriceCell.component.test.tsx @@ -1,17 +1,18 @@ import React from 'react'; +import { QueryClient } from '@tanstack/react-query'; import { render, screen } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { VAULT_PLAN_CODE } from '@/module.constants'; import { DataGridTextCellMock } from '@/test-utils/mocks/manager-react-components'; import { OdsSkeletonMock } from '@/test-utils/mocks/ods-components'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { BillingPriceCell } from '../BillingPriceCell.components'; -const { mockUseQuery } = vi.hoisted(() => ({ - mockUseQuery: vi.fn(), -})); - vi.mock('@ovh-ux/manager-react-components', () => ({ DataGridTextCell: DataGridTextCellMock, })); @@ -20,33 +21,36 @@ vi.mock('@ovhcloud/ods-components/react', () => ({ OdsSkeleton: OdsSkeletonMock, })); -vi.mock('@/data/hooks/consumption/useServiceConsumption', () => ({ - useGetServiceConsumptionOptions: vi.fn(() => vi.fn()), -})); +describe('BillingPriceCell', () => { + let queryClient: QueryClient; -vi.mock('@tanstack/react-query', () => ({ - useQuery: mockUseQuery, -})); + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); -describe('BillingPriceCell', () => { - it('should display price when data is present', () => { - mockUseQuery.mockReturnValue({ - data: '30.00 €', - isPending: false, - }); + beforeEach(() => { + queryClient = createQueryClientTest(); + }); + + it('should display price when data is present', async () => { + queryClient.setQueryData(queryKeys.consumption.byResource('vault-id'), [ + { + planCode: VAULT_PLAN_CODE, + price: { text: '30.00 €' }, + }, + ]); - render(); + const wrapper = await buildWrapper(); + + render(, { wrapper }); expect(screen.getByText('30.00 €')).toBeVisible(); }); - it('should display skeleton during loading', () => { - mockUseQuery.mockReturnValue({ - data: undefined, - isPending: true, - }); + it('should display skeleton during loading', async () => { + // Don't seed the cache so the query stays in pending state + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); expect(screen.getByTestId('ods-skeleton')).toBeVisible(); }); diff --git a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingUsageCell.component.test.tsx b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingUsageCell.component.test.tsx index e164038c454a..897a96664638 100644 --- a/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingUsageCell.component.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/billing/listing/_components/__tests__/BillingUsageCell.component.test.tsx @@ -1,18 +1,19 @@ import React from 'react'; +import { QueryClient } from '@tanstack/react-query'; import { render, screen } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { VAULT_PLAN_CODE } from '@/module.constants'; import { DataGridTextCellMock } from '@/test-utils/mocks/manager-react-components'; import { OdsSkeletonMock } from '@/test-utils/mocks/ods-components'; import { useTranslationMock } from '@/test-utils/mocks/react-i18next'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { BillingUsageCell } from '../BillingUsageCell.components'; -const { mockUseQuery } = vi.hoisted(() => ({ - mockUseQuery: vi.fn(), -})); - vi.mock('@ovh-ux/manager-react-components', () => ({ DataGridTextCell: DataGridTextCellMock, })); @@ -25,48 +26,46 @@ vi.mock('react-i18next', () => ({ useTranslation: useTranslationMock, })); -vi.mock('@/data/hooks/consumption/useServiceConsumption', () => ({ - useGetServiceConsumptionOptions: vi.fn(() => vi.fn()), -})); +describe('BillingUsageCell', () => { + let queryClient: QueryClient; -vi.mock('@/hooks/useGetVaultConsumptionDetails', () => ({ - useGetVaultConsumptionDetails: vi.fn(), -})); + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); -vi.mock('@tanstack/react-query', () => ({ - useQuery: mockUseQuery, -})); + beforeEach(() => { + queryClient = createQueryClientTest(); + }); -describe('BillingUsageCell', () => { - it('should display usage label when data is present', () => { - mockUseQuery.mockReturnValue({ - data: [10], - isPending: false, - }); + it('should display usage label when data is present', async () => { + queryClient.setQueryData(queryKeys.consumption.byResource('vault-id'), [ + { + planCode: VAULT_PLAN_CODE, + quantity: 10, + }, + ]); + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); expect(screen.getByText('10 translated_unit_size_GB')).toBeVisible(); }); - it('should display "-" when consumption details are not present', () => { - mockUseQuery.mockReturnValue({ - data: null, - isPending: false, - }); + it('should display "-" when consumption details are not present', async () => { + queryClient.setQueryData(queryKeys.consumption.byResource('vault-id'), []); - render(); + const wrapper = await buildWrapper(); + + render(, { wrapper }); expect(screen.getByText('-')).toBeVisible(); }); - it('should display skeleton during loading', () => { - mockUseQuery.mockReturnValue({ - data: undefined, - isPending: true, - }); + it('should display skeleton during loading', async () => { + // Don't seed the cache so the query stays in pending state + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); expect(screen.getByTestId('ods-skeleton')).toBeVisible(); }); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/AgentsListing.page.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/AgentsListing.page.tsx index a967dd207c1a..0981fb7da202 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/AgentsListing.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/AgentsListing.page.tsx @@ -2,6 +2,7 @@ import { Suspense } from 'react'; import { Outlet, useNavigate } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { Trans, useTranslation } from 'react-i18next'; import { ODS_BUTTON_SIZE } from '@ovhcloud/ods-components'; @@ -12,7 +13,8 @@ import { Datagrid, Links, ManagerButton } from '@ovh-ux/manager-react-components import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { ReloadButton } from '@/components/ReloadButton/ReloadButton.component'; -import { BACKUP_AGENTS_LIST_QUERY_KEY, useBackupAgentList } from '@/data/hooks/agents/getAgents'; +import { agentsQueries } from '@/data/queries/agents.queries'; +import { queryKeys } from '@/data/queries/queryKeys'; import { useGuideUtils } from '@/hooks/useGuideUtils'; import { BACKUP_AGENT_IAM_RULES } from '@/module.constants'; import { AgentStatusLegend } from '@/pages/services/dashboard/agent/_components/AgentStatusLegend'; @@ -27,8 +29,9 @@ export default function AgentsListingPage() { NAMESPACES.ACTIONS, ]); const navigate = useNavigate(); + const queryClient = useQueryClient(); const columns = useAgentsListingColumnsHooks(); - const { flattenData, isPending } = useBackupAgentList(); + const { data, isPending } = useQuery(agentsQueries.withClient(queryClient).list()); const guide = useGuideUtils(); const handleDownloadButton = () => { @@ -90,16 +93,13 @@ export default function AgentsListingPage() { - + } columns={columns} - items={flattenData || []} - totalItems={flattenData?.length || 0} + items={data || []} + totalItems={data?.length || 0} isLoading={isPending} /> )} diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/AgentDataLocationCell.component.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/AgentDataLocationCell.component.tsx index 281a8d78155b..4759e5169434 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/AgentDataLocationCell.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/AgentDataLocationCell.component.tsx @@ -1,13 +1,24 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; + import { OdsSkeleton } from '@ovhcloud/ods-components/react'; import { DataGridTextCell } from '@ovh-ux/manager-react-components'; import { ResourceLocationCell } from '@/components/CommonCells/ResourceLocationCell/ResourceLocationCell.component'; -import { useBackupVaultDetails } from '@/data/hooks/vaults/getVaultDetails'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; +import { selectVaultRegion } from '@/data/selectors/vaults.selectors'; import { Agent } from '@/types/Agent.type'; export const AgentDataLocationCell = ({ vaultId }: Pick) => { - const { data, isPending, isError } = useBackupVaultDetails({ vaultId }); + const queryClient = useQueryClient(); + const { + data: region, + isPending, + isError, + } = useQuery({ + ...vaultsQueries.withClient(queryClient).detail(vaultId!), + select: selectVaultRegion, + }); if (!vaultId || isError) { return -; @@ -17,5 +28,5 @@ export const AgentDataLocationCell = ({ vaultId }: Pick) => { return ; } - return ; + return ; }; diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/__tests__/AgentDataLocationCell.component.test.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/__tests__/AgentDataLocationCell.component.test.tsx index 0dfd6a86f903..055228d09fe1 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/__tests__/AgentDataLocationCell.component.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/_components/__tests__/AgentDataLocationCell.component.test.tsx @@ -1,17 +1,14 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { QueryClient } from '@tanstack/react-query'; +import { render, screen, waitFor } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; -import { AgentDataLocationCell } from '../AgentDataLocationCell.component'; - -const { useBackupVaultDetailsMock } = vi.hoisted(() => ({ - useBackupVaultDetailsMock: vi.fn(), -})); +import { queryKeys } from '@/data/queries/queryKeys'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; -vi.mock('@/data/hooks/vaults/getVaultDetails', () => ({ - useBackupVaultDetails: useBackupVaultDetailsMock, -})); +import { AgentDataLocationCell } from '../AgentDataLocationCell.component'; vi.mock('@ovh-ux/manager-react-components', () => ({ DataGridTextCell: ({ children }: { children: React.ReactNode }) => ( @@ -30,52 +27,58 @@ vi.mock('@/components/CommonCells/ResourceLocationCell/ResourceLocationCell.comp })); describe('AgentDataLocationCell', () => { - it('renders "-" when vaultId is not provided', () => { - useBackupVaultDetailsMock.mockReturnValue({ - data: undefined, - isPending: true, - }); + let queryClient: QueryClient; - render(); + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + + beforeEach(() => { + queryClient = createQueryClientTest(); + }); + + it('renders "-" when vaultId is not provided', async () => { + const wrapper = await buildWrapper(); + + render(, { wrapper }); expect(screen.getByTestId('DataGridTextCell')).toHaveTextContent('-'); }); - it('renders OdsSkeleton when isPending is true', () => { - useBackupVaultDetailsMock.mockReturnValue({ - data: undefined, - isPending: true, - }); + it('renders OdsSkeleton when isPending is true', async () => { + // Don't seed the cache so the query stays in pending state + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); expect(screen.getByTestId('OdsSkeleton')).toBeInTheDocument(); }); - it('renders OdsSkeleton when data is not available', () => { - useBackupVaultDetailsMock.mockReturnValue({ - data: undefined, - isPending: false, - isError: true, + it('renders "-" when data is not available (error)', async () => { + // Seed the cache with an error state + queryClient.setQueryDefaults(queryKeys.vaults.detail('vault-id'), { retry: false }); + await queryClient.prefetchQuery({ + queryKey: queryKeys.vaults.detail('vault-id'), + queryFn: () => Promise.reject(new Error('fail')), }); - render(); + const wrapper = await buildWrapper(); - expect(screen.getByText('-')).toBeInTheDocument(); + render(, { wrapper }); + + await waitFor(() => expect(screen.getByText('-')).toBeInTheDocument()); }); - it('renders ResourceLocationCell when data is available', () => { + it('renders ResourceLocationCell when data is available', async () => { const mockData = { currentState: { region: 'GRA', }, }; - useBackupVaultDetailsMock.mockReturnValue({ - data: mockData, - isPending: false, - }); + queryClient.setQueryData(queryKeys.vaults.detail('vault-id'), mockData); + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); expect(screen.getByTestId('ResourceLocationCell')).toHaveTextContent('GRA'); }); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/AddConfiguration.page.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/AddConfiguration.page.tsx index 374e1dc7c807..efc8f2178cfd 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/AddConfiguration.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/AddConfiguration.page.tsx @@ -3,7 +3,7 @@ import { useCallback, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useForm, useWatch } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { z } from 'zod'; @@ -17,10 +17,10 @@ import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { BaremetalOption } from '@/components/CommonFields/BaremetalOption/BaremetalOption.component'; import { DownloadCode } from '@/components/DownloadCode/DownloadCode.component'; import { RhfField } from '@/components/Fields/RhfField.component'; -import { useBackupVSPCTenantAgentDownloadLink } from '@/data/hooks/agents/getDownloadLinkAgent'; -import { useAddConfigurationVSPCTenantAgent } from '@/data/hooks/agents/postAgent'; -import { useBaremetalsList } from '@/data/hooks/baremetal/useBaremetalsList'; -import { useVSPCTenantsOptions } from '@/data/hooks/tenants/useVspcTenants'; +import { useAddConfigurationVSPCTenantAgent } from '@/data/hooks/useAddConfigurationVSPCTenantAgent'; +import { agentsQueries } from '@/data/queries/agents.queries'; +import { baremetalsQueries } from '@/data/queries/baremetals.queries'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; import { OS_LABELS } from '@/module.constants'; import { OS } from '@/types/Os.type'; import { getProductResourceNames } from '@/utils/getProductResourceNamesSet'; @@ -39,6 +39,7 @@ const AddConfigurationPage = () => { NAMESPACES.ACTIONS, ]); const navigate = useNavigate(); + const queryClient = useQueryClient(); const goBack = () => navigate('..'); const [formSubmitError, setFormSubmitError] = useState(); const { @@ -56,14 +57,14 @@ const AddConfigurationPage = () => { }); const { data: productNameExcluded, isPending: isProductNameExcludedPending } = useQuery({ - ...useVSPCTenantsOptions(), + ...tenantsQueries.withClient(queryClient).vspcAll(), select: (data) => getProductResourceNames(data), }); - const { flattenData, isPending } = useBaremetalsList(); + const { data, isPending } = useQuery(baremetalsQueries.all()); const baremetalList = !isProductNameExcludedPending && !isPending - ? flattenData.filter(({ name }) => !productNameExcluded?.has(name)) + ? (data ?? []).filter(({ name }) => !productNameExcluded?.has(name)) : []; const { @@ -98,8 +99,19 @@ const AddConfigurationPage = () => { const os = useWatch({ name: 'os', control }); - const { data: downloadLink, isLoading: isLoadingDownloadLink } = - useBackupVSPCTenantAgentDownloadLink({ os: os as OS | undefined }); + const { data: downloadLink, isPending: isLoadingDownloadLink } = useQuery({ + ...agentsQueries.withClient(queryClient).downloadLink(), + enabled: !!os, + select: (downloadData) => { + switch (os) { + case 'WINDOWS': + return downloadData.windowsUrl; + case 'LINUX': + default: + return downloadData.linuxUrl; + } + }, + }); const formRef = useRef(null); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/__tests__/AddConfiguration.test.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/__tests__/AddConfiguration.test.tsx index 0c79d37d46c1..6c0939625f10 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/__tests__/AddConfiguration.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/add-configuration/__tests__/AddConfiguration.test.tsx @@ -1,9 +1,11 @@ import React from 'react'; +import { QueryClient } from '@tanstack/react-query'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { vi } from 'vitest'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockAgentDownloadLinks } from '@/mocks/agents/agentDownloadLinks'; import { BAREMETALS_MOCK } from '@/mocks/baremetals/baremetals.mocks'; import { TENANTS_MOCKS } from '@/mocks/tenant/tenants.mock'; @@ -21,6 +23,8 @@ import { } from '@/test-utils/mocks/ods-components'; import { useTranslationMock } from '@/test-utils/mocks/react-i18next'; import { LinkMock, useNavigateMock } from '@/test-utils/mocks/react-router-dom'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import AddConfigurationPage from '../AddConfiguration.page'; @@ -52,56 +56,19 @@ vi.mock('@ovh-ux/manager-react-components', () => ({ Drawer: DrawerMock, })); -const { - useBaremetalsListMock, - useBackupVSPCTenantAgentDownloadLinkMock, - useAddConfigurationVSPCTenantAgentMock, - useQueryMock, -} = vi.hoisted(() => ({ - useBaremetalsListMock: vi - .fn() - .mockReturnValue({ flattenData: undefined, isPending: true, isError: false }), - useBackupVSPCTenantAgentDownloadLinkMock: vi.fn(), +const { useAddConfigurationVSPCTenantAgentMock } = vi.hoisted(() => ({ useAddConfigurationVSPCTenantAgentMock: vi.fn().mockReturnValue({ mutate: vi.fn(), isPending: false, isSuccess: false, isError: false, }), - useQueryMock: vi.fn().mockReturnValue({ data: new Set(), isPending: false, isError: false }), })); -vi.mock('@/data/hooks/tenants/useVspcTenants', () => ({ - useVSPCTenantsOptions: vi.fn().mockReturnValue({}), +vi.mock('@/data/hooks/useAddConfigurationVSPCTenantAgent', () => ({ + useAddConfigurationVSPCTenantAgent: useAddConfigurationVSPCTenantAgentMock, })); -vi.mock('@/data/hooks/tenants/useVspcTenantId', () => ({ - useGetVspcTenantId: vi.fn().mockReturnValue(vi.fn().mockResolvedValue(TENANTS_MOCKS[0]!.id)), - useVspcTenantId: vi.fn().mockReturnValue({ data: TENANTS_MOCKS[0]!.id }), -})); - -vi.mock('@tanstack/react-query', () => ({ - useQuery: useQueryMock, -})); - -vi.mock('@/data/hooks/baremetal/useBaremetalsList', () => { - return { - useBaremetalsList: useBaremetalsListMock, - }; -}); - -vi.mock('@/data/hooks/agents/postAgent', () => { - return { - useAddConfigurationVSPCTenantAgent: useAddConfigurationVSPCTenantAgentMock, - }; -}); - -vi.mock('@/data/hooks/agents/getDownloadLinkAgent', () => { - return { - useBackupVSPCTenantAgentDownloadLink: useBackupVSPCTenantAgentDownloadLinkMock, - }; -}); - vi.mock('@/hooks/useRequiredParams', () => { return { useRequiredParams: vi.fn().mockReturnValue({ @@ -114,20 +81,30 @@ const getSelectServer = () => screen.getByTestId('select-server'); const getSelectOs = () => screen.getByTestId('select-os'); describe('FirstOrderFormComponent', () => { + let queryClient: QueryClient; + + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + + const seedCommonData = ({ withBaremetals = true } = {}) => { + if (withBaremetals) { + queryClient.setQueryData(queryKeys.baremetals.all, BAREMETALS_MOCK); + } + queryClient.setQueryData(queryKeys.tenants.vspc.all(), TENANTS_MOCKS); + queryClient.setQueryData(queryKeys.agents.downloadLink(), mockAgentDownloadLinks); + }; + + beforeEach(() => { + queryClient = createQueryClientTest(); + }); + it.each([[true], [false]])( 'renders onboarding and expected disabled if no baremetal : $expectedDisabled', async (isPendingMock) => { - useBaremetalsListMock.mockReturnValue({ - flattenData: BAREMETALS_MOCK, - isPending: isPendingMock, - isError: false, - }); - useBackupVSPCTenantAgentDownloadLinkMock.mockReturnValue({ - data: mockAgentDownloadLinks.linuxUrl, - isPending: false, - }); - - render(); + seedCommonData({ withBaremetals: !isPendingMock }); + + const wrapper = await buildWrapper(); + + render(, { wrapper }); await waitFor( () => expect(getSelectServer()).toHaveAttribute('data-disabled', `${isPendingMock}`), @@ -137,18 +114,13 @@ describe('FirstOrderFormComponent', () => { ); it('renders onboarding and expected generate order link', async () => { - useBaremetalsListMock.mockReturnValue({ - flattenData: BAREMETALS_MOCK, - isPending: false, - isError: false, - }); - useBackupVSPCTenantAgentDownloadLinkMock.mockReturnValue({ - data: mockAgentDownloadLinks.linuxUrl, - isPending: false, - }); + seedCommonData(); + + const wrapper = await buildWrapper(); + const user = userEvent.setup(); - render(); + render(, { wrapper }); await waitFor(() => expect(getSelectServer().children.length).toBe(BAREMETALS_MOCK.length)); await waitFor(() => expect(getSelectOs().children.length).toBe(Object.keys(OS_LABELS).length)); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/delete/DeleteAgent.page.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/delete/DeleteAgent.page.tsx index 8d3386984af0..1746309be25c 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/delete/DeleteAgent.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/delete/DeleteAgent.page.tsx @@ -1,5 +1,6 @@ import { useNavigate, useParams } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { Trans, useTranslation } from 'react-i18next'; import { ODS_MODAL_COLOR } from '@ovhcloud/ods-components'; @@ -9,17 +10,18 @@ import { NAMESPACES } from '@ovh-ux/manager-common-translations'; import { Modal, useNotifications } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useBackupVSPCTenantAgentDetails } from '@/data/hooks/agents/getAgentDetails'; -import { useDeleteTenantAgent } from '@/data/hooks/agents/useDeleteAgent'; +import { useDeleteTenantAgent } from '@/data/hooks/useDeleteTenantAgent'; +import { agentsQueries } from '@/data/queries/agents.queries'; export default function DeleteAgentPage() { const { t } = useTranslation([BACKUP_AGENT_NAMESPACES.AGENT, NAMESPACES.ACTIONS]); const navigate = useNavigate(); + const queryClient = useQueryClient(); const closeModal = () => navigate('..'); const { addSuccess, addError } = useNotifications(); const { agentId } = useParams<{ agentId: string }>(); - const { data } = useBackupVSPCTenantAgentDetails({ agentId: agentId! }); + const { data } = useQuery(agentsQueries.withClient(queryClient).detail(agentId!)); const { mutate: deleteAgent, isPending } = useDeleteTenantAgent({ onSuccess: () => diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/AgentDownload.page.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/AgentDownload.page.tsx index 674625b702ec..ed78afc47fe7 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/AgentDownload.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/AgentDownload.page.tsx @@ -2,6 +2,7 @@ import { useId, useState } from 'react'; import { useNavigate } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { ODS_MODAL_COLOR } from '@ovhcloud/ods-components'; @@ -18,7 +19,7 @@ import { Modal } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { DownloadCode } from '@/components/DownloadCode/DownloadCode.component'; -import { useBackupVSPCTenantAgentDownloadLink } from '@/data/hooks/agents/getDownloadLinkAgent'; +import { agentsQueries } from '@/data/queries/agents.queries'; import { OS_LABELS } from '@/module.constants'; import { OS } from '@/types/Os.type'; @@ -27,10 +28,21 @@ export default function DownloadAgentPage() { const [osSelected, setOsSelected] = useState(null); const { t } = useTranslation([BACKUP_AGENT_NAMESPACES.AGENT, NAMESPACES.ACTIONS]); const navigate = useNavigate(); + const queryClient = useQueryClient(); const closeModal = () => navigate('..'); - const { data: downloadLink, isLoading } = useBackupVSPCTenantAgentDownloadLink({ - os: osSelected, + const { data: downloadLink, isPending: isLoading } = useQuery({ + ...agentsQueries.withClient(queryClient).downloadLink(), + enabled: !!osSelected, + select: (data) => { + switch (osSelected) { + case 'WINDOWS': + return data.windowsUrl; + case 'LINUX': + default: + return data.linuxUrl; + } + }, }); const handleChangeDownloadLink = (osKey: OS) => { diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/__tests__/AgentDownload.test.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/__tests__/AgentDownload.test.tsx index 922204a8b008..43249c52e529 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/__tests__/AgentDownload.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/download/__tests__/AgentDownload.test.tsx @@ -1,18 +1,17 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { queryKeys } from '@/data/queries/queryKeys'; import { BACKUP_AGENT_NAMESPACES } from '@/lib'; import { mockAgentDownloadLinks } from '@/mocks/agents/agentDownloadLinks'; import { TENANTS_MOCKS } from '@/mocks/tenant/tenants.mock'; import DownloadAgentPage from '@/pages/services/dashboard/agent/download/AgentDownload.page'; - -const { useBackupVSPCTenantAgentDownloadLinkMock } = vi.hoisted(() => ({ - useBackupVSPCTenantAgentDownloadLinkMock: vi.fn(), -})); +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; const codeTestId = 'ods-code'; -// --- Mock translation --- +// --- Mock ODS --- vi.mock('@ovhcloud/ods-components/react', async () => { const actual = await vi.importActual('@ovhcloud/ods-components/react'); @@ -115,16 +114,6 @@ vi.mock('@/hooks/useRequiredParams', () => { }; }); -vi.mock('@/data/hooks/agents/getDownloadLinkAgent', () => { - return { - useBackupVSPCTenantAgentDownloadLink: useBackupVSPCTenantAgentDownloadLinkMock, - }; -}); - -vi.mock('@/data/hooks/tenants/useVspcTenantId', () => ({ - useVspcTenantId: vi.fn().mockReturnValue({ data: TENANTS_MOCKS[0]!.id }), -})); - const getSelectOs = () => screen.getByRole('combobox', { name: `translated_${BACKUP_AGENT_NAMESPACES.AGENT}:select_os` }); @@ -132,12 +121,14 @@ describe('AgentDownload', () => { it('Should render AgentDownload component', async () => { const emptyLinkLabel = 'curl -O "..."'; + const queryClient = createQueryClientTest(); + queryClient.setQueryData(queryKeys.agents.downloadLink(), mockAgentDownloadLinks); + + const wrapper = await testWrapperBuilder().withQueryClient(queryClient).build(); + const user = userEvent.setup(); - useBackupVSPCTenantAgentDownloadLinkMock.mockReturnValue({ - data: mockAgentDownloadLinks.linuxUrl, - isLoading: false, - }); - render(); + + render(, { wrapper }); await waitFor(() => expect( @@ -147,34 +138,17 @@ describe('AgentDownload', () => { expect(getSelectOs()).toBeVisible(); - expect(getSelectOs()).toHaveValue('LINUX'); - - expect(useBackupVSPCTenantAgentDownloadLinkMock).toHaveBeenCalledWith({ - os: null, - }); - + // Initially no OS selected → download code shows "..." expect(screen.getAllByTestId(codeTestId)[0]).toHaveTextContent(emptyLinkLabel); - // Prepare mock for change value - useBackupVSPCTenantAgentDownloadLinkMock.mockReturnValue({ - data: mockAgentDownloadLinks.windowsUrl, - isLoading: false, - }); - useBackupVSPCTenantAgentDownloadLinkMock.mockClear(); - - // Test update value on click on windows + // Select WINDOWS await user.selectOptions(getSelectOs(), ['WINDOWS']); - expect(useBackupVSPCTenantAgentDownloadLinkMock).toHaveBeenCalledWith({ - os: 'WINDOWS', - }); - - expect(screen.getAllByTestId(codeTestId)[0]).not.toHaveTextContent( - mockAgentDownloadLinks.linuxUrl, - ); - - expect(screen.getAllByTestId(codeTestId)[0]).toHaveTextContent( - mockAgentDownloadLinks.windowsUrl, + // After selecting WINDOWS, the download link should show the windows URL + await waitFor(() => + expect(screen.getAllByTestId(codeTestId)[0]).toHaveTextContent( + mockAgentDownloadLinks.windowsUrl, + ), ); }); }); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/EditConfiguration.page.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/EditConfiguration.page.tsx index e211381f89b6..61fa3acf978f 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/EditConfiguration.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/EditConfiguration.page.tsx @@ -3,6 +3,7 @@ import { useContext, useRef, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { zodResolver } from '@hookform/resolvers/zod'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import capitalize from 'lodash.capitalize'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -16,9 +17,9 @@ import { Drawer, ErrorBoundary, useNotifications } from '@ovh-ux/manager-react-c import { BackupAgentContext } from '@/BackupAgent.context'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { RhfField } from '@/components/Fields/RhfField.component'; -import { useBackupVSPCTenantAgentDetails } from '@/data/hooks/agents/getAgentDetails'; -import { useEditConfigurationVSPCTenantAgent } from '@/data/hooks/agents/putAgent'; -import { useBackupTenantPolicies } from '@/data/hooks/tenants/useVspcTenantBackupPolicies'; +import { useEditConfigurationVSPCTenantAgent } from '@/data/hooks/useEditConfigurationVSPCTenantAgent'; +import { agentsQueries } from '@/data/queries/agents.queries'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; import { LABELS } from '@/module.constants'; const FORM_ID = 'form-link-agent-title' as const; @@ -44,19 +45,20 @@ export const EditConfigurationPage = () => { const { appName } = useContext(BackupAgentContext); const navigate = useNavigate(); + const queryClient = useQueryClient(); const goBack = () => navigate('..'); const { data: resourceAgent, - isLoading, + isPending: isLoading, error, isSuccess, refetch, - } = useBackupVSPCTenantAgentDetails({ - agentId: agentId!, - }); + } = useQuery(agentsQueries.withClient(queryClient).detail(agentId!)); const isAgentEnabled = resourceAgent?.status === 'ENABLED'; - const { data: policies, isLoading: isPoliciesLoading } = useBackupTenantPolicies(); + const { data: policies, isPending: isPoliciesLoading } = useQuery( + tenantsQueries.withClient(queryClient).vspcPolicies(), + ); const { mutate, isPending } = useEditConfigurationVSPCTenantAgent({ onSuccess: () => { diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/__tests__/EditConfiguration.test.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/__tests__/EditConfiguration.test.tsx index 16bb5865879e..b9aa169b6d9f 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/__tests__/EditConfiguration.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/agent/edit-configuration/__tests__/EditConfiguration.test.tsx @@ -1,14 +1,18 @@ import React from 'react'; +import { QueryClient } from '@tanstack/react-query'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { vi } from 'vitest'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockAgents } from '@/mocks/agents/agents'; import { mockTenantBackupPolicies } from '@/mocks/tenant/backupPolicies.mock'; import { TENANTS_MOCKS } from '@/mocks/tenant/tenants.mock'; import { EditConfigurationPage } from '@/pages/services/dashboard/agent/edit-configuration/EditConfiguration.page'; import { useParamsMock } from '@/test-utils/mocks/react-router-dom'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; vi.mock('react-router-dom', async (importOriginal) => { const actual = await importOriginal(); @@ -71,33 +75,24 @@ vi.mock('@ovh-ux/manager-react-components', async (importOriginal) => { }; }); -const { - useBackupTenantPoliciesMock, - useBackupVSPCTenantAgentDetailsMock, - useEditConfigurationVSPCTenantAgentMock, - useGetVspcTenantIdMock, -} = vi.hoisted(() => ({ - useBackupTenantPoliciesMock: vi - .fn() - .mockReturnValue({ data: undefined, isLoading: true, isError: false }), +const { useEditConfigurationVSPCTenantAgentMock, getBackupAgentsDetailsMock } = vi.hoisted(() => ({ useEditConfigurationVSPCTenantAgentMock: vi .fn() .mockReturnValue({ isPending: false, mutate: vi.fn() }), - useBackupVSPCTenantAgentDetailsMock: vi.fn(), - useGetVspcTenantIdMock: vi.fn(), -})); - -vi.mock('@/data/hooks/agents/getAgentDetails', () => ({ - useBackupVSPCTenantAgentDetails: useBackupVSPCTenantAgentDetailsMock, + getBackupAgentsDetailsMock: vi.fn(), })); -vi.mock('@/data/hooks/agents/putAgent', () => ({ +vi.mock('@/data/hooks/useEditConfigurationVSPCTenantAgent', () => ({ useEditConfigurationVSPCTenantAgent: useEditConfigurationVSPCTenantAgentMock, })); -vi.mock('@/data/hooks/tenants/useVspcTenantBackupPolicies', () => ({ - useBackupTenantPolicies: useBackupTenantPoliciesMock, -})); +vi.mock('@/data/api/agents/agents.requests', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + getBackupAgentsDetails: getBackupAgentsDetailsMock, + }; +}); const getUnableEditAgentNotEnabledBanner = () => screen.queryByText('translated_unable_edit_agent_not_enabled'); @@ -116,17 +111,16 @@ const getSelectPolicy = () => screen.getByTestId('select-policy'); const getSubmitButton = () => screen.getByRole('button', { name: `translated_edit` }); describe('EditConfigurationComponent', () => { + let queryClient: QueryClient; + + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + beforeAll(() => { useParamsMock.mockReturnValue({ tenantId: TENANTS_MOCKS[0]!.id, agentId: mockAgents[0]!.id }); - useBackupVSPCTenantAgentDetailsMock.mockReturnValue({ - isLoading: false, - isError: false, - isSuccess: true, - data: mockAgents[0]!, - refetch: vi.fn().mockResolvedValue({ data: mockAgents[0]! }), - }); + }); - useGetVspcTenantIdMock.mockReturnValue(vi.fn().mockReturnValue(TENANTS_MOCKS[0]!.id)); + beforeEach(() => { + queryClient = createQueryClientTest(); }); it('renders edit configuration component and see default value', async () => { @@ -135,16 +129,19 @@ describe('EditConfigurationComponent', () => { isPending: false, mutate: mutateMock, }); + getBackupAgentsDetailsMock.mockResolvedValue(mockAgents[0]!); + + queryClient.setQueryData(queryKeys.agents.detail(mockAgents[0]!.id), mockAgents[0]!); + queryClient.setQueryData(queryKeys.tenants.vspc.policies(), mockTenantBackupPolicies); + // Seed dependencies for ensureQueryData resolution during refetch + queryClient.setQueryData(queryKeys.backupServices.all, [{ id: 'backup-service-id' }]); + queryClient.setQueryData(queryKeys.tenants.vspc.all(), [TENANTS_MOCKS[0]!]); + + const wrapper = await buildWrapper(); - useBackupTenantPoliciesMock.mockReturnValue({ - data: mockTenantBackupPolicies, - isLoading: false, - isError: false, - isSuccess: true, - }); const user = userEvent.setup(); - render(); + render(, { wrapper }); expect(getUnableEditAgentNotEnabledBanner()).not.toBeInTheDocument(); @@ -166,31 +163,26 @@ describe('EditConfigurationComponent', () => { }); }); - it('renders edit configuration component and see banner because agent is not enabled', () => { - useBackupVSPCTenantAgentDetailsMock.mockReturnValue({ - isLoading: false, - isError: false, - isSuccess: true, - data: { ...mockAgents[0]!, status: 'NOT_CONFIGURED' }, - refetch: vi.fn().mockResolvedValue({ data: {} }), + it('renders edit configuration component and see banner because agent is not enabled', async () => { + queryClient.setQueryData(queryKeys.agents.detail(mockAgents[0]!.id), { + ...mockAgents[0]!, + status: 'NOT_CONFIGURED', }); - render(); + const wrapper = await buildWrapper(); + + render(, { wrapper }); expect(getUnableEditAgentNotEnabledBanner()).toBeVisible(); expect(getSubmitButton()).toBeDisabled(); }); - it('renders edit configuration loading drawer component', () => { - useBackupVSPCTenantAgentDetailsMock.mockReturnValue({ - isLoading: true, - isError: false, - isSuccess: false, - data: undefined, - refetch: vi.fn().mockResolvedValue({ data: {} }), - }); + it('renders edit configuration loading drawer component', async () => { + // Don't seed agent data — query stays in loading state + + const wrapper = await buildWrapper(); - render(); + render(, { wrapper }); screen.getByRole('heading', { name: `translated_edit_configuration`, diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/delete/DeleteTenant.page.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/delete/DeleteTenant.page.tsx index b4efb8c6229f..b4d7786831c0 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/delete/DeleteTenant.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/delete/DeleteTenant.page.tsx @@ -1,6 +1,6 @@ import { useNavigate } from 'react-router-dom'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { ODS_MODAL_COLOR } from '@ovhcloud/ods-components'; @@ -11,8 +11,8 @@ import { useFeatureAvailability } from '@ovh-ux/manager-module-common-api'; import { Modal, useNotifications } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useDeleteVSPCTenant } from '@/data/hooks/tenants/useDeleteTenant'; -import { useVSPCTenantsOptions } from '@/data/hooks/tenants/useVspcTenants'; +import { useDeleteVSPCTenant } from '@/data/hooks/useDeleteVSPCTenant'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; import { useGetFeaturesAvailabilityNames } from '@/hooks/useGetFeatureAvailability'; export default function DeleteTenantPage() { @@ -20,6 +20,7 @@ export default function DeleteTenantPage() { const navigate = useNavigate(); const closeModal = () => navigate('..'); const { addSuccess, addError } = useNotifications(); + const queryClient = useQueryClient(); const { DELETE_TENANT: deleteAgentFeatureName } = useGetFeaturesAvailabilityNames([ 'DELETE_TENANT', ]); @@ -27,7 +28,7 @@ export default function DeleteTenantPage() { const isDeleteTenantFeatureAvailable = featureAvailabilities?.[deleteAgentFeatureName] ?? false; const { data: vspcName } = useQuery({ - ...useVSPCTenantsOptions(), + ...tenantsQueries.withClient(queryClient).vspcAll(), select: ([vspcTenant]) => vspcTenant?.currentState.name, }); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/GeneralInformation.page.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/GeneralInformation.page.tsx index 9f64a6b32240..6874df653c14 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/GeneralInformation.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/GeneralInformation.page.tsx @@ -1,15 +1,18 @@ import { Outlet, useNavigate } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; + import { BillingInformationsTileStandard } from '@ovh-ux/manager-billing-informations'; -import { useBackupVSPCTenantDetails } from '@/data/hooks/tenants/useVspcTenantDetails'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; import { urls } from '@/routes/routes.constants'; import { GeneralInformationTenantTile } from './_components/general-information-tenant-tile/GeneralInformationTenantTile.component'; import SubscriptionTile from './_components/subscription-tile/SubscriptionTile.component'; export default function GeneralInformationPage() { - const { data: tenantResource } = useBackupVSPCTenantDetails(); + const queryClient = useQueryClient(); + const { data: tenantResource } = useQuery(tenantsQueries.withClient(queryClient).vspcDetail()); const navigate = useNavigate(); return ( diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/__tests__/GeneralInformationTenantTile.test.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/__tests__/GeneralInformationTenantTile.test.tsx index 21fd25ff86b7..91e11f55a911 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/__tests__/GeneralInformationTenantTile.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/__tests__/GeneralInformationTenantTile.test.tsx @@ -1,8 +1,12 @@ +import { QueryClient } from '@tanstack/react-query'; import { render, screen } from '@testing-library/react'; import { vi } from 'vitest'; import { GeneralInformationTileProps } from '@/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component'; +import { queryKeys } from '@/data/queries/queryKeys'; import { TENANTS_MOCKS } from '@/mocks/tenant/tenants.mock'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { GeneralInformationTenantTile } from '../general-information-tenant-tile/GeneralInformationTenantTile.component'; @@ -10,14 +14,6 @@ vi.mock('react-router-dom', () => ({ useHref: vi.fn().mockImplementation((url: string) => url), })); -const { useBackupVSPCTenantDetailsMock } = vi.hoisted(() => ({ - useBackupVSPCTenantDetailsMock: vi.fn(), -})); - -vi.mock('@/data/hooks/tenants/useVspcTenantDetails', () => ({ - useBackupVSPCTenantDetails: useBackupVSPCTenantDetailsMock, -})); - vi.mock( '@/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component', () => ({ @@ -30,18 +26,32 @@ vi.mock( ); describe('GeneralInformationTenantTile', () => { + let queryClient: QueryClient; + + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + + beforeEach(() => { + queryClient = createQueryClientTest(); + }); + it('Should render GeneralInformationTenantTile component', async () => { - useBackupVSPCTenantDetailsMock.mockReturnValue({ data: TENANTS_MOCKS[0]!, isPending: false }); - const { container } = render(); + queryClient.setQueryData(queryKeys.tenants.vspc.detail(), TENANTS_MOCKS[0]!); + + const wrapper = await buildWrapper(); + + const { container } = render(, { wrapper }); await expect(container).toBeAccessible(); expect(screen.getByText(TENANTS_MOCKS[0]!.currentState.name)).toBeVisible(); }); - it('Should render GeneralInformationTenantTile component', async () => { - useBackupVSPCTenantDetailsMock.mockReturnValue({ data: TENANTS_MOCKS[0]!, isPending: true }); - const { container } = render(); + it('Should render GeneralInformationTenantTile component loading', async () => { + // Don't seed data — query stays in pending state + + const wrapper = await buildWrapper(); + + const { container } = render(, { wrapper }); await expect(container).toBeAccessible(); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/general-information-tenant-tile/GeneralInformationTenantTile.component.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/general-information-tenant-tile/GeneralInformationTenantTile.component.tsx index 9423990fb769..af2c9c5211cb 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/general-information-tenant-tile/GeneralInformationTenantTile.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/general-information-tenant-tile/GeneralInformationTenantTile.component.tsx @@ -1,5 +1,6 @@ import { useHref } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsLink, OdsSkeleton } from '@ovhcloud/ods-components/react'; @@ -8,13 +9,16 @@ import { ManagerTile } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { GeneralInformationTile } from '@/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component'; -import { useBackupVSPCTenantDetails } from '@/data/hooks/tenants/useVspcTenantDetails'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; import { LABELS } from '@/module.constants'; import { urls } from '@/routes/routes.constants'; export function GeneralInformationTenantTile() { const { t } = useTranslation(BACKUP_AGENT_NAMESPACES.SERVICE_DASHBOARD); - const { data, isPending, isError } = useBackupVSPCTenantDetails(); + const queryClient = useQueryClient(); + const { data, isPending, isError } = useQuery( + tenantsQueries.withClient(queryClient).vspcDetail(), + ); const resetPasswordHref = useHref(urls.dashboardTenantResetPassword); diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx index 9664cf35adab..b8fde7629ebb 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx @@ -1,3 +1,4 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsSkeleton, OdsText } from '@ovhcloud/ods-components/react'; @@ -6,7 +7,7 @@ import { NAMESPACES } from '@ovh-ux/manager-common-translations'; import { ManagerTile } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useBackupTenantDetails } from '@/data/hooks/tenants/useBackupTenantDetails'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; import { useTenantBackupStats } from './_hooks/useTenantBackupStats'; @@ -16,7 +17,8 @@ const SubscriptionTile = () => { NAMESPACES.BILLING, BACKUP_AGENT_NAMESPACES.SERVICE_DASHBOARD, ]); - const { data, isPending } = useBackupTenantDetails(); + const queryClient = useQueryClient(); + const { data, isPending } = useQuery(tenantsQueries.withClient(queryClient).details()); const { connectedVaultsText, installedAgentsText, diff --git a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/_hooks/useTenantBackupStats.ts b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/_hooks/useTenantBackupStats.ts index e28e4024594b..933dd74c17b7 100644 --- a/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/_hooks/useTenantBackupStats.ts +++ b/packages/manager/modules/backup-agent/src/pages/services/dashboard/general-information/_components/subscription-tile/_hooks/useTenantBackupStats.ts @@ -1,10 +1,12 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useInstalledBackupAgents } from '@/data/hooks/tenants/useVspcTenants'; +import { tenantsQueries } from '@/data/queries/tenants.queries'; import { Resource } from '@/types/Resource.type'; import { Tenant } from '@/types/Tenant.type'; import { WithRegion } from '@/types/Utils.type'; +import { countBackupAgents } from '@/utils/countBackupAgents'; type UseTenantBackupStatsProps = { tenantDetails?: Resource>; @@ -18,7 +20,14 @@ export function useTenantBackupStats({ tenantDetails }: UseTenantBackupStatsProp connectedVaultCount, }); - const { installedBackupAgents, isPending } = useInstalledBackupAgents(); + const queryClient = useQueryClient(); + const { data: vspcTenantDetails, isPending } = useQuery( + tenantsQueries.withClient(queryClient).vspcDetail(), + ); + + const installedBackupAgents = countBackupAgents( + vspcTenantDetails?.currentState ? [vspcTenantDetails.currentState] : [], + ); const installedAgentsText = t('number_of_linked_server', { installedAgentsCount: installedBackupAgents, diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/VaultDashboard.page.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/VaultDashboard.page.tsx index 82543bcce0ad..732b1f906659 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/VaultDashboard.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/VaultDashboard.page.tsx @@ -2,6 +2,7 @@ import React, { Suspense, startTransition, useContext } from 'react'; import { NavLink, Outlet, useNavigate, useParams } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsTab, OdsTabs } from '@ovhcloud/ods-components/react'; @@ -11,7 +12,8 @@ import { BaseLayout, Breadcrumb, GuideButton } from '@ovh-ux/manager-react-compo import { useOvhTracking } from '@ovh-ux/manager-react-shell-client'; import { BackupAgentContext } from '@/BackupAgent.context'; -import { useBackupVaultDetails } from '@/data/hooks/vaults/getVaultDetails'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; +import { selectVaultName } from '@/data/selectors/vaults.selectors'; import { useMainGuideItem } from '@/hooks/useMainGuideItem'; import { useVaultDashboardTabs } from './_hooks/useVaultDashboardTabs'; @@ -19,7 +21,11 @@ import { useVaultDashboardTabs } from './_hooks/useVaultDashboardTabs'; export default function VaultDashboardPage() { const { appName } = useContext(BackupAgentContext); const { vaultId } = useParams<{ vaultId: string }>(); - const { data: vaultResource } = useBackupVaultDetails({ vaultId: vaultId! }); + const queryClient = useQueryClient(); + const { data: vaultName } = useQuery({ + ...vaultsQueries.withClient(queryClient).detail(vaultId!), + select: selectVaultName, + }); const { t } = useTranslation(['common', NAMESPACES.ACTIONS]); const navigate = useNavigate(); @@ -36,7 +42,7 @@ export default function VaultDashboardPage() { return ( , }} backLinkLabel={t(`${NAMESPACES.ACTIONS}:back`)} diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/buckets/VaultBuckets.page.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/buckets/VaultBuckets.page.tsx index 6f43d1b151df..d166be7af4ef 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/buckets/VaultBuckets.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/buckets/VaultBuckets.page.tsx @@ -2,22 +2,26 @@ import React, { Suspense } from 'react'; import { useParams } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { Datagrid } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { ReloadButton } from '@/components/ReloadButton/ReloadButton.component'; -import { - BACKUP_VAULT_DETAILS_QUERY_KEY, - useBackupVaultDetails, -} from '@/data/hooks/vaults/getVaultDetails'; +import { queryKeys } from '@/data/queries/queryKeys'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; +import { selectVaultBuckets } from '@/data/selectors/vaults.selectors'; import { useBucketColumns } from './_hooks/useBucketColumns.hooks'; export default function VaultBucketsPage() { const { vaultId } = useParams<{ vaultId: string }>(); - const { data: vaultResource, isLoading } = useBackupVaultDetails({ vaultId: vaultId! }); + const queryClient = useQueryClient(); + const { data: buckets = [], isPending } = useQuery({ + ...vaultsQueries.withClient(queryClient).detail(vaultId!), + select: selectVaultBuckets, + }); const { t } = useTranslation(BACKUP_AGENT_NAMESPACES.VAULT_LISTING); const columns = useBucketColumns(); @@ -26,15 +30,12 @@ export default function VaultBucketsPage() { - + } columns={columns} - items={vaultResource?.currentState.buckets ?? []} - totalItems={vaultResource?.currentState.buckets.length ?? 0} + items={buckets} + totalItems={buckets.length} /> ); diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/GeneralInformation.page.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/GeneralInformation.page.tsx index 97c0511e8d17..4207f9608f01 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/GeneralInformation.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/GeneralInformation.page.tsx @@ -1,8 +1,10 @@ import { Outlet, useNavigate, useParams } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; + import { BillingInformationsTileStandard } from '@ovh-ux/manager-billing-informations'; -import { useBackupVaultDetails } from '@/data/hooks/vaults/getVaultDetails'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; import { subRoutes } from '@/routes/routes.constants'; import { GeneralInformationVaultTile } from './_components/general-information-vault-tile/GeneralInformationVaultTile.component'; @@ -10,7 +12,8 @@ import { SubscriptionTile } from './_components/subscription-tile/SubscriptionTi export default function GeneralInformationPage() { const { vaultId } = useParams<{ vaultId: string }>(); - const { data: vaultResource } = useBackupVaultDetails({ vaultId: vaultId! }); + const queryClient = useQueryClient(); + const { data: vaultResource } = useQuery(vaultsQueries.withClient(queryClient).detail(vaultId!)); const navigate = useNavigate(); return ( diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/GeneralInformationVaultTile.test.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/GeneralInformationVaultTile.test.tsx index 38bb2114965f..5ca166566d8c 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/GeneralInformationVaultTile.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/GeneralInformationVaultTile.test.tsx @@ -1,50 +1,53 @@ +import { QueryClient } from '@tanstack/react-query'; import { render, screen } from '@testing-library/react'; import { vi } from 'vitest'; -import { GeneralInformationTileProps } from '@/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockLocations } from '@/mocks/location/locations'; import { mockVaults } from '@/mocks/vaults/vaults.mock'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { GeneralInformationVaultTile } from '../general-information-vault-tile/GeneralInformationVaultTile.component'; -const { useBackupVaultDetailsMock, useLocationDetailsMock } = vi.hoisted(() => ({ - useBackupVaultDetailsMock: vi.fn(), - useLocationDetailsMock: vi.fn(), +vi.mock('react-i18next', () => ({ + useTranslation: vi.fn().mockReturnValue({ + t: vi.fn().mockImplementation((key: string) => key), + }), })); -vi.mock('@/data/hooks/location/getLocationDetails', () => ({ - useLocationDetails: useLocationDetailsMock, -})); -vi.mock('@/data/hooks/vaults/getVaultDetails', () => ({ - useBackupVaultDetails: useBackupVaultDetailsMock, -})); +describe('GeneralInformationVaultTile', () => { + let queryClient: QueryClient; + const vault = mockVaults[0]!; -vi.mock( - '@/components/CommonTiles/GeneralInformationsTile/GeneralInformationTile.component', - () => ({ - GeneralInformationTile: ({ - resourceDetails, - isLoading, - }: GeneralInformationTileProps) => - isLoading ? <>is loading : <>{resourceDetails?.currentState.name}, - }), -); + const buildWrapper = () => testWrapperBuilder().withQueryClient(queryClient).build(); + + beforeEach(() => { + queryClient = createQueryClientTest(); + }); -describe('GeneralInformationVaultTile', () => { it('Should render GeneralInformationVaultTile component', async () => { - useBackupVaultDetailsMock.mockReturnValue({ data: mockVaults[0]!, isLoading: false }); - useLocationDetailsMock.mockReturnValue({ data: mockLocations[0]!, isLoading: false }); - const { container } = render(); + queryClient.setQueryData(queryKeys.vaults.detail(vault.id), vault); + queryClient.setQueryData( + queryKeys.locations.detail(vault.currentState.region), + mockLocations[0]!, + ); + + const wrapper = await buildWrapper(); + + const { container } = render(, { wrapper }); await expect(container).toBeAccessible(); - expect(screen.getByText(mockVaults[0]!.currentState.name)).toBeVisible(); + expect(screen.getByText(vault.currentState.name)).toBeVisible(); }); - it('Should render GeneralInformationVaultTile component', async () => { - useBackupVaultDetailsMock.mockReturnValue({ data: mockVaults[0]!, isLoading: true }); - useLocationDetailsMock.mockReturnValue({ data: mockLocations[0]!, isLoading: true }); - const { container } = render(); + it('Should render GeneralInformationVaultTile component with skeletons when loading', async () => { + // Don't seed the cache so queries stay in loading state + + const wrapper = await buildWrapper(); + + const { container } = render(, { wrapper }); await expect(container).toBeAccessible(); diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/SubscriptionTile.test.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/SubscriptionTile.test.tsx index 84c8c8da1873..fa06373b237d 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/SubscriptionTile.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/__tests__/SubscriptionTile.test.tsx @@ -3,10 +3,12 @@ import { vi } from 'vitest'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; +import { queryKeys } from '@/data/queries/queryKeys'; import { BACKUP_AGENT_NAMESPACES } from '@/lib'; -import { TENANTS_MOCKS } from '@/mocks/tenant/tenants.mock'; import { mockVaults } from '@/mocks/vaults/vaults.mock'; import { VAULT_PLAN_CODE } from '@/module.constants'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { SubscriptionTile } from '../subscription-tile/SubscriptionTile.component'; @@ -16,27 +18,6 @@ const LABELS_VISIBLES = [ `${BACKUP_AGENT_NAMESPACES.VAULT_DASHBOARD}:type_billing`, ]; -vi.mock('@/data/hooks/consumption/useServiceConsumption', () => { - return { - useGetServiceConsumptionOptions: vi.fn().mockReturnValue(vi.fn()), - }; -}); - -const { useBackupVaultDetailsMock, useQuery } = vi.hoisted(() => ({ - useBackupVaultDetailsMock: vi.fn(), - useQuery: vi.fn(), -})); - -vi.mock('@/data/hooks/vaults/getVaultDetails', () => ({ - useBackupVaultDetails: useBackupVaultDetailsMock, -})); - -vi.mock('@tanstack/react-query', () => { - return { - useQuery: useQuery, - }; -}); - vi.mock('react-i18next', () => ({ useTranslation: vi.fn().mockReturnValue({ t: vi.fn().mockImplementation((key: string) => key), @@ -46,19 +27,22 @@ vi.mock('react-i18next', () => ({ vi.mock('@/hooks/useRequiredParams', () => { return { useRequiredParams: vi.fn().mockReturnValue({ - tenantId: TENANTS_MOCKS[0]!.id, + vaultId: mockVaults[0]!.id, }), }; }); describe('SubscriptionTile', () => { it('Should render SubscriptionTile component', async () => { - useBackupVaultDetailsMock.mockReturnValue({ data: mockVaults[0]!, isLoading: false }); - useQuery.mockReturnValue({ - data: [{ planCode: VAULT_PLAN_CODE, quantity: 100, price: { text: '100 €' } }], - isPending: false, - }); - const { container } = render(); + const queryClient = createQueryClientTest(); + queryClient.setQueryData(queryKeys.vaults.detail(mockVaults[0]!.id), mockVaults[0]!); + queryClient.setQueryData(queryKeys.consumption.byResource(mockVaults[0]!.id), [ + { planCode: VAULT_PLAN_CODE, quantity: 100, price: { text: '100 €' } }, + ]); + + const wrapper = await testWrapperBuilder().withQueryClient(queryClient).build(); + + const { container } = render(, { wrapper }); await expect(container).toBeAccessible(); diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/general-information-vault-tile/GeneralInformationVaultTile.component.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/general-information-vault-tile/GeneralInformationVaultTile.component.tsx index 0418d49127e3..efc33a3273e0 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/general-information-vault-tile/GeneralInformationVaultTile.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/general-information-vault-tile/GeneralInformationVaultTile.component.tsx @@ -1,3 +1,4 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsBadge, OdsSkeleton, OdsText } from '@ovhcloud/ods-components/react'; @@ -7,8 +8,8 @@ import { ManagerTile } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; import { ResourceStatusBadge } from '@/components/ResourceStatusBadge/ResourceStatusBadge.component'; -import { useLocationDetails } from '@/data/hooks/location/getLocationDetails'; -import { useBackupVaultDetails } from '@/data/hooks/vaults/getVaultDetails'; +import { locationsQueries } from '@/data/queries/locations.queries'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; import { VAULT_DEFAULT_IMMUTABILITY } from '@/module.constants'; type GeneralInformationVaultTileProps = { @@ -23,10 +24,15 @@ export function GeneralInformationVaultTile({ vaultId }: GeneralInformationVault 'dashboard', BACKUP_AGENT_NAMESPACES.VAULT_DASHBOARD, ]); - const { data: vault, isLoading: isLoadingVault } = useBackupVaultDetails({ vaultId }); - const { data: locationData, isLoading: isLoadingLocation } = useLocationDetails( - vault?.currentState.region, + const queryClient = useQueryClient(); + const { data: vault, isPending: isLoadingVault } = useQuery( + vaultsQueries.withClient(queryClient).detail(vaultId), ); + const vaultRegion = vault?.currentState.region; + const { data: locationData, isPending: isLoadingLocation } = useQuery({ + ...locationsQueries.detail(vaultRegion!), + enabled: !!vaultRegion, + }); /* The code below is a copy of GeneralInformationTile component, made specifically for vaults. diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx index da45d691dbfe..9ebeebef20f5 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/SubscriptionTile.component.tsx @@ -1,3 +1,4 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsIcon, OdsSkeleton, OdsText, OdsTooltip } from '@ovhcloud/ods-components/react'; @@ -6,7 +7,7 @@ import { NAMESPACES } from '@ovh-ux/manager-common-translations'; import { ManagerTile } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useBackupVaultDetails } from '@/data/hooks/vaults/getVaultDetails'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; import { BillingType, ConsumptionDetails, ConsumptionRegionsList } from './_components'; @@ -22,7 +23,10 @@ export function SubscriptionTile({ vaultId }: SubscriptionTileProps) { NAMESPACES.BILLING, BACKUP_AGENT_NAMESPACES.VAULT_DASHBOARD, ]); - const { isPending, data: vault } = useBackupVaultDetails({ vaultId }); + const queryClient = useQueryClient(); + const { isPending, data: vault } = useQuery( + vaultsQueries.withClient(queryClient).detail(vaultId), + ); const tooltipId = 'consumption-tooltip'; return ( diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/BillingType.component.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/BillingType.component.tsx index c5cf7d67fb6c..bd7a1d859a17 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/BillingType.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/BillingType.component.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsSkeleton, OdsText } from '@ovhcloud/ods-components/react'; @@ -6,9 +6,9 @@ import { OdsSkeleton, OdsText } from '@ovhcloud/ods-components/react'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useGetServiceConsumptionOptions } from '@/data/hooks/consumption/useServiceConsumption'; +import { consumptionQueries } from '@/data/queries/consumption.queries'; +import { selectConsumptionPriceText } from '@/data/selectors/consumption.selectors'; import { useRequiredParams } from '@/hooks/useRequiredParams'; -import { VAULT_PLAN_CODE } from '@/module.constants'; import { CONSUMPTION_MAX_VALUE_IN_TB } from '../SubscriptionTile.component'; @@ -21,12 +21,13 @@ export const BillingType = () => { BACKUP_AGENT_NAMESPACES.COMMON, ]); const { vaultId } = useRequiredParams('vaultId'); - const { data: consumptionData, isPending } = useQuery(useGetServiceConsumptionOptions()(vaultId)); + const queryClient = useQueryClient(); + const { data: priceHTText = '-', isPending } = useQuery({ + ...consumptionQueries.withClient(queryClient).byResource(vaultId), + select: selectConsumptionPriceText, + }); const bundleSize = `${CONSUMPTION_MAX_VALUE_IN_TB}${t(`${NAMESPACES.BYTES}:unit_size_TB`)}`; - const priceHTText = - consumptionData?.find((consumption) => consumption.planCode === VAULT_PLAN_CODE)?.price.text ?? - '-'; return (
diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/ConsumptionDetails.component.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/ConsumptionDetails.component.tsx index a7772d373800..f9c64eda0f39 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/ConsumptionDetails.component.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/ConsumptionDetails.component.tsx @@ -1,15 +1,15 @@ import { useId } from 'react'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { OdsProgressBar, OdsSkeleton, OdsText } from '@ovhcloud/ods-components/react'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; -import { useGetServiceConsumptionOptions } from '@/data/hooks/consumption/useServiceConsumption'; +import { consumptionQueries } from '@/data/queries/consumption.queries'; +import { selectConsumptionQuantity } from '@/data/selectors/consumption.selectors'; import { useRequiredParams } from '@/hooks/useRequiredParams'; -import { VAULT_PLAN_CODE } from '@/module.constants'; import { CONSUMPTION_MAX_VALUE_IN_TB } from '../SubscriptionTile.component'; @@ -17,7 +17,11 @@ export const ConsumptionDetails = () => { const idLabel = useId(); const { t } = useTranslation([NAMESPACES.BYTES]); const { vaultId } = useRequiredParams('vaultId'); - const { data: consumptionData, isPending } = useQuery(useGetServiceConsumptionOptions()(vaultId)); + const queryClient = useQueryClient(); + const { data: consumptionInGB = 0, isPending } = useQuery({ + ...consumptionQueries.withClient(queryClient).byResource(vaultId), + select: selectConsumptionQuantity, + }); if (isPending) { return ( @@ -27,9 +31,6 @@ export const ConsumptionDetails = () => { ); } - - const consumptionInGB = - consumptionData?.find((consumption) => consumption.planCode === VAULT_PLAN_CODE)?.quantity ?? 0; const consumptionInTB = consumptionInGB / 1000; const consumptionInPercentage = (consumptionInTB / CONSUMPTION_MAX_VALUE_IN_TB) * 100; const consumptionLabel = `${consumptionInGB} ${t('unit_size_GB')} / ${CONSUMPTION_MAX_VALUE_IN_TB} ${t('unit_size_TB')} (${consumptionInPercentage}%)`; diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/BillingType.test.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/BillingType.test.tsx index 32e19a7c99af..d1424bde47f0 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/BillingType.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/BillingType.test.tsx @@ -1,20 +1,13 @@ import { render } from '@testing-library/react'; -import { vi } from 'vitest'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockVaults } from '@/mocks/vaults/vaults.mock'; +import { VAULT_PLAN_CODE } from '@/module.constants'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { BillingType } from '../BillingType.component'; -const { useQuery } = vi.hoisted(() => ({ - useQuery: vi.fn(), -})); - -vi.mock('@tanstack/react-query', () => { - return { - useQuery: useQuery, - }; -}); - vi.mock('@/hooks/useRequiredParams', () => { return { useRequiredParams: vi.fn().mockReturnValue({ @@ -23,16 +16,16 @@ vi.mock('@/hooks/useRequiredParams', () => { }; }); -vi.mock('@/data/hooks/consumption/useServiceConsumption', () => { - return { - useGetServiceConsumptionOptions: vi.fn().mockReturnValue(vi.fn()), - }; -}); - describe('BillingType component a11y', () => { it('Should render BillingType component', async () => { - useQuery.mockReturnValue({ data: [], isPending: false }); - const { container } = render(); + const queryClient = createQueryClientTest(); + queryClient.setQueryData(queryKeys.consumption.byResource(mockVaults[0]!.id), [ + { planCode: VAULT_PLAN_CODE, quantity: 100, price: { text: '100 €' } }, + ]); + + const wrapper = await testWrapperBuilder().withQueryClient(queryClient).build(); + + const { container } = render(, { wrapper }); await expect(container).toBeAccessible(); }); diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/ConsumptionDetails.test.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/ConsumptionDetails.test.tsx index 448c4e486fa8..54a37399adcf 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/ConsumptionDetails.test.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/dashboard/general-information/_components/subscription-tile/_components/__tests__/ConsumptionDetails.test.tsx @@ -1,26 +1,13 @@ import { render } from '@testing-library/react'; +import { queryKeys } from '@/data/queries/queryKeys'; import { mockVaults } from '@/mocks/vaults/vaults.mock'; import { VAULT_PLAN_CODE } from '@/module.constants'; +import { testWrapperBuilder } from '@/test-utils/testWrapperBuilder'; +import { createQueryClientTest } from '@/test-utils/testWrapperProviders'; import { ConsumptionDetails } from '../ConsumptionDetails.component'; -const { useQuery } = vi.hoisted(() => ({ - useQuery: vi.fn(), -})); - -vi.mock('@/data/hooks/consumption/useServiceConsumption', () => { - return { - useGetServiceConsumptionOptions: vi.fn().mockReturnValue(vi.fn()), - }; -}); - -vi.mock('@tanstack/react-query', () => { - return { - useQuery: useQuery, - }; -}); - vi.mock('@/hooks/useRequiredParams', () => { return { useRequiredParams: vi.fn().mockReturnValue({ @@ -31,12 +18,14 @@ vi.mock('@/hooks/useRequiredParams', () => { describe('ConsumptionDetails component a11y', () => { it('Should render ConsumptionDetails component', async () => { - useQuery.mockReturnValue({ - data: [{ planCode: VAULT_PLAN_CODE, quantity: 100 }], - isPending: false, - }); + const queryClient = createQueryClientTest(); + queryClient.setQueryData(queryKeys.consumption.byResource(mockVaults[0]!.id), [ + { planCode: VAULT_PLAN_CODE, quantity: 100 }, + ]); + + const wrapper = await testWrapperBuilder().withQueryClient(queryClient).build(); - const { container } = render(); + const { container } = render(, { wrapper }); await expect(container).toBeAccessible(); }); diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/delete/DeleteVault.page.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/delete/DeleteVault.page.tsx index 664a2e87e27f..ee3293a0e510 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/delete/DeleteVault.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/delete/DeleteVault.page.tsx @@ -1,5 +1,6 @@ import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { ODS_MODAL_COLOR } from '@ovhcloud/ods-components'; @@ -10,8 +11,8 @@ import { useFeatureAvailability } from '@ovh-ux/manager-module-common-api'; import { Modal, useNotifications } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useBackupVaultsList } from '@/data/hooks/vaults/getVault'; -import { useDeleteVault } from '@/data/hooks/vaults/useDeleteVault'; +import { useDeleteVault } from '@/data/hooks/useDeleteVault'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; import { useGetFeaturesAvailabilityNames } from '@/hooks/useGetFeatureAvailability'; export default function DeleteVaultPage() { @@ -20,7 +21,8 @@ export default function DeleteVaultPage() { const closeModal = () => navigate('..'); const { addSuccess, addError } = useNotifications(); const [searchParams] = useSearchParams(); - const { data: vaults } = useBackupVaultsList(); + const queryClient = useQueryClient(); + const { data: vaults } = useQuery(vaultsQueries.withClient(queryClient).list()); const vaultId = searchParams.get('vaultId'); const vault = vaults?.find(({ id }) => id === vaultId); diff --git a/packages/manager/modules/backup-agent/src/pages/vaults/listing/Listing.page.tsx b/packages/manager/modules/backup-agent/src/pages/vaults/listing/Listing.page.tsx index 931d2b980898..b4fc22e3c645 100644 --- a/packages/manager/modules/backup-agent/src/pages/vaults/listing/Listing.page.tsx +++ b/packages/manager/modules/backup-agent/src/pages/vaults/listing/Listing.page.tsx @@ -2,6 +2,7 @@ import { Suspense } from 'react'; import { Outlet } from 'react-router-dom'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { Trans, useTranslation } from 'react-i18next'; import { OdsText } from '@ovhcloud/ods-components/react'; @@ -9,14 +10,15 @@ import { OdsText } from '@ovhcloud/ods-components/react'; import { Datagrid, Links } from '@ovh-ux/manager-react-components'; import { BACKUP_AGENT_NAMESPACES } from '@/BackupAgent.translations'; -import { useBackupVaultsList } from '@/data/hooks/vaults/getVault'; +import { vaultsQueries } from '@/data/queries/vaults.queries'; import { useGuideUtils } from '@/hooks/useGuideUtils'; import { useColumns } from './_hooks/useColumns.hooks'; export default function ListingPage() { useTranslation([BACKUP_AGENT_NAMESPACES.VAULT_LISTING]); - const { data } = useBackupVaultsList(); + const queryClient = useQueryClient(); + const { data } = useQuery(vaultsQueries.withClient(queryClient).list()); const columns = useColumns(); const guide = useGuideUtils();