From 8e2d6f350c9e2afd6f90e7f1b48d804cb18a285e Mon Sep 17 00:00:00 2001 From: darsene <72250222+darsene@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:07:48 +0200 Subject: [PATCH] feat(hpc-vmware-managed-vcd): add new product VCD (#12552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref: MANAGER-14354 Signed-off-by: David Arsène Co-authored-by: Paul Dickerson Co-authored-by: Thibault Barske Co-authored-by: Nicolas Pierre-charles --- .gitignore | 1 + .../src/hooks/iam/iam.interface.ts | 6 + .../src/hooks/iam/index.ts | 1 + .../src/hooks/iam/useOvhIam.tsx | 2 +- .../src/hooks/index.ts | 1 + .../universe/HostedPrivateCloudSidebar.tsx | 33 ++- .../services/hostedPrivateCloud.ts | 14 +- .../translations/sidebar/Messages_de_DE.json | 4 +- .../translations/sidebar/Messages_en_GB.json | 4 +- .../translations/sidebar/Messages_es_ES.json | 4 +- .../translations/sidebar/Messages_fr_CA.json | 3 +- .../translations/sidebar/Messages_fr_FR.json | 3 +- .../translations/sidebar/Messages_it_IT.json | 4 +- .../translations/sidebar/Messages_pl_PL.json | 4 +- .../translations/sidebar/Messages_pt_PT.json | 4 +- .../common/translations/Messages_de_DE.json | 3 +- .../common/translations/Messages_en_GB.json | 3 +- .../common/translations/Messages_es_ES.json | 3 +- .../common/translations/Messages_fr_CA.json | 1 + .../common/translations/Messages_fr_FR.json | 1 + .../common/translations/Messages_it_IT.json | 3 +- .../common/translations/Messages_pl_PL.json | 3 +- .../common/translations/Messages_pt_PT.json | 3 +- .../client/app/config/constants.config.js | 36 +++ .../details/dedicatedCloud.routing.js | 6 +- .../details/managed-baremetal.routing.js | 6 +- .../apps/hpc-vmware-managed-vcd/.gitignore | 1 + .../apps/hpc-vmware-managed-vcd/README.md | 3 + .../apps/hpc-vmware-managed-vcd/cucumber.js | 20 ++ .../e2e/features/onboarding.feature | 7 + .../e2e/step-definitions/onboarding.step.ts | 32 +++ .../e2e/utils/constants.ts | 7 + .../e2e/utils/index.tsx | 2 + .../e2e/utils/network.ts | 21 ++ .../apps/hpc-vmware-managed-vcd/index.html | 22 ++ .../mocks/iam/iam.handler.ts | 15 ++ .../mocks/iam/iam.mock.ts | 22 ++ .../hpc-vmware-managed-vcd/mocks/index.ts | 3 + .../vcd-organization/vcd-datacentre.mock.ts | 32 +++ .../vcd-organization.handler.ts | 71 ++++++ .../vcd-organization/vcd-organization.mock.ts | 60 +++++ .../veeam-backup/veeam-backup.handler.ts | 38 +++ .../mocks/veeam-backup/veeam-backup.mock.ts | 49 ++++ .../apps/hpc-vmware-managed-vcd/package.json | 74 ++++++ .../playwright.config.ts | 20 ++ .../hpc-vmware-managed-vcd/postcss.config.js | 6 + .../dashboard/Messages_de_DE.json | 45 ++++ .../dashboard/Messages_en_GB.json | 45 ++++ .../dashboard/Messages_es_ES.json | 45 ++++ .../dashboard/Messages_fr_CA.json | 45 ++++ .../dashboard/Messages_fr_FR.json | 45 ++++ .../dashboard/Messages_it_IT.json | 45 ++++ .../dashboard/Messages_pl_PL.json | 45 ++++ .../dashboard/Messages_pt_PT.json | 45 ++++ .../Messages_de_DE.json | 3 + .../Messages_en_GB.json | 3 + .../Messages_es_ES.json | 3 + .../Messages_fr_CA.json | 3 + .../Messages_fr_FR.json | 3 + .../Messages_it_IT.json | 3 + .../Messages_pl_PL.json | 3 + .../Messages_pt_PT.json | 3 + .../datacentres/Messages_de_DE.json | 10 + .../datacentres/Messages_en_GB.json | 10 + .../datacentres/Messages_es_ES.json | 10 + .../datacentres/Messages_fr_CA.json | 10 + .../datacentres/Messages_fr_FR.json | 10 + .../datacentres/Messages_it_IT.json | 10 + .../datacentres/Messages_pl_PL.json | 10 + .../datacentres/Messages_pt_PT.json | 10 + .../datacentres/compute/Messages_de_DE.json | 7 + .../datacentres/compute/Messages_en_GB.json | 7 + .../datacentres/compute/Messages_es_ES.json | 7 + .../datacentres/compute/Messages_fr_CA.json | 7 + .../datacentres/compute/Messages_fr_FR.json | 7 + .../datacentres/compute/Messages_it_IT.json | 7 + .../datacentres/compute/Messages_pl_PL.json | 7 + .../datacentres/compute/Messages_pt_PT.json | 7 + .../datacentres/order/Messages_de_DE.json | 18 ++ .../datacentres/order/Messages_en_GB.json | 18 ++ .../datacentres/order/Messages_es_ES.json | 18 ++ .../datacentres/order/Messages_fr_CA.json | 18 ++ .../datacentres/order/Messages_fr_FR.json | 18 ++ .../datacentres/order/Messages_it_IT.json | 18 ++ .../datacentres/order/Messages_pl_PL.json | 18 ++ .../datacentres/order/Messages_pt_PT.json | 18 ++ .../datacentres/storage/Messages_de_DE.json | 7 + .../datacentres/storage/Messages_en_GB.json | 7 + .../datacentres/storage/Messages_es_ES.json | 7 + .../datacentres/storage/Messages_fr_CA.json | 7 + .../datacentres/storage/Messages_fr_FR.json | 7 + .../datacentres/storage/Messages_it_IT.json | 7 + .../datacentres/storage/Messages_pl_PL.json | 7 + .../datacentres/storage/Messages_pt_PT.json | 7 + .../error/Messages_de_DE.json | 8 + .../error/Messages_en_GB.json | 8 + .../error/Messages_es_ES.json | 8 + .../error/Messages_fr_CA.json | 8 + .../error/Messages_fr_FR.json | 8 + .../error/Messages_it_IT.json | 8 + .../error/Messages_pl_PL.json | 8 + .../error/Messages_pt_PT.json | 8 + .../translations/listing/Messages_de_DE.json | 8 + .../translations/listing/Messages_en_GB.json | 8 + .../translations/listing/Messages_es_ES.json | 8 + .../translations/listing/Messages_fr_CA.json | 8 + .../translations/listing/Messages_fr_FR.json | 8 + .../translations/listing/Messages_it_IT.json | 8 + .../translations/listing/Messages_pl_PL.json | 8 + .../translations/listing/Messages_pt_PT.json | 8 + .../onboarding/Messages_de_DE.json | 18 ++ .../onboarding/Messages_en_GB.json | 18 ++ .../onboarding/Messages_es_ES.json | 18 ++ .../onboarding/Messages_fr_CA.json | 18 ++ .../onboarding/Messages_fr_FR.json | 18 ++ .../onboarding/Messages_it_IT.json | 18 ++ .../onboarding/Messages_pl_PL.json | 18 ++ .../onboarding/Messages_pt_PT.json | 18 ++ .../apps/hpc-vmware-managed-vcd/setupTests.ts | 35 +++ .../apps/hpc-vmware-managed-vcd/src/App.tsx | 29 +++ .../src/assets/VmwareBroadcomxOVHcloud.svg | 29 +++ .../src/assets/error-banner-oops.png | Bin 0 -> 60234 bytes .../breadcrumb/Breadcrumb.component.tsx | 25 ++ .../layout/VcdDashboardLayout.component.tsx | 84 +++++++ .../compute/ComputeOrderCells.component.tsx | 71 ++++++ .../container/DatagridContainer.component.tsx | 127 ++++++++++ .../container/DatagridContainer.spec.tsx | 93 +++++++ .../storage/StorageOrderCells.component.tsx | 47 ++++ .../src/components/error/Error.component.tsx | 52 ++++ .../src/components/error/Error.scss | 18 ++ .../form/DatacentreOrder.component.tsx | 152 ++++++++++++ .../form/QuantitySelector.component.tsx | 82 +++++++ .../components/loading/Loading.component.tsx | 12 + .../src/components/modal/EditDetailModal.tsx | 135 +++++++++++ .../modal/UpdateDetailModalHandler.tsx | 89 +++++++ .../billing-tile/BillingTile.component.tsx | 121 ++++++++++ .../tiles/billing-tile/BillingTile.spec.tsx | 67 +++++ ...centreGeneralInformationTile.component.tsx | 115 +++++++++ .../DatacentreGeneralInformationTile.spec.tsx | 107 ++++++++ .../EditableTileItem.component.tsx | 56 +++++ .../EditableTileItem.spec.tsx | 30 +++ ...ganizationDataProtectionTile.component.tsx | 43 ++++ .../OrganizationDataProtectionTile.spec.tsx | 145 +++++++++++ .../BackupTileItem.component.tsx | 55 +++++ .../DatacentresCount.component.tsx | 32 +++ ...zationGeneralInformationTile.component.tsx | 110 +++++++++ ...rganizationGeneralInformationTile.spec.tsx | 66 +++++ .../OrganizationOptionsTile.component.tsx | 62 +++++ .../OrganizationOptionsTile.spec.tsx | 63 +++++ .../tile-subtitle/TileSubtitle.component.tsx | 17 ++ .../tiles/tile-subtitle/TileSubtitle.spec.tsx | 21 ++ .../src/context/DatacentreOrder.context.tsx | 56 +++++ .../data/api/hpc-vmware-managed-vcd-cart.ts | 9 + .../api/hpc-vmware-managed-vcd-datacentre.ts | 58 +++++ .../api/hpc-vmware-managed-vcd.constants.ts | 1 + .../src/data/api/hpc-vmware-managed-vcd.ts | 47 ++++ .../src/data/hooks/useAutoRefetch.ts | 29 +++ .../data/hooks/useManagedVcdDatacentres.ts | 31 +++ .../data/hooks/useManagedVcdOrganization.ts | 47 ++++ .../src/data/hooks/useOrderableResource.ts | 13 + .../src/data/hooks/useUpdateVcdDatacentre.ts | 39 +++ .../data/hooks/useUpdateVcdOrganization.ts | 44 ++++ .../src/data/hooks/useVcdCatalog.ts | 13 + .../src/data/hooks/useVcdOrder.ts | 34 +++ .../src/hooks/breadcrumb/useBreadcrumb.tsx | 54 +++++ .../src/hooks/guide/useGuideUtils.tsx | 125 ++++++++++ .../src/hooks/user/useCurrentUser.ts | 32 +++ .../src/hpc-vmware-managed-vcd.config.ts | 8 + .../hpc-vmware-managed-vcd/src/index.scss | 1 + .../apps/hpc-vmware-managed-vcd/src/index.tsx | 51 ++++ .../hpc-vmware-managed-vcd/src/pages/404.tsx | 7 + .../DatacentreDashboard.constant.ts | 2 + .../datacentre/DatacentreDashboard.page.tsx | 82 +++++++ .../DatacentreComputeOrder.constants.ts | 2 + .../DatacentreComputeOrder.page.tsx | 77 ++++++ .../compute/DatacentreCompute.constants.ts | 1 + .../compute/DatacentreCompute.page.tsx | 111 +++++++++ .../DatacentreGeneralInformation.page.tsx | 37 +++ .../edit/EditVdcDescription.page.tsx | 52 ++++ .../DatacentreStorageOrder.constants.ts | 2 + .../DatacentreStorageOrder.page.tsx | 55 +++++ .../storage/DatacentreStorage.page.tsx | 123 ++++++++++ .../OrganizationDashboard.constants.ts | 3 + .../OrganizationDashboard.page.tsx | 55 +++++ .../OrganizationDashboard.spec.tsx | 37 +++ .../OrganizationGeneralInformation.page.tsx | 56 +++++ .../OrganizationGeneralInformation.spec.tsx | 159 ++++++++++++ .../edit/EditDescription.page.tsx | 6 + .../edit/EditName.page.tsx | 6 + .../src/pages/layout.tsx | 31 +++ .../listing/datacentres/datacentres.page.tsx | 124 ++++++++++ .../organizations/Organizations.page.tsx | 91 +++++++ .../organizations/Organizations.spec.tsx | 21 ++ .../src/pages/onboarding/Onboarding.page.tsx | 72 ++++++ .../src/pages/onboarding/Onboarding.spec.tsx | 15 ++ .../src/routes/routes.constant.ts | 29 +++ .../src/routes/routes.tsx | 228 ++++++++++++++++++ .../src/test-utils/TestApp.tsx | 21 ++ .../src/test-utils/index.ts | 2 + .../src/test-utils/render-test.tsx | 79 ++++++ .../src/test-utils/test-i18n.ts | 80 ++++++ .../src/tracking.constant.ts | 20 ++ .../src/types/datagrid-route.type.ts | 6 + .../src/types/vcd-catalog.interface.ts | 53 ++++ .../src/types/vcd-compute.interface.ts | 14 ++ .../src/types/vcd-datacenter.interface.ts | 26 ++ .../vcd-organization-backup.interface.ts | 48 ++++ .../src/types/vcd-organization.interface.ts | 25 ++ .../src/types/vcd-storage.interface.ts | 21 ++ .../vcd-vdc-orderable-resource.interface.ts | 26 ++ .../src/utils/capitalize.ts | 3 + .../src/utils/formValidation.ts | 15 ++ .../src/utils/getBackupBadge.ts | 65 +++++ .../src/utils/getPricedOrderableResource.ts | 38 +++ .../src/utils/iam.constants.ts | 6 + .../src/utils/planCode.constants.ts | 1 + .../src/utils/queryKeys.ts | 56 +++++ .../src/utils/refetchConditions.ts | 13 + .../hpc-vmware-managed-vcd/src/vite-hmr.ts | 5 + .../hpc-vmware-managed-vcd/tailwind.config.js | 14 ++ .../apps/hpc-vmware-managed-vcd/tsconfig.json | 27 +++ .../hpc-vmware-managed-vcd/tsconfig.test.json | 6 + .../hpc-vmware-managed-vcd/vite.config.mjs | 8 + .../hpc-vmware-managed-vcd/vitest.config.js | 41 ++++ .../translations/Messages_de_DE.json | 5 +- .../translations/Messages_en_GB.json | 5 +- .../translations/Messages_es_ES.json | 5 +- .../translations/Messages_fr_CA.json | 3 +- .../translations/Messages_fr_FR.json | 3 +- .../translations/Messages_it_IT.json | 5 +- .../translations/Messages_pl_PL.json | 5 +- .../translations/Messages_pt_PT.json | 5 +- .../modules/order/src/order.constant.ts | 23 ++ yarn.lock | 68 +++++- 234 files changed, 6824 insertions(+), 41 deletions(-) create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/.gitignore create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/README.md create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/cucumber.js create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/e2e/features/onboarding.feature create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/e2e/step-definitions/onboarding.step.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/index.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/network.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/index.html create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.handler.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.mock.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/index.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-datacentre.mock.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.handler.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.mock.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.handler.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.mock.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/package.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/playwright.config.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/postcss.config.js create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_de_DE.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_en_GB.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_es_ES.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_CA.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_FR.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_it_IT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pl_PL.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pt_PT.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/setupTests.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/App.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/assets/VmwareBroadcomxOVHcloud.svg create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/assets/error-banner-oops.png create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/breadcrumb/Breadcrumb.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/dashboard/layout/VcdDashboardLayout.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/compute/ComputeOrderCells.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/storage/StorageOrderCells.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.scss create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/DatacentreOrder.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/QuantitySelector.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/loading/Loading.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/EditDetailModal.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/UpdateDetailModalHandler.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/backup-tile-item/BackupTileItem.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/DatacentresCount.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.component.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/context/DatacentreOrder.context.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-cart.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-datacentre.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useAutoRefetch.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdDatacentres.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdOrganization.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useOrderableResource.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdDatacentre.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdOrganization.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdCatalog.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdOrder.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/breadcrumb/useBreadcrumb.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/guide/useGuideUtils.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/user/useCurrentUser.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/hpc-vmware-managed-vcd.config.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/index.scss create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/index.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/404.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.constant.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/DatacentreGeneralInformation.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/edit/EditVdcDescription.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage/DatacentreStorage.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditDescription.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditName.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/layout.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/datacentres/datacentres.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.page.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.spec.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.constant.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/TestApp.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/index.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/render-test.tsx create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/test-i18n.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/tracking.constant.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/datagrid-route.type.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-catalog.interface.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-compute.interface.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-datacenter.interface.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization-backup.interface.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization.interface.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-storage.interface.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-vdc-orderable-resource.interface.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/capitalize.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/formValidation.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getBackupBadge.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getPricedOrderableResource.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/iam.constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/planCode.constants.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/queryKeys.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/utils/refetchConditions.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/src/vite-hmr.ts create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/tailwind.config.js create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.test.json create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/vite.config.mjs create mode 100644 packages/manager/apps/hpc-vmware-managed-vcd/vitest.config.js diff --git a/.gitignore b/.gitignore index 5aa93103e845..9a22c0b89c38 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ node_modules cache dist !**/iam/**/types +!**/apps/**/types .memsourcerc.yaml /docs/docs/public/assets/json/packages.json .extras* diff --git a/packages/manager-react-components/src/hooks/iam/iam.interface.ts b/packages/manager-react-components/src/hooks/iam/iam.interface.ts index df40493a3484..943ba135189b 100644 --- a/packages/manager-react-components/src/hooks/iam/iam.interface.ts +++ b/packages/manager-react-components/src/hooks/iam/iam.interface.ts @@ -1,3 +1,9 @@ +export interface IamObject { + id: string; + urn: string; + displayName?: string; +} + export interface IamInterface { urns?: string[]; actions?: string[]; diff --git a/packages/manager-react-components/src/hooks/iam/index.ts b/packages/manager-react-components/src/hooks/iam/index.ts index 602483d699e1..b317fba26758 100644 --- a/packages/manager-react-components/src/hooks/iam/index.ts +++ b/packages/manager-react-components/src/hooks/iam/index.ts @@ -1 +1,2 @@ +export * from './iam.interface'; export * from './useOvhIam'; diff --git a/packages/manager-react-components/src/hooks/iam/useOvhIam.tsx b/packages/manager-react-components/src/hooks/iam/useOvhIam.tsx index 66c714448ce3..1e87ca390cbb 100644 --- a/packages/manager-react-components/src/hooks/iam/useOvhIam.tsx +++ b/packages/manager-react-components/src/hooks/iam/useOvhIam.tsx @@ -32,7 +32,7 @@ export const fetchAuthorizationCheck = async ( urn: string, ): Promise => { const { data } = await apiClient.v2.post( - `/iam/resource/${urn}/authorization/check`, + `/iam/resource/${encodeURIComponent(urn)}/authorization/check`, { actions, }, diff --git a/packages/manager-react-components/src/hooks/index.ts b/packages/manager-react-components/src/hooks/index.ts index 2186d9c5c60b..6f8e8ecf2795 100644 --- a/packages/manager-react-components/src/hooks/index.ts +++ b/packages/manager-react-components/src/hooks/index.ts @@ -12,6 +12,7 @@ export * from './datagrid/useResourcesV6'; export * from './services'; export * from './tasks'; export * from './date'; +export * from './iam'; export { useProductMaintenance } from './pci/useMaintenance'; export { getMacroRegion, diff --git a/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/HostedPrivateCloudSidebar.tsx b/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/HostedPrivateCloudSidebar.tsx index 8283fb984cc7..05a14762c527 100644 --- a/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/HostedPrivateCloudSidebar.tsx +++ b/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/HostedPrivateCloudSidebar.tsx @@ -18,6 +18,7 @@ import veeamBackupLogo from '@/assets/images/sidebar/veeam-backup-logo.png'; const features = [ 'dedicated-cloud', + 'hpc-vmware-managed-vcd', 'dedicated-cloud:sapHanaOrder', 'nutanix', 'veeam-enterprise', @@ -66,7 +67,7 @@ export default function HostedPrivateCloudSidebar() { if (feature['dedicated-cloud']) { menu.push({ id: 'hpc-dedicated-cloud', - label: t('sidebar_vmware'), + label: t('sidebar_vmware_vsphere'), icon: getIcon('ovh-font ovh-font-dedicatedCloud'), routeMatcher: new RegExp(`^(/configuration)?/dedicated_cloud`), async loader() { @@ -97,6 +98,36 @@ export default function HostedPrivateCloudSidebar() { }); } + if (feature['hpc-vmware-managed-vcd']) { + menu.push({ + id: 'hpc-managed-vcd', + label: t('sidebar_vmware_vcd'), + icon: getIcon('ovh-font ovh-font-dedicatedCloud'), + pathMatcher: new RegExp(`^/hpc-vmware-managed-vcd`), + async loader() { + const app = 'hpc-vmware-managed-vcd' + const services = await loadServices('/vmwareCloudDirector/organization', null, app); + const icon = getIcon('ovh-font ovh-font-dedicatedCloud'); + return [ + { + id: 'dedicated-vmware-vcd-all', + label: t('sidebar_vmware_all'), + href: navigation.getURL(app, '/'), + icon, + ignoreSearch: true, + }, + ...services.map((service) => ({ + ...service, + icon, + pathMatcher: new RegExp( + `^/hpc-vmware-managed-vcd/${service.serviceName}`, + ), + })), + ]; + }, + }); + } + if (feature.nutanix) { menu.push({ id: 'nutanix', diff --git a/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/hostedPrivateCloud.ts b/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/hostedPrivateCloud.ts index 77e2eecca80f..4da8d8856f5c 100644 --- a/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/hostedPrivateCloud.ts +++ b/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/hostedPrivateCloud.ts @@ -24,7 +24,7 @@ hostedPrivateCloudUniverse.children = [ id: 'vm-ware', idAttr: 'vm-ware-link', universe: hostedPrivateCloudUniverse.id, - translation: 'sidebar_vmware', + translation: 'sidebar_vmware_vsphere', serviceType: 'DEDICATEDCLOUD_VMWARE', routing: { application: 'dedicated', @@ -32,6 +32,18 @@ hostedPrivateCloudUniverse.children = [ }, features: ['dedicated-cloud'], }, + { + id: 'hpc-managed-vcd', + universe: hostedPrivateCloudUniverse.id, + translation: 'sidebar_vmware_vcd', + serviceType: 'MANAGED_VCD', + tag: NodeTag.NEW, + routing: { + application: 'hpc-vmware-managed-vcd', + hash: '#/', + }, + features: ['hpc-vmware-managed-vcd'], + }, { id: 'nutanix', idAttr: 'nutanix-link', diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_de_DE.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_de_DE.json index a24cce5aa752..b49539443382 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_de_DE.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_de_DE.json @@ -203,5 +203,7 @@ "sidebar_hycu": "HYCU", "sidebar_all_hycu": "Alle meine Lizenzen", "sidebar_veeam_backup": "Managed Veeam für VCD", - "sidebar_all_veeam_backup": "Alle Dienstleistungen" + "sidebar_all_veeam_backup": "Alle Dienstleistungen", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json index 569fd6b2b722..8cce9c734275 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json @@ -203,5 +203,7 @@ "sidebar_hycu": "HYCU", "sidebar_all_hycu": "All my licenses", "sidebar_veeam_backup": "Managed Veeam for VCD", - "sidebar_all_veeam_backup": "All services" + "sidebar_all_veeam_backup": "All services", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json index a247ae381e14..b9abd15ca113 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json @@ -203,5 +203,7 @@ "sidebar_hycu": "HYCU", "sidebar_all_hycu": "Todas mis licencias", "sidebar_veeam_backup": "Managed Veeam for VCD", - "sidebar_all_veeam_backup": "Todos los servicios" + "sidebar_all_veeam_backup": "Todos los servicios", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json index 69485c4bf59f..482a094df48c 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json @@ -31,7 +31,8 @@ "sidebar_licences": "Licences", "sidebar_hpc": "Hosted Private Cloud", "sidebar_hpc_short": "HPC", - "sidebar_vmware": "VMware", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD", "sidebar_vmware_all": "Tous mes services", "sidebar_anthos_all": "Tous mes déploiements", "sidebar_nutanix": "Nutanix", diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json index 69485c4bf59f..482a094df48c 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json @@ -31,7 +31,8 @@ "sidebar_licences": "Licences", "sidebar_hpc": "Hosted Private Cloud", "sidebar_hpc_short": "HPC", - "sidebar_vmware": "VMware", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD", "sidebar_vmware_all": "Tous mes services", "sidebar_anthos_all": "Tous mes déploiements", "sidebar_nutanix": "Nutanix", diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json index 710bc8591cdc..b65885dfc4a9 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json @@ -203,5 +203,7 @@ "sidebar_hycu": "HYCU", "sidebar_all_hycu": "Tutte le mie licenze", "sidebar_veeam_backup": "Managed Veeam for VCD", - "sidebar_all_veeam_backup": "Tutti i servizi" + "sidebar_all_veeam_backup": "Tutti i servizi", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json index 17286faf3b69..ab725d3e21aa 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json @@ -203,5 +203,7 @@ "sidebar_hycu": "HYCU", "sidebar_all_hycu": "Wszystkie moje licencje", "sidebar_veeam_backup": "Managed Veeam for VCD", - "sidebar_all_veeam_backup": "Wszystkie usługi" + "sidebar_all_veeam_backup": "Wszystkie usługi", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json index b3a6a5dceac7..7d3533325a56 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json @@ -203,5 +203,7 @@ "sidebar_hycu": "HYCU", "sidebar_all_hycu": "Todas as minhas licenças", "sidebar_veeam_backup": "Managed Veeam for VCD", - "sidebar_all_veeam_backup": "Todos os serviços" + "sidebar_all_veeam_backup": "Todos os serviços", + "sidebar_vmware_vsphere": "Managed VMware vSphere", + "sidebar_vmware_vcd": "Managed VCD" } diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_de_DE.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_de_DE.json index 57669e863118..876e3b708d2a 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_de_DE.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_de_DE.json @@ -546,5 +546,6 @@ "core_pcc_top_guide_11_title": "Offizielle Dokumentation zu Nutanix", "older_interface": "Altes Kundeninterface", "core_pcc_top_guide_12_title": "Offizielle Dokumentation zu SAP HANA on Private Cloud", - "core_pcc_top_guide_13_title": "IPs die Verbindung zum vCenter erlauben" + "core_pcc_top_guide_13_title": "IPs die Verbindung zum vCenter erlauben", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Director" } diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_en_GB.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_en_GB.json index 3f060c82cb6e..208716a43879 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_en_GB.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_en_GB.json @@ -546,5 +546,6 @@ "common_resiliate_contact_support": "To cancel this service, please call our support team on: 0333 370 0425. Thank you for choosing OVH.", "core_pcc_top_guide_11_title": "Nutanix official documentation", "core_pcc_top_guide_12_title": "SAP HANA on Private Cloud official documentation", - "core_pcc_top_guide_13_title": "Authorise IPs to connect to vCenter" + "core_pcc_top_guide_13_title": "Authorise IPs to connect to vCenter", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Director" } diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_es_ES.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_es_ES.json index ced65899a29c..e86ec57b9d35 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_es_ES.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_es_ES.json @@ -546,5 +546,6 @@ "common_resiliate_contact_support": "Para dar de baja este servicio, puede ponerse en contacto con nuestro Soporte en el 91 758 34 77. ¡Gracias por su comprensión!", "core_pcc_top_guide_11_title": "Documentación oficial de Nutanix", "core_pcc_top_guide_12_title": "Documentación oficial de SAP HANA on Private Cloud", - "core_pcc_top_guide_13_title": "Autorizar las direcciones IP a conectarse al vCenter" + "core_pcc_top_guide_13_title": "Autorizar las direcciones IP a conectarse al vCenter", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Director" } diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_CA.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_CA.json index 7e63c5cc6029..58c5c0f16ec0 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_CA.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_CA.json @@ -488,6 +488,7 @@ "core_pcc_top_guide_11_title": "Documentation officielle de Nutanix", "core_pcc_top_guide_12_title": "Documentation officielle de SAP HANA on Private Cloud", "core_pcc_top_guide_13_title": "Autoriser des IP à se connecter au vCenter", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Director", "sso_modal_title": "OVH - Authentification", "sso_modal_loading": "Chargement...", "sso_modal_user_title": "Vous étiez connecté en tant que :", diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_FR.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_FR.json index 7e63c5cc6029..58c5c0f16ec0 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_FR.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_fr_FR.json @@ -488,6 +488,7 @@ "core_pcc_top_guide_11_title": "Documentation officielle de Nutanix", "core_pcc_top_guide_12_title": "Documentation officielle de SAP HANA on Private Cloud", "core_pcc_top_guide_13_title": "Autoriser des IP à se connecter au vCenter", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Director", "sso_modal_title": "OVH - Authentification", "sso_modal_loading": "Chargement...", "sso_modal_user_title": "Vous étiez connecté en tant que :", diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_it_IT.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_it_IT.json index 636282fe0b3c..7925a0590b34 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_it_IT.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_it_IT.json @@ -546,5 +546,6 @@ "common_resiliate_contact_support": "Per disattivare questo servizio, contatta il nostro supporto tecnico al numero 02 5560 0423 o apri un ticket.", "core_pcc_top_guide_11_title": "Documentazione ufficiale di Nutanix", "core_pcc_top_guide_12_title": "Documentazione ufficiale di SAP HANA on Private Cloud", - "core_pcc_top_guide_13_title": "Autorizzare IP a connettersi al vCenter" + "core_pcc_top_guide_13_title": "Autorizzare IP a connettersi al vCenter", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Director" } diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_pl_PL.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_pl_PL.json index 840e0c09750f..55f949e1dc29 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_pl_PL.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_pl_PL.json @@ -546,5 +546,6 @@ "common_resiliate_contact_support": "Aby zrezygnować z tej usługi, skontaktuj się z Pomocą techniczną. Zadzwoń na numer: 71 750 02 00 i wybierz 3. Dziękujemy za wyrozumiałość.", "core_pcc_top_guide_11_title": "Oficjalna dokumentacja Nutanix", "core_pcc_top_guide_12_title": "Oficjalna dokumentacja SAP HANA on Private Cloud", - "core_pcc_top_guide_13_title": "Autoryzacja adresów IP, które mogą łączyć się z vCenter" + "core_pcc_top_guide_13_title": "Autoryzacja adresów IP, które mogą łączyć się z vCenter", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Director" } diff --git a/packages/manager/apps/dedicated/client/app/common/translations/Messages_pt_PT.json b/packages/manager/apps/dedicated/client/app/common/translations/Messages_pt_PT.json index c1156892727d..acfa768c9044 100644 --- a/packages/manager/apps/dedicated/client/app/common/translations/Messages_pt_PT.json +++ b/packages/manager/apps/dedicated/client/app/common/translations/Messages_pt_PT.json @@ -546,5 +546,6 @@ "common_resiliate_contact_support": "Para cancelar este serviço, contacte o nosso apoio ao cliente através do +351 213 155 642. Obrigado pela sua compreensão.", "core_pcc_top_guide_11_title": "Documentação oficial da Nutanix", "core_pcc_top_guide_12_title": "Documentação oficial do SAP HANA on Private Cloud", - "core_pcc_top_guide_13_title": "Autorizar endereços IP a ligar-se ao vCenter" + "core_pcc_top_guide_13_title": "Autorizar endereços IP a ligar-se ao vCenter", + "core_pcc_top_guide_14_title": "VMware on OVHcloud - VMware Cloud Diretor" } diff --git a/packages/manager/apps/dedicated/client/app/config/constants.config.js b/packages/manager/apps/dedicated/client/app/config/constants.config.js index 00c6bd37effb..36ec8bf045a4 100644 --- a/packages/manager/apps/dedicated/client/app/config/constants.config.js +++ b/packages/manager/apps/dedicated/client/app/config/constants.config.js @@ -1143,6 +1143,12 @@ const constants = { atInternetClickTag: 'TopGuide-PrivateCloud-10', url: 'http://pubs.vmware.com/NSX-62/index.jsp?lang=fr', }, + { + title: 'core_pcc_top_guide_14_title', + atInternetClickTag: 'TopGuide-PrivateCloud-14', + url: + 'https://help.ovhcloud.com/csm/fr-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad&spa=1', + }, ], de_DE: [ { @@ -1202,6 +1208,12 @@ const constants = { url: 'https://docs.vmware.com/de/VMware-NSX-Data-Center-for-vSphere/index.html', }, + { + title: 'core_pcc_top_guide_14_title', + atInternetClickTag: 'TopGuide-PrivateCloud-14', + url: + 'https://help.ovhcloud.com/csm/worldeuro-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + }, ], en_GB: [ { @@ -1258,6 +1270,12 @@ const constants = { atInternetClickTag: 'TopGuide-PrivateCloud-10', url: 'http://pubs.vmware.com/NSX-62/index.jsp?lang=en', }, + { + title: 'core_pcc_top_guide_14_title', + atInternetClickTag: 'TopGuide-PrivateCloud-14', + url: + 'https://help.ovhcloud.com/csm/worldeuro-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + }, ], }, }, @@ -1831,6 +1849,12 @@ const constants = { atInternetClickTag: 'TopGuide-PrivateCloud-10', url: 'http://pubs.vmware.com/NSX-62/index.jsp?lang=fr', }, + { + title: 'core_pcc_top_guide_14_title', + atInternetClickTag: 'TopGuide-PrivateCloud-14v', + url: + 'https://help.ovhcloud.com/csm/fr-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad&spa=1', + }, ], de_DE: [ { @@ -1890,6 +1914,12 @@ const constants = { url: 'https://docs.vmware.com/de/VMware-NSX-Data-Center-for-vSphere/index.html', }, + { + title: 'core_pcc_top_guide_14_title', + atInternetClickTag: 'TopGuide-PrivateCloud-14', + url: + 'https://help.ovhcloud.com/csm/worldeuro-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + }, ], en_GB: [ { @@ -1946,6 +1976,12 @@ const constants = { atInternetClickTag: 'TopGuide-PrivateCloud-10', url: 'http://pubs.vmware.com/NSX-62/index.jsp?lang=en', }, + { + title: 'core_pcc_top_guide_14_title', + atInternetClickTag: 'TopGuide-PrivateCloud-14', + url: + 'https://help.ovhcloud.com/csm/worldeuro-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + }, ], }, }, diff --git a/packages/manager/apps/dedicated/client/app/dedicatedCloud/details/dedicatedCloud.routing.js b/packages/manager/apps/dedicated/client/app/dedicatedCloud/details/dedicatedCloud.routing.js index 4d922e778039..30eb74f42a57 100644 --- a/packages/manager/apps/dedicated/client/app/dedicatedCloud/details/dedicatedCloud.routing.js +++ b/packages/manager/apps/dedicated/client/app/dedicatedCloud/details/dedicatedCloud.routing.js @@ -95,9 +95,11 @@ export default /* @ngInject */ ($stateProvider) => { managedVCDAvailability: /* @ngInject */ (ovhFeatureFlipping) => ovhFeatureFlipping - .checkFeatureAvailability('hpc-vmware-managed-vcd') + .checkFeatureAvailability('dedicated-cloud:vcd-migration') .then((featureAvailability) => - featureAvailability.isFeatureAvailable('hpc-vmware-managed-vcd'), + featureAvailability.isFeatureAvailable( + 'dedicated-cloud:vcd-migration', + ), ), dedicatedCloudServiceInfos: /* @ngInject */ ( diff --git a/packages/manager/apps/dedicated/client/app/managedBaremetal/details/managed-baremetal.routing.js b/packages/manager/apps/dedicated/client/app/managedBaremetal/details/managed-baremetal.routing.js index 335ae4aa1a43..3d16e706e87f 100644 --- a/packages/manager/apps/dedicated/client/app/managedBaremetal/details/managed-baremetal.routing.js +++ b/packages/manager/apps/dedicated/client/app/managedBaremetal/details/managed-baremetal.routing.js @@ -93,9 +93,11 @@ export default /* @ngInject */ ($stateProvider) => { managedVCDAvailability: /* @ngInject */ (ovhFeatureFlipping) => ovhFeatureFlipping - .checkFeatureAvailability('hpc-vmware-managed-vcd') + .checkFeatureAvailability('dedicated-cloud:vcd-migration') .then((featureAvailability) => - featureAvailability.isFeatureAvailable('hpc-vmware-managed-vcd'), + featureAvailability.isFeatureAvailable( + 'dedicated-cloud:vcd-migration', + ), ), dedicatedCloudServiceInfos: /* @ngInject */ ( diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/.gitignore b/packages/manager/apps/hpc-vmware-managed-vcd/.gitignore new file mode 100644 index 000000000000..4ebc8aea50e0 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/.gitignore @@ -0,0 +1 @@ +coverage diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/README.md b/packages/manager/apps/hpc-vmware-managed-vcd/README.md new file mode 100644 index 000000000000..d3b80766d4cf --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/README.md @@ -0,0 +1,3 @@ +# @ovh-ux/manager-hpc-vmware-managed-vcd-app + +> New managed VMware cloud director offers diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/cucumber.js b/packages/manager/apps/hpc-vmware-managed-vcd/cucumber.js new file mode 100644 index 000000000000..8e6abbfbca8f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/cucumber.js @@ -0,0 +1,20 @@ +const isCI = process.env.CI; + +module.exports = { + default: { + paths: ['e2e/features/**/*.feature'], + require: [ + '../../../../playwright-helpers/bdd-setup.ts', + 'e2e/**/*.step.ts', + ], + requireModule: ['ts-node/register'], + format: [ + 'summary', + isCI ? 'progress' : 'progress-bar', + !isCI && ['html', 'e2e/reports/cucumber-results-report.html'], + !isCI && ['usage-json', 'e2e/reports/cucumber-usage-report.json'], + ].filter(Boolean), + formatOptions: { snippetInterface: 'async-await' }, + retry: 1, + }, +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/e2e/features/onboarding.feature b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/features/onboarding.feature new file mode 100644 index 000000000000..3b64e213c20f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/features/onboarding.feature @@ -0,0 +1,7 @@ +Feature: Onboarding page + + Scenario: User wants to find informations related to hpc-vmware-managed-vcd + Given User has 0 elements in the Listing page + When User navigates to Listing page + Then User gets redirected to Onboarding page + Then User sees 3 guides diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/e2e/step-definitions/onboarding.step.ts b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/step-definitions/onboarding.step.ts new file mode 100644 index 000000000000..67b20b6e52c8 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/step-definitions/onboarding.step.ts @@ -0,0 +1,32 @@ +import { Given, When, Then } from '@cucumber/cucumber'; +import { expect } from '@playwright/test'; +import { ICustomWorld } from '../../../../../../playwright-helpers'; +import { ConfigParams, getUrl, setupNetwork } from '../utils'; + +Given('User has {int} elements in the Listing page', function( + this: ICustomWorld, + nb: number, +) { + this.handlersConfig.nb = nb; +}); + +When('User navigates to Listing page', async function( + this: ICustomWorld, +) { + await setupNetwork(this); + await this.page.goto(getUrl('listing'), { waitUntil: 'load' }); +}); + +Then('User gets redirected to Onboarding page', async function( + this: ICustomWorld, +) { + await expect(this.page).toHaveURL(getUrl('onboarding')); +}); + +Then('User sees {int} guides', async function( + this: ICustomWorld, + nbGuides: number, +) { + const guides = await this.page.locator('osds-tile'); + await expect(guides).toHaveCount(nbGuides); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/constants.ts new file mode 100644 index 000000000000..866e6dadabe9 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/constants.ts @@ -0,0 +1,7 @@ +import { urls } from '../../src/routes/routes.constant'; + +export const appUrl = 'http://localhost:9001/app'; + +export type AppRoute = keyof typeof urls; + +export const getUrl = (route: AppRoute) => `${appUrl}/#${urls[route]}`; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/index.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/index.tsx new file mode 100644 index 000000000000..24a453c58aa9 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/index.tsx @@ -0,0 +1,2 @@ +export * from './network'; +export * from './constants'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/network.ts b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/network.ts new file mode 100644 index 000000000000..97b9b13964ef --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/e2e/utils/network.ts @@ -0,0 +1,21 @@ +import { BrowserContext } from '@playwright/test'; +import { + ICustomWorld, + toPlaywrightMockHandler, + Handler, +} from '../../../../../../playwright-helpers'; +import { GetAuthenticationMocks } from '../../../../../../playwright-helpers/mocks/auth'; + +export type ConfigParams = GetAuthenticationMocks; + +export const getConfig = (params: ConfigParams): Handler[] => []; + +export const setupNetwork = async (world: ICustomWorld) => + Promise.all( + getConfig({ + ...((world?.handlersConfig as ConfigParams) || ({} as ConfigParams)), + isAuthMocked: true, + }) + .reverse() + .map(toPlaywrightMockHandler(world.context as BrowserContext)), + ); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/index.html b/packages/manager/apps/hpc-vmware-managed-vcd/index.html new file mode 100644 index 000000000000..ec4e92d05007 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/index.html @@ -0,0 +1,22 @@ + + + + + + + + OVHcloud + + + + + +
+ + + diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.handler.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.handler.ts new file mode 100644 index 000000000000..cb2b8e6ae4f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.handler.ts @@ -0,0 +1,15 @@ +import { PathParams } from 'msw'; +import { Handler } from '../../../../../../playwright-helpers'; +import { resourceList } from './iam.mock'; + +const findResourceByUrn = (params: PathParams) => + resourceList.find(({ urn }) => urn === params.urn); + +export const getIamMocks = (): Handler[] => [ + { + url: '/iam/resource/:urn/authorization/check', + response: (_: unknown, params: PathParams) => findResourceByUrn(params), + api: 'v2', + method: 'post', + }, +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.mock.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.mock.ts new file mode 100644 index 000000000000..9c7b36f89c6a --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/iam/iam.mock.ts @@ -0,0 +1,22 @@ +import { IamCheckResponse } from '@ovh-ux/manager-react-components'; +import { organizationList } from '../vcd-organization/vcd-organization.mock'; +import { iamActions } from '@/utils/iam.constants'; + +export const resourceList: IamCheckResponse[] = [ + { + urn: organizationList[0].iam.urn, + authorizedActions: [ + iamActions.vmwareCloudDirectorApiovhOrganizationEdit, + iamActions.vmwareCloudDirectorApiovhOrganizationVirtualDataCenterEdit, + ], + unauthorizedActions: [], + }, + { + urn: organizationList[1].iam.urn, + authorizedActions: [ + iamActions.vmwareCloudDirectorApiovhOrganizationEdit, + iamActions.vmwareCloudDirectorApiovhOrganizationVirtualDataCenterEdit, + ], + unauthorizedActions: [], + }, +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/index.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/index.ts new file mode 100644 index 000000000000..05a214fbbb99 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/index.ts @@ -0,0 +1,3 @@ +export * from './iam/iam.handler'; +export * from './vcd-organization/vcd-organization.handler'; +export * from './veeam-backup/veeam-backup.handler'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-datacentre.mock.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-datacentre.mock.ts new file mode 100644 index 000000000000..f3830048da4b --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-datacentre.mock.ts @@ -0,0 +1,32 @@ +import IVcdDatacentre from '../../src/types/vcd-datacenter.interface'; + +export const datacentreList: IVcdDatacentre[] = [ + { + id: 'vdc-eu-central-waw-adc311b5-0c0b-4071-b48f-b20813868bcf', + resourceStatus: 'READY', + currentState: { + commercialRange: 'STANDARD', + description: + 'Pour vous proposer une description adaptée, pourriez-vous me donner plus de détails sur votre service ? Cela me permettra de créer une description précise et impactante qui tient dans la limite des 255 caractères.', + ipQuota: 10, + memoryQuota: 64, + name: 'vdc-eu-central-waw-adc311b5-0c0b-4071-b48f-b20813868bcf', + region: 'EU-CENTRAL-WAW', + storageQuota: 1, + vCPUCount: 16, + vCPUSpeed: 3, + }, + currentTasks: [], + targetSpec: { + description: + 'Pour vous proposer une description adaptée, pourriez-vous me donner plus de détails sur votre service ? Cela me permettra de créer une description précise et impactante qui tient dans la limite des 255 caractères.', + vCPUSpeed: 3, + }, + updatedAt: '2024-09-23T13:53:49Z', + iam: { + id: '33dda1c2-b24e-4db2-b7f3-4f3a8e08d68f', + urn: + 'urn:v1:eu:resource:vmwareCloudDirector:org-eu-central-waw-366861de-e0e4-4ad5-a4c5-e9f80d744142/virtualDataCenter/vdc-eu-central-waw-adc311b5-0c0b-4071-b48f-b20813868bcf', + }, + }, +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.handler.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.handler.ts new file mode 100644 index 000000000000..f7946ad71e6a --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.handler.ts @@ -0,0 +1,71 @@ +import { PathParams } from 'msw'; +import { Handler } from '../../../../../../playwright-helpers'; +import { organizationList } from './vcd-organization.mock'; +import { datacentreList } from './vcd-datacentre.mock'; + +export type GetOrganizationMocksParams = { + isOrganizationKo?: boolean; + isOrganizationUpdateKo?: boolean; + nbOrganization?: number; + allOrgsBackedUp?: boolean; + isDatacentresKo?: boolean; + nbDatacentres?: number; +}; + +const findOrganizationById = (params: PathParams) => + organizationList.find(({ id }) => id === params.id); + +export const getOrganizationMocks = ({ + isOrganizationKo, + isOrganizationUpdateKo, + nbOrganization = Number.POSITIVE_INFINITY, + allOrgsBackedUp, + isDatacentresKo, + nbDatacentres = Number.POSITIVE_INFINITY, +}: GetOrganizationMocksParams): Handler[] => { + const nb = allOrgsBackedUp ? 1 : nbOrganization; + return [ + { + url: '/vmwareCloudDirector/organization/:id/virtualDataCenter', + response: isDatacentresKo + ? { + message: 'Datacentres error', + } + : datacentreList.slice(0, nbDatacentres), + api: 'v2', + status: isDatacentresKo ? 500 : 200, + }, + { + url: '/vmwareCloudDirector/organization/:id', + response: isOrganizationUpdateKo + ? { + message: 'Organization update error', + } + : {}, + method: 'put', + api: 'v2', + status: isOrganizationUpdateKo ? 500 : 200, + }, + { + url: '/vmwareCloudDirector/organization/:id', + response: (_: unknown, params: PathParams) => + isOrganizationKo + ? { + message: 'Organization error', + } + : findOrganizationById(params), + api: 'v2', + status: isOrganizationKo ? 500 : 200, + }, + { + url: '/vmwareCloudDirector/organization', + response: isOrganizationKo + ? { + message: 'Organization error', + } + : organizationList.slice(0, nb), + status: isOrganizationKo ? 500 : 200, + api: 'v2', + }, + ]; +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.mock.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.mock.ts new file mode 100644 index 000000000000..963b0a20aedf --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/vcd-organization/vcd-organization.mock.ts @@ -0,0 +1,60 @@ +import IVcdOrganization from '../../src/types/vcd-organization.interface'; + +export const organizationList: IVcdOrganization[] = [ + { + currentState: { + apiUrl: 'https://vcd.my.company', + billingType: 'MONTHLY', + description: 'Company VCD Organization', + fullName: 'Company VCD', + region: 'EU-WEST-GRA', + name: 'org-eu-west-gra-6cfa2c69-c62c-4853-80ee-c9682e6727f0', + spla: false, + webInterfaceUrl: 'https://vcd.my.company', + }, + currentTasks: [ + { + id: '1fda9001-a48b-4022-a656-ac295d363470', + link: + '/v2/vmwareCloudDirector/organization/6cfa2c69-c62c-4853-80ee-c9682e6727f0/task/1fda9001-a48b-4022-a656-ac295d363470', + status: 'PENDING', + type: 'VCD_UPDATE', + }, + ], + id: '6cfa2c69-c62c-4853-80ee-c9682e6727f0', + resourceStatus: 'UPDATING', + targetSpec: { + description: 'Company production VCD Organization', + fullName: 'Company VCD', + }, + updatedAt: '2024-06-14T09:21:21.943Z', + iam: { + id: 'id1', + urn: 'urn:1', + }, + }, + { + currentState: { + apiUrl: 'https://vcd.my.demo.lab', + billingType: 'DEMO', + description: 'My demo VCD Organization', + fullName: 'Demo VCD', + region: 'CA-EAST-BHS', + name: 'org-ca-east-bhs-61ebdcec-0623-4a61-834f-a1719cd475b4', + spla: true, + webInterfaceUrl: 'https://vcd.my.second.lab', + }, + currentTasks: [], + id: '61ebdcec-0623-4a61-834f-a1719cd475b4', + resourceStatus: 'READY', + targetSpec: { + description: 'My demo VCD Organization', + fullName: 'Demo VCD', + }, + updatedAt: '2024-06-14T09:21:21.943Z', + iam: { + id: 'id2', + urn: 'urn:2', + }, + }, +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.handler.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.handler.ts new file mode 100644 index 000000000000..f27b17cbeb17 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.handler.ts @@ -0,0 +1,38 @@ +import { PathParams } from 'msw'; +import { Handler } from '../../../../../../playwright-helpers'; +import { backupList } from './veeam-backup.mock'; + +export type GetVeeamBackupMocksParams = { + isBackupKo?: boolean; + nbBackup?: number; +}; + +const findBackupById = (params: PathParams) => + backupList.find(({ id }) => id === params.id); + +export const getVeeamBackupMocks = ({ + isBackupKo, + nbBackup = Number.POSITIVE_INFINITY, +}: GetVeeamBackupMocksParams): Handler[] => [ + { + url: '/vmwareCloudDirector/backup/:id', + response: (_: unknown, params: PathParams) => + isBackupKo + ? { + message: 'Backup error', + } + : findBackupById(params), + status: isBackupKo ? 500 : 200, + api: 'v2', + }, + { + url: '/vmwareCloudDirector/backup', + response: isBackupKo + ? { + message: 'Backup error', + } + : backupList.slice(0, nbBackup), + status: isBackupKo ? 500 : 200, + api: 'v2', + }, +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.mock.ts b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.mock.ts new file mode 100644 index 000000000000..c3d4cf19fc8b --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/mocks/veeam-backup/veeam-backup.mock.ts @@ -0,0 +1,49 @@ +import IVcdOrganizationBackup, { + BackupResourceStatus, +} from '../../src/types/vcd-organization-backup.interface'; +import { organizationList } from '../vcd-organization/vcd-organization.mock'; + +export const backupList: IVcdOrganizationBackup[] = [ + { + id: `${organizationList[0].id}-veeam-backup`, + iam: { + displayName: 'Company A backup service', + id: 'daf6f34e-4b19-11ef-97b7-0050568ce122', + urn: 'urn:v1:resource:vmwareCloudDirectorBackup:BackupA', + }, + currentState: { + offers: [ + { + name: 'BRONZE', + quotaInTB: 100, + usedSpaceInGB: 50, + status: 'READY', + }, + { + name: 'SILVER', + quotaInTB: 100, + usedSpaceInGB: 50, + status: 'READY', + }, + ], + region: 'CA-EAST-BHS', + }, + updatedAt: '2024-06-14T09:21:21.943Z', + createdAt: '2024-06-14T09:21:21.943Z', + resourceStatus: BackupResourceStatus.READY, + targetSpec: { + offers: [ + { + name: 'BRONZE', + quotaInTB: 100, + status: 'READY', + }, + { + name: 'SILVER', + quotaInTB: 100, + status: 'READY', + }, + ], + }, + }, +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/package.json b/packages/manager/apps/hpc-vmware-managed-vcd/package.json new file mode 100644 index 000000000000..fb62a9ec5c98 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/package.json @@ -0,0 +1,74 @@ +{ + "name": "@ovh-ux/manager-hpc-vmware-managed-vcd-app", + "version": "0.0.0", + "private": true, + "description": "New managed VMware Cloud Director offers", + "repository": { + "type": "git", + "url": "git+https://github.com/ovh/manager.git", + "directory": "packages/manager/apps/hpc-vmware-managed-vcd" + }, + "license": "BSD-3-Clause", + "author": "OVH SAS", + "scripts": { + "build": "tsc && vite build", + "coverage": "vitest run --coverage", + "dev": "tsc && vite", + "start": "lerna exec --stream --scope='@ovh-ux/manager-hpc-vmware-managed-vcd-app' --include-dependencies -- npm run build --if-present", + "start:dev": "lerna exec --stream --scope='@ovh-ux/manager-hpc-vmware-managed-vcd-app' --include-dependencies -- npm run dev --if-present", + "start:watch": "lerna exec --stream --parallel --scope='@ovh-ux/manager-hpc-vmware-managed-vcd-app' --include-dependencies -- npm run dev:watch --if-present", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "test:e2e": "tsc && node ../../../../scripts/run-playwright-bdd.js", + "test:e2e:cii": "tsc && node ../../../../scripts/run-playwright-bdd.js --ci" + }, + "dependencies": { + "@ovh-ux/manager-config": "*", + "@ovh-ux/manager-core-api": "*", + "@ovh-ux/manager-core-utils": "*", + "@ovh-ux/manager-module-order": "^0.5.0", + "@ovh-ux/manager-react-components": "^1.30.0", + "@ovh-ux/manager-react-shell-client": "*", + "@ovh-ux/manager-tailwind-config": "*", + "@ovh-ux/request-tagger": "*", + "@ovhcloud/ods-common-core": "17.2.2", + "@ovhcloud/ods-common-theming": "17.2.2", + "@ovhcloud/ods-components": "17.2.2", + "@ovhcloud/ods-theme-blue-jeans": "17.2.2", + "@tanstack/react-query": "5.51.21", + "@tanstack/react-query-devtools": "5.51.21", + "axios": "^1.1.2", + "clsx": "^1.2.1", + "i18next": "^23.8.2", + "i18next-http-backend": "^2.4.3", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-i18next": "^14.0.5", + "react-router-dom": "^6.3.0", + "tailwindcss": "^3.3.3" + }, + "devDependencies": { + "@cucumber/cucumber": "^10.3.1", + "@ovh-ux/manager-vite-config": "*", + "@playwright/test": "^1.41.2", + "@testing-library/dom": "^10.1.0", + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^16.0.0", + "@testing-library/user-event": "^13.2.1", + "@types/react": "^18.2.55", + "@types/react-dom": "^18.2.19", + "@vitejs/plugin-react": "^4.2.1", + "@vitest/coverage-v8": "^1.2.0", + "autoprefixer": "^10.4.17", + "element-internals-polyfill": "^1.3.10", + "msw": "2.1.7", + "typescript": "^4.3.2", + "vite": "^4.5.0", + "vitest": "^1.2.0" + }, + "regions": [ + "CA", + "EU", + "US" + ] +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/playwright.config.ts b/packages/manager/apps/hpc-vmware-managed-vcd/playwright.config.ts new file mode 100644 index 000000000000..feb249bcbe3f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/playwright.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + workers: 3, + fullyParallel: false, + timeout: 30 * 1000, + reporter: [['html', { open: 'on-failure' }]], + expect: { + timeout: 20000, + }, + use: { + // Collect trace when retrying the failed test. + trace: 'retain-on-failure', + }, + testMatch: '**/*.e2e.ts', + webServer: { + command: 'yarn run dev', + url: 'http://localhost:9000/', + }, +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/postcss.config.js b/packages/manager/apps/hpc-vmware-managed-vcd/postcss.config.js new file mode 100644 index 000000000000..12a703d900da --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_de_DE.json new file mode 100644 index 000000000000..a3768904d63f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_de_DE.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "Allgemeine Informationen", + "managed_vcd_dashboard_datacentres_title": "Rechenzentren", + "managed_vcd_dashboard_datacentres_label": "Rechenzentren", + "managed_vcd_dashboard_description": "Beschreibung", + "managed_vcd_dashboard_name": "Name", + "managed_vcd_dashboard_localisation": "Region", + "managed_vcd_dashboard_datacentres_count": "Anzahl der Rechenzentren", + "managed_vcd_dashboard_management_interface": "Verwaltungsinterface", + "managed_vcd_dashboard_management_interface_access": "Zu VCD wechseln", + "managed_vcd_dashboard_api_url": "API-URL", + "managed_vcd_dashboard_options": "Optionen", + "managed_vcd_dashboard_windows_license": "Windows Lizenz ", + "managed_vcd_dashboard_windows_license_activate": "Aktivieren", + "managed_vcd_dashboard_windows_license_active": "Ihre SPLA-Lizenz ist aktiviert.", + "managed_vcd_dashboard_windows_license_unactive": "Ihre SPLA-Lizenz ist nicht aktiviert.", + "managed_vcd_dashboard_service_management": "Verwaltung der Dienstleistung", + "managed_vcd_dashboard_mailing_list": "Mailingliste", + "managed_vcd_dashboard_service_renew": "Verlängerung", + "managed_vcd_dashboard_service_cancellation": "Dienstleistung kündigen", + "managed_vcd_dashboard_password": "Passwort", + "managed_vcd_dashboard_password_renew": "Admin-Passwort erneuern", + "managed_vcd_dashboard_password_tooltip": "Wenn Sie Ihr Administrator-Passwort ändern möchten, kontaktieren Sie bitte den Support", + "managed_vcd_dashboard_back_link": "Zurück zur Liste", + "managed_vcd_dashboard_coming_soon": "Demnächst verfügbar", + "managed_vcd_dashboard_data_protection": "Datenschutz", + "managed_vcd_dashboard_backup_status_error": "Status nicht verfügbar", + "managed_vcd_dashboard_backup_status_subscribed": "abonniert", + "managed_vcd_dashboard_backup_status_unsubscribed": "Nicht abonniert", + "managed_vcd_dashboard_backup_status_creating": "Aktivierung wird durchgeführt", + "managed_vcd_dashboard_backup_status_updating": "Änderung wird durchgeführt", + "managed_vcd_dashboard_backup_status_disabling": "Wird deaktiviert", + "managed_vcd_dashboard_backup_link": "Backups verwalten", + "managed_vcd_dashboard_edit_modal_error": "Es ist ein Fehler aufgetreten: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Abbrechen", + "managed_vcd_dashboard_edit_modal_cta_edit": "Ändern", + "managed_vcd_dashboard_edit_name_modal_title": "Namen ändern", + "managed_vcd_dashboard_edit_name_modal_label": "Name", + "managed_vcd_dashboard_edit_name_modal_success": "Der Name wurde erfolgreich geändert.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Bitte geben Sie einen Namen ein, der zwischen 1 und 128 Zeichen lang ist.", + "managed_vcd_dashboard_edit_description_modal_title": "Beschreibung bearbeiten", + "managed_vcd_dashboard_edit_description_modal_label": "Beschreibung", + "managed_vcd_dashboard_edit_description_modal_success": "Die Beschreibung wurde erfolgreich bearbeitet.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Bitte geben Sie eine Beschreibung ein, die zwischen 1 und 255 Zeichen lang ist." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_en_GB.json new file mode 100644 index 000000000000..2ddb8e54a9e8 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_en_GB.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "General information", + "managed_vcd_dashboard_datacentres_title": "Datacentres", + "managed_vcd_dashboard_datacentres_label": "datacentres", + "managed_vcd_dashboard_description": "Description", + "managed_vcd_dashboard_name": "Name", + "managed_vcd_dashboard_localisation": "Region", + "managed_vcd_dashboard_datacentres_count": "Number of datacentres", + "managed_vcd_dashboard_management_interface": "Management Interface", + "managed_vcd_dashboard_management_interface_access": "Access VCD", + "managed_vcd_dashboard_api_url": "API URL", + "managed_vcd_dashboard_options": "Options", + "managed_vcd_dashboard_windows_license": "Windows licence ", + "managed_vcd_dashboard_windows_license_activate": "Activate", + "managed_vcd_dashboard_windows_license_active": "Your SPLA license is activated.", + "managed_vcd_dashboard_windows_license_unactive": "Your SPLA license is not activated.", + "managed_vcd_dashboard_service_management": "Service management", + "managed_vcd_dashboard_mailing_list": "Mailing list", + "managed_vcd_dashboard_service_renew": "Renewal", + "managed_vcd_dashboard_service_cancellation": "Cancel the service", + "managed_vcd_dashboard_password": "Password", + "managed_vcd_dashboard_password_renew": "Renew the admin password", + "managed_vcd_dashboard_password_tooltip": "If you would like to change your admin password, please contact support", + "managed_vcd_dashboard_back_link": "Back to list", + "managed_vcd_dashboard_coming_soon": "Coming soon", + "managed_vcd_dashboard_data_protection": "Data protection", + "managed_vcd_dashboard_backup_status_error": "Status unavailable", + "managed_vcd_dashboard_backup_status_subscribed": "Subscribed", + "managed_vcd_dashboard_backup_status_unsubscribed": "Not subscribed", + "managed_vcd_dashboard_backup_status_creating": "Activating", + "managed_vcd_dashboard_backup_status_updating": "Modifying", + "managed_vcd_dashboard_backup_status_disabling": "Deactivating", + "managed_vcd_dashboard_backup_link": "Manage your backups", + "managed_vcd_dashboard_edit_modal_error": "An error has occurred: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Cancel", + "managed_vcd_dashboard_edit_modal_cta_edit": "Modify", + "managed_vcd_dashboard_edit_name_modal_title": "Change name", + "managed_vcd_dashboard_edit_name_modal_label": "Name", + "managed_vcd_dashboard_edit_name_modal_success": "The name has been modified.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Please enter a name between 1 and 128 characters long.", + "managed_vcd_dashboard_edit_description_modal_title": "Edit description", + "managed_vcd_dashboard_edit_description_modal_label": "Description", + "managed_vcd_dashboard_edit_description_modal_success": "The description has been modified.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Please enter a description with a length between 1 and 255 characters." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_es_ES.json new file mode 100644 index 000000000000..314f7814f5aa --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_es_ES.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "Datos generales", + "managed_vcd_dashboard_datacentres_title": "Datacenters", + "managed_vcd_dashboard_datacentres_label": "datacenters", + "managed_vcd_dashboard_description": "Descripción", + "managed_vcd_dashboard_name": "Nombre", + "managed_vcd_dashboard_localisation": "Zona", + "managed_vcd_dashboard_datacentres_count": "Número de datacenters", + "managed_vcd_dashboard_management_interface": "Interfaz de gestión", + "managed_vcd_dashboard_management_interface_access": "Acceder a VCD", + "managed_vcd_dashboard_api_url": "URL API", + "managed_vcd_dashboard_options": "Opciones", + "managed_vcd_dashboard_windows_license": "Licencia Windows", + "managed_vcd_dashboard_windows_license_activate": "Activar", + "managed_vcd_dashboard_windows_license_active": "Su licencia SPLA está activada.", + "managed_vcd_dashboard_windows_license_unactive": "Su licencia SPLA no está activada.", + "managed_vcd_dashboard_service_management": "Gestión del servicio", + "managed_vcd_dashboard_mailing_list": "Listas de correo", + "managed_vcd_dashboard_service_renew": "Renovación ", + "managed_vcd_dashboard_service_cancellation": "Dar de baja el servicio", + "managed_vcd_dashboard_password": "Contraseña", + "managed_vcd_dashboard_password_renew": "Renovar la contraseña de administrador", + "managed_vcd_dashboard_password_tooltip": "Si desea cambiar la contraseña de administrador, póngase en contacto con el soporte", + "managed_vcd_dashboard_back_link": "Volver a la lista", + "managed_vcd_dashboard_coming_soon": "Próximamente", + "managed_vcd_dashboard_data_protection": "Protección de datos", + "managed_vcd_dashboard_backup_status_error": "Estado no disponible", + "managed_vcd_dashboard_backup_status_subscribed": "Contratar", + "managed_vcd_dashboard_backup_status_unsubscribed": "No suscrito", + "managed_vcd_dashboard_backup_status_creating": "Activación en curso", + "managed_vcd_dashboard_backup_status_updating": "Modificando", + "managed_vcd_dashboard_backup_status_disabling": "Desactivación en curso", + "managed_vcd_dashboard_backup_link": "Gestionar las copias de seguridad", + "managed_vcd_dashboard_edit_modal_error": "Se ha producido un error: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Cancelar", + "managed_vcd_dashboard_edit_modal_cta_edit": "Modificar", + "managed_vcd_dashboard_edit_name_modal_title": "Modificar el nombre", + "managed_vcd_dashboard_edit_name_modal_label": "Nombre", + "managed_vcd_dashboard_edit_name_modal_success": "El nombre se ha modificado correctamente.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Introduzca un nombre de entre 1 y 128 caracteres.", + "managed_vcd_dashboard_edit_description_modal_title": "Modificar la descripción", + "managed_vcd_dashboard_edit_description_modal_label": "Descripción", + "managed_vcd_dashboard_edit_description_modal_success": "La descripción se ha modificado correctamente.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Introduce una descripción que tenga entre 1 y 255 caracteres." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_CA.json new file mode 100644 index 000000000000..594a2a4f1f95 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_CA.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "Informations générales", + "managed_vcd_dashboard_datacentres_title": "Datacentres", + "managed_vcd_dashboard_datacentres_label": "datacentres", + "managed_vcd_dashboard_description": "Description", + "managed_vcd_dashboard_name": "Nom", + "managed_vcd_dashboard_localisation": "Région", + "managed_vcd_dashboard_datacentres_count": "Nombre de datacentres", + "managed_vcd_dashboard_management_interface": "Interface de gestion", + "managed_vcd_dashboard_management_interface_access": "Accéder à VCD", + "managed_vcd_dashboard_api_url": "URL API", + "managed_vcd_dashboard_options": "Options", + "managed_vcd_dashboard_windows_license": "Licence Windows", + "managed_vcd_dashboard_windows_license_activate": "Activer", + "managed_vcd_dashboard_windows_license_active": "Votre licence spla est activée.", + "managed_vcd_dashboard_windows_license_unactive": "Votre licence spla n'est pas activée.", + "managed_vcd_dashboard_service_management": "Gestion du service", + "managed_vcd_dashboard_mailing_list": "Mailing list", + "managed_vcd_dashboard_service_renew": "Renouvellement", + "managed_vcd_dashboard_service_cancellation": "Résilier le service", + "managed_vcd_dashboard_password": "Mot de passe", + "managed_vcd_dashboard_password_renew": "Renouveler le mot de passe admin", + "managed_vcd_dashboard_password_tooltip": "Si vous souhaitez changer votre mot de passe administrateur, merci de contacter le support", + "managed_vcd_dashboard_back_link": "Retour à la liste", + "managed_vcd_dashboard_coming_soon": "Bientôt disponible", + "managed_vcd_dashboard_data_protection": "Protection de Données", + "managed_vcd_dashboard_backup_status_error": "Statut indisponible", + "managed_vcd_dashboard_backup_status_subscribed": "Souscrit", + "managed_vcd_dashboard_backup_status_unsubscribed": "Non souscrit", + "managed_vcd_dashboard_backup_status_creating": "Activation en cours", + "managed_vcd_dashboard_backup_status_updating": "Modification en cours", + "managed_vcd_dashboard_backup_status_disabling": "Désactivation en cours", + "managed_vcd_dashboard_backup_link": "Gérer vos sauvegardes", + "managed_vcd_dashboard_edit_modal_error": "Une erreur est survenue: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Annuler", + "managed_vcd_dashboard_edit_modal_cta_edit": "Modifier", + "managed_vcd_dashboard_edit_name_modal_title": "Modifier le nom", + "managed_vcd_dashboard_edit_name_modal_label": "Nom", + "managed_vcd_dashboard_edit_name_modal_success": "Le nom a été modifié avec succès.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Veuillez saisir un nom dont la longueur est comprise entre 1 et 128 caractères.", + "managed_vcd_dashboard_edit_description_modal_title": "Modifier la description", + "managed_vcd_dashboard_edit_description_modal_label": "Description", + "managed_vcd_dashboard_edit_description_modal_success": "La description a été modifiée avec succès.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Veuillez saisir une description dont la longueur est comprise entre 1 et 255 caractères." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_FR.json new file mode 100644 index 000000000000..594a2a4f1f95 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_fr_FR.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "Informations générales", + "managed_vcd_dashboard_datacentres_title": "Datacentres", + "managed_vcd_dashboard_datacentres_label": "datacentres", + "managed_vcd_dashboard_description": "Description", + "managed_vcd_dashboard_name": "Nom", + "managed_vcd_dashboard_localisation": "Région", + "managed_vcd_dashboard_datacentres_count": "Nombre de datacentres", + "managed_vcd_dashboard_management_interface": "Interface de gestion", + "managed_vcd_dashboard_management_interface_access": "Accéder à VCD", + "managed_vcd_dashboard_api_url": "URL API", + "managed_vcd_dashboard_options": "Options", + "managed_vcd_dashboard_windows_license": "Licence Windows", + "managed_vcd_dashboard_windows_license_activate": "Activer", + "managed_vcd_dashboard_windows_license_active": "Votre licence spla est activée.", + "managed_vcd_dashboard_windows_license_unactive": "Votre licence spla n'est pas activée.", + "managed_vcd_dashboard_service_management": "Gestion du service", + "managed_vcd_dashboard_mailing_list": "Mailing list", + "managed_vcd_dashboard_service_renew": "Renouvellement", + "managed_vcd_dashboard_service_cancellation": "Résilier le service", + "managed_vcd_dashboard_password": "Mot de passe", + "managed_vcd_dashboard_password_renew": "Renouveler le mot de passe admin", + "managed_vcd_dashboard_password_tooltip": "Si vous souhaitez changer votre mot de passe administrateur, merci de contacter le support", + "managed_vcd_dashboard_back_link": "Retour à la liste", + "managed_vcd_dashboard_coming_soon": "Bientôt disponible", + "managed_vcd_dashboard_data_protection": "Protection de Données", + "managed_vcd_dashboard_backup_status_error": "Statut indisponible", + "managed_vcd_dashboard_backup_status_subscribed": "Souscrit", + "managed_vcd_dashboard_backup_status_unsubscribed": "Non souscrit", + "managed_vcd_dashboard_backup_status_creating": "Activation en cours", + "managed_vcd_dashboard_backup_status_updating": "Modification en cours", + "managed_vcd_dashboard_backup_status_disabling": "Désactivation en cours", + "managed_vcd_dashboard_backup_link": "Gérer vos sauvegardes", + "managed_vcd_dashboard_edit_modal_error": "Une erreur est survenue: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Annuler", + "managed_vcd_dashboard_edit_modal_cta_edit": "Modifier", + "managed_vcd_dashboard_edit_name_modal_title": "Modifier le nom", + "managed_vcd_dashboard_edit_name_modal_label": "Nom", + "managed_vcd_dashboard_edit_name_modal_success": "Le nom a été modifié avec succès.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Veuillez saisir un nom dont la longueur est comprise entre 1 et 128 caractères.", + "managed_vcd_dashboard_edit_description_modal_title": "Modifier la description", + "managed_vcd_dashboard_edit_description_modal_label": "Description", + "managed_vcd_dashboard_edit_description_modal_success": "La description a été modifiée avec succès.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Veuillez saisir une description dont la longueur est comprise entre 1 et 255 caractères." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_it_IT.json new file mode 100644 index 000000000000..466d2897719a --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_it_IT.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "Informazioni generali", + "managed_vcd_dashboard_datacentres_title": "Datacenter", + "managed_vcd_dashboard_datacentres_label": "datacenter", + "managed_vcd_dashboard_description": "Descrizione", + "managed_vcd_dashboard_name": "Cognome", + "managed_vcd_dashboard_localisation": "Regione", + "managed_vcd_dashboard_datacentres_count": "Numero di datacenter", + "managed_vcd_dashboard_management_interface": "Interfaccia di gestione", + "managed_vcd_dashboard_management_interface_access": "Accedi a VCD", + "managed_vcd_dashboard_api_url": "URL API", + "managed_vcd_dashboard_options": "Opzioni", + "managed_vcd_dashboard_windows_license": "Licenza Windows", + "managed_vcd_dashboard_windows_license_activate": "Attiva", + "managed_vcd_dashboard_windows_license_active": "La tua licenza SPLA è attiva.", + "managed_vcd_dashboard_windows_license_unactive": "La tua licenza SPLA non è attiva.", + "managed_vcd_dashboard_service_management": "Gestione del servizio", + "managed_vcd_dashboard_mailing_list": "Mailing list", + "managed_vcd_dashboard_service_renew": "Rinnovo", + "managed_vcd_dashboard_service_cancellation": "Disattiva il servizio", + "managed_vcd_dashboard_password": "Password", + "managed_vcd_dashboard_password_renew": "Rinnova la password admin", + "managed_vcd_dashboard_password_tooltip": "Per modificare la password amministratore, contatta il supporto", + "managed_vcd_dashboard_back_link": "Torna alla lista", + "managed_vcd_dashboard_coming_soon": "Presto disponibile", + "managed_vcd_dashboard_data_protection": "Protezione dei Dati", + "managed_vcd_dashboard_backup_status_error": "Stato non disponibile", + "managed_vcd_dashboard_backup_status_subscribed": "Sottoscritto", + "managed_vcd_dashboard_backup_status_unsubscribed": "Non sottoscritto", + "managed_vcd_dashboard_backup_status_creating": "Attivazione in corso", + "managed_vcd_dashboard_backup_status_updating": "Modifica in corso", + "managed_vcd_dashboard_backup_status_disabling": "Disattivazione in corso", + "managed_vcd_dashboard_backup_link": "Gestire i backup", + "managed_vcd_dashboard_edit_modal_error": "Si è verificato un errore: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Annulla", + "managed_vcd_dashboard_edit_modal_cta_edit": "Modifica", + "managed_vcd_dashboard_edit_name_modal_title": "Modifica il nome", + "managed_vcd_dashboard_edit_name_modal_label": "Cognome", + "managed_vcd_dashboard_edit_name_modal_success": "Il nome è stato modificato correttamente.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Immettere un nome di lunghezza compresa tra 1 e 128 caratteri.", + "managed_vcd_dashboard_edit_description_modal_title": "Modifica la descrizione", + "managed_vcd_dashboard_edit_description_modal_label": "Descrizione", + "managed_vcd_dashboard_edit_description_modal_success": "La descrizione è stata modificata.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Immettere una descrizione di lunghezza compresa tra 1 e 255 caratteri." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pl_PL.json new file mode 100644 index 000000000000..5193dd1361bc --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pl_PL.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "Informacje ogólne", + "managed_vcd_dashboard_datacentres_title": "Centra danych", + "managed_vcd_dashboard_datacentres_label": "datacenter", + "managed_vcd_dashboard_description": "Opis", + "managed_vcd_dashboard_name": "Nazwisko", + "managed_vcd_dashboard_localisation": "Region", + "managed_vcd_dashboard_datacentres_count": "Liczba centrów danych", + "managed_vcd_dashboard_management_interface": "Panel administracyjny", + "managed_vcd_dashboard_management_interface_access": "Dostęp do VCD", + "managed_vcd_dashboard_api_url": "URL API", + "managed_vcd_dashboard_options": "Opcje", + "managed_vcd_dashboard_windows_license": "Licencja Windows", + "managed_vcd_dashboard_windows_license_activate": "Włącz", + "managed_vcd_dashboard_windows_license_active": "Twoja licencja SPLA jest aktywna.", + "managed_vcd_dashboard_windows_license_unactive": "Twoja licencja SPLA nie jest aktywna.", + "managed_vcd_dashboard_service_management": "Zarządzanie usługą", + "managed_vcd_dashboard_mailing_list": "Lista mailingowa", + "managed_vcd_dashboard_service_renew": "Odnowienie", + "managed_vcd_dashboard_service_cancellation": "Rezygnacja z usługi", + "managed_vcd_dashboard_password": "Hasło", + "managed_vcd_dashboard_password_renew": "Odnów hasło administratora", + "managed_vcd_dashboard_password_tooltip": "Jeśli chcesz zmienić hasło administratora, skontaktuj się z pomocą", + "managed_vcd_dashboard_back_link": "Powrót do listy", + "managed_vcd_dashboard_coming_soon": "Dostępne wkrótce", + "managed_vcd_dashboard_data_protection": "Ochrona danych", + "managed_vcd_dashboard_backup_status_error": "Status niedostępny", + "managed_vcd_dashboard_backup_status_subscribed": "Zamówiony", + "managed_vcd_dashboard_backup_status_unsubscribed": "Nie zamówione", + "managed_vcd_dashboard_backup_status_creating": "Trwa aktywacja", + "managed_vcd_dashboard_backup_status_updating": "Trwa zmiana", + "managed_vcd_dashboard_backup_status_disabling": "Trwa wyłączanie", + "managed_vcd_dashboard_backup_link": "Zarządzanie kopiami zapasowymi", + "managed_vcd_dashboard_edit_modal_error": "Wystąpił błąd: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Anuluj", + "managed_vcd_dashboard_edit_modal_cta_edit": "Zmień", + "managed_vcd_dashboard_edit_name_modal_title": "Zmień nazwę", + "managed_vcd_dashboard_edit_name_modal_label": "Nazwisko", + "managed_vcd_dashboard_edit_name_modal_success": "Nazwa została zmieniona.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Wpisz nazwę zawierającą od 1 do 128 znaków.", + "managed_vcd_dashboard_edit_description_modal_title": "Zmień opis", + "managed_vcd_dashboard_edit_description_modal_label": "Opis", + "managed_vcd_dashboard_edit_description_modal_success": "Opis został zmodyfikowany.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Wpisz opis zawierający od 1 do 255 znaków." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pt_PT.json new file mode 100644 index 000000000000..40079f125539 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/dashboard/Messages_pt_PT.json @@ -0,0 +1,45 @@ +{ + "managed_vcd_dashboard_general_information": "Informações gerais", + "managed_vcd_dashboard_datacentres_title": "Datacenters", + "managed_vcd_dashboard_datacentres_label": "datacenters", + "managed_vcd_dashboard_description": "Descrição", + "managed_vcd_dashboard_name": "Nome", + "managed_vcd_dashboard_localisation": "Area", + "managed_vcd_dashboard_datacentres_count": "Número de datacenters", + "managed_vcd_dashboard_management_interface": "Interface de gestão", + "managed_vcd_dashboard_management_interface_access": "Aceder ao VCD", + "managed_vcd_dashboard_api_url": "URL API", + "managed_vcd_dashboard_options": "Opções", + "managed_vcd_dashboard_windows_license": "Licença Windows", + "managed_vcd_dashboard_windows_license_activate": "Ativar", + "managed_vcd_dashboard_windows_license_active": "A sua licença spla está ativada.", + "managed_vcd_dashboard_windows_license_unactive": "A sua licença spla não está ativada.", + "managed_vcd_dashboard_service_management": "Gestão do serviço", + "managed_vcd_dashboard_mailing_list": "Mailing list", + "managed_vcd_dashboard_service_renew": "Renovação", + "managed_vcd_dashboard_service_cancellation": "Cancelar serviço", + "managed_vcd_dashboard_password": "Password", + "managed_vcd_dashboard_password_renew": "Renovar a palavra-passe admin", + "managed_vcd_dashboard_password_tooltip": "Se pretender alterar a sua palavra-passe de administrador, contacte o suporte", + "managed_vcd_dashboard_back_link": "Voltar à lista", + "managed_vcd_dashboard_coming_soon": "Disponível em breve", + "managed_vcd_dashboard_data_protection": "Proteção de dados", + "managed_vcd_dashboard_backup_status_error": "Estado indisponível", + "managed_vcd_dashboard_backup_status_subscribed": "Subscrito", + "managed_vcd_dashboard_backup_status_unsubscribed": "Não subscrito", + "managed_vcd_dashboard_backup_status_creating": "Ativação em curso", + "managed_vcd_dashboard_backup_status_updating": "Modificação em curso", + "managed_vcd_dashboard_backup_status_disabling": "Desativação em curso", + "managed_vcd_dashboard_backup_link": "Gerir os seus backups", + "managed_vcd_dashboard_edit_modal_error": "Ocorreu um erro: {{error}}.", + "managed_vcd_dashboard_edit_modal_cta_cancel": "Anular", + "managed_vcd_dashboard_edit_modal_cta_edit": "Modificar", + "managed_vcd_dashboard_edit_name_modal_title": "Modificar o nome", + "managed_vcd_dashboard_edit_name_modal_label": "Nome", + "managed_vcd_dashboard_edit_name_modal_success": "O nome foi modificado com sucesso.", + "managed_vcd_dashboard_edit_name_modal_helper_error": "Introduza um nome com um comprimento entre 1 e 128 caracteres.", + "managed_vcd_dashboard_edit_description_modal_title": "Modificar a descrição", + "managed_vcd_dashboard_edit_description_modal_label": "Descrição", + "managed_vcd_dashboard_edit_description_modal_success": "A descrição foi modificada com sucesso.", + "managed_vcd_dashboard_edit_description_modal_helper_error": "Introduza uma descrição com um comprimento entre 1 e 255 caracteres." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_de_DE.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_de_DE.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_en_GB.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_en_GB.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_es_ES.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_es_ES.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_CA.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_CA.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_FR.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_fr_FR.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_it_IT.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_it_IT.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pl_PL.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pl_PL.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pt_PT.json new file mode 100644 index 000000000000..91eac4ece1f7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/Messages_pt_PT.json @@ -0,0 +1,3 @@ +{ + "title": "Managed VCD" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_de_DE.json new file mode 100644 index 000000000000..3a1a72bb3a95 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_de_DE.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Virtuelle Rechenzentren", + "managed_vcd_vdc_commercial_range": "Kaufmännische Reihe", + "managed_vcd_vdc_vcpu_count": "vCPU gesamt", + "managed_vcd_vdc_ram_count": "RAM gesamt", + "managed_vcd_vdc_quota_value": "{{quota}} GB", + "managed_vcd_vdc_vcpu_speed": "vCPU Geschwindigkeit", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_en_GB.json new file mode 100644 index 000000000000..1ff887412d99 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_en_GB.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Virtual datacentres", + "managed_vcd_vdc_commercial_range": "Commercial range", + "managed_vcd_vdc_vcpu_count": "Total vCPU", + "managed_vcd_vdc_ram_count": "Total RAM", + "managed_vcd_vdc_quota_value": "{{quota}} GB", + "managed_vcd_vdc_vcpu_speed": "vCPU speed", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_es_ES.json new file mode 100644 index 000000000000..f5af44f2b2b4 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_es_ES.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Datacenters virtuales", + "managed_vcd_vdc_commercial_range": "Gama comercial", + "managed_vcd_vdc_vcpu_count": "Total vCPU", + "managed_vcd_vdc_ram_count": "RAM total", + "managed_vcd_vdc_quota_value": "{{quota}} GB", + "managed_vcd_vdc_vcpu_speed": "Velocidad vCPU", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_CA.json new file mode 100644 index 000000000000..bc878c531532 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_CA.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Datacentres virtuels", + "managed_vcd_vdc_commercial_range": "Gamme commerciale", + "managed_vcd_vdc_vcpu_count": "Total vCPU", + "managed_vcd_vdc_ram_count": "Total RAM", + "managed_vcd_vdc_quota_value": "{{quota}} Go", + "managed_vcd_vdc_vcpu_speed": "Vitesse vCPU", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_FR.json new file mode 100644 index 000000000000..bc878c531532 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_FR.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Datacentres virtuels", + "managed_vcd_vdc_commercial_range": "Gamme commerciale", + "managed_vcd_vdc_vcpu_count": "Total vCPU", + "managed_vcd_vdc_ram_count": "Total RAM", + "managed_vcd_vdc_quota_value": "{{quota}} Go", + "managed_vcd_vdc_vcpu_speed": "Vitesse vCPU", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_it_IT.json new file mode 100644 index 000000000000..cbd07f00eef0 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_it_IT.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Datacenter virtuali", + "managed_vcd_vdc_commercial_range": "Gamma commerciale", + "managed_vcd_vdc_vcpu_count": "Totale vCPU", + "managed_vcd_vdc_ram_count": "RAM totale", + "managed_vcd_vdc_quota_value": "{{quota}} GB", + "managed_vcd_vdc_vcpu_speed": "Velocità vCPU", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pl_PL.json new file mode 100644 index 000000000000..b8709850335d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pl_PL.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Wirtualne centra danych", + "managed_vcd_vdc_commercial_range": "Gama", + "managed_vcd_vdc_vcpu_count": "Całkowite zasoby vCPU", + "managed_vcd_vdc_ram_count": "Całkowita pamięć RAM", + "managed_vcd_vdc_quota_value": "{{quota}} GB", + "managed_vcd_vdc_vcpu_speed": "Prędkość vCPU", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pt_PT.json new file mode 100644 index 000000000000..ee0c89e17ebd --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/Messages_pt_PT.json @@ -0,0 +1,10 @@ +{ + "managed_vcd_vdc_title": "Datacenters virtuais", + "managed_vcd_vdc_commercial_range": "Gama comercial", + "managed_vcd_vdc_vcpu_count": "Total vCPU", + "managed_vcd_vdc_ram_count": "Total RAM", + "managed_vcd_vdc_quota_value": "{{quota}} GB", + "managed_vcd_vdc_vcpu_speed": "Velocidade vCPU", + "managed_vcd_vdc_vcpu_value": "{{speed}} GHz", + "managed_vcd_vdc_id": "ID" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_de_DE.json new file mode 100644 index 000000000000..fdd2acaa3282 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_de_DE.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Virtual Host", + "managed_vcd_vdc_compute_billing": "Abrechnung", + "managed_vcd_vdc_compute_billing_MONTHLY": "Monatlich", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Virtual Host bestellen" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_en_GB.json new file mode 100644 index 000000000000..4607f5fc2694 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_en_GB.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Virtual Host", + "managed_vcd_vdc_compute_billing": "Billing", + "managed_vcd_vdc_compute_billing_MONTHLY": "Monthly", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Order a Virtual Host" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_es_ES.json new file mode 100644 index 000000000000..ffb3c011eeff --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_es_ES.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Virtual Host", + "managed_vcd_vdc_compute_billing": "Facturación", + "managed_vcd_vdc_compute_billing_MONTHLY": "Al mes", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Contratar un Virtual Host" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_CA.json new file mode 100644 index 000000000000..1dd78b3da0d3 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_CA.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Virtual Host", + "managed_vcd_vdc_compute_billing": "Facturation", + "managed_vcd_vdc_compute_billing_MONTHLY": "Au mois", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Commander un Virtual Host" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_FR.json new file mode 100644 index 000000000000..1dd78b3da0d3 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_FR.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Virtual Host", + "managed_vcd_vdc_compute_billing": "Facturation", + "managed_vcd_vdc_compute_billing_MONTHLY": "Au mois", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Commander un Virtual Host" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_it_IT.json new file mode 100644 index 000000000000..4cd55f3ec606 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_it_IT.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Virtual Host", + "managed_vcd_vdc_compute_billing": "Fatturazione", + "managed_vcd_vdc_compute_billing_MONTHLY": "Mensile", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Ordina un Virtual Host" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pl_PL.json new file mode 100644 index 000000000000..c125b42554f3 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pl_PL.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Wirtualny Host", + "managed_vcd_vdc_compute_billing": "System fakturowania", + "managed_vcd_vdc_compute_billing_MONTHLY": "Za miesiąc", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Zamów Virtual Host" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pt_PT.json new file mode 100644 index 000000000000..4d33aa3e972e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_pt_PT.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_compute_vhost_profile": "Virtual Host", + "managed_vcd_vdc_compute_billing": "Facturation", + "managed_vcd_vdc_compute_billing_MONTHLY": "Mensal", + "managed_vcd_vdc_compute_id": "ID", + "managed_vcd_vdc_compute_order_cta": "Encomendar um Host Virtual" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_de_DE.json new file mode 100644 index 000000000000..0919d20b28a7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_de_DE.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Speicherkapazität bestellen", + "managed_vcd_vdc_order_compute_subtitle": "Sie können Ihr Virtual Datacenter anpassen, indem Sie Virtual Hosts hinzufügen. Anschließend werden Sie zu einem neuen Tab weitergeleitet, um Ihre Bestellung abzuschließen. Wählen Sie einen Virtual Host-Typ aus.", + "managed_vcd_vdc_order_storage_subtitle": "Sie können Ihr Virtual Datacenter anpassen, indem Sie Speicherkapazität hinzufügen. Anschließend werden Sie zu einem neuen Tab weitergeleitet, um Ihre Bestellung abzuschließen. Wählen Sie Ihre Speicherkapazität.", + "managed_vcd_vdc_order_unavailable": "Bitte kontaktieren Sie den OVHcloud Support", + "managed_vcd_vdc_order_vhost": "Virtual Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}} GB", + "managed_vcd_vdc_order_vcpu_count": "Anzahl der vCPU", + "managed_vcd_vdc_order_type": "Typ", + "managed_vcd_vdc_order_price": "Preis", + "managed_vcd_vdc_order_price_detail": "Preis für 1 Monat", + "managed_vcd_vdc_order_quantity_title": "Menge auswählen", + "managed_vcd_vdc_order_quantity_label": "Menge", + "managed_vcd_vdc_order_cancel_cta": "Abbrechen", + "managed_vcd_vdc_order_confirm_cta": "Bestellen" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_en_GB.json new file mode 100644 index 000000000000..d36b180221b5 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_en_GB.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Order storage capacity", + "managed_vcd_vdc_order_compute_subtitle": "You can customize your Virtual Datacentre by adding Virtual Hosts. You will then be redirected to a new tab to finalize your order. Select a type of Virtual Host.", + "managed_vcd_vdc_order_storage_subtitle": "You can customize your Virtual Datacentre by adding storage capacity. You will then be redirected to a new tab to finalize your order. Select your storage capacity.", + "managed_vcd_vdc_order_unavailable": "Please contact OVHcloud support", + "managed_vcd_vdc_order_vhost": "Virtual Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}}GB", + "managed_vcd_vdc_order_vcpu_count": "Number of vCPU", + "managed_vcd_vdc_order_type": "Type", + "managed_vcd_vdc_order_price": "Price", + "managed_vcd_vdc_order_price_detail": "Price for 1 month", + "managed_vcd_vdc_order_quantity_title": "Choose a quantity", + "managed_vcd_vdc_order_quantity_label": "Quantity", + "managed_vcd_vdc_order_cancel_cta": "Cancel", + "managed_vcd_vdc_order_confirm_cta": "Order now" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_es_ES.json new file mode 100644 index 000000000000..0b3b6d96f269 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_es_ES.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Contratar capacidad de almacenamiento", + "managed_vcd_vdc_order_compute_subtitle": "Puede personalizar su Virtual Datacenter añadiendo hosts virtuales. A continuación, el sistema le redirigirá a una nueva pestaña para finalizar el pedido. Seleccione un tipo de host virtual.", + "managed_vcd_vdc_order_storage_subtitle": "Puede personalizar su centro de datos virtual añadiendo capacidad de almacenamiento. A continuación, el sistema le redirigirá a una nueva pestaña para finalizar el pedido. Seleccione su capacidad de almacenamiento.", + "managed_vcd_vdc_order_unavailable": "Contacte con el soporte de OVHcloud", + "managed_vcd_vdc_order_vhost": "Virtual Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}} GB", + "managed_vcd_vdc_order_vcpu_count": "Número de vCPU", + "managed_vcd_vdc_order_type": "Tipo", + "managed_vcd_vdc_order_price": "Precio", + "managed_vcd_vdc_order_price_detail": "Precio por 1 mes", + "managed_vcd_vdc_order_quantity_title": "Elegir una cantidad", + "managed_vcd_vdc_order_quantity_label": "Cantidad", + "managed_vcd_vdc_order_cancel_cta": "Cancelar", + "managed_vcd_vdc_order_confirm_cta": "Contratar" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_CA.json new file mode 100644 index 000000000000..ca03439fd8a8 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_CA.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Commander de la capacité de stockage", + "managed_vcd_vdc_order_compute_subtitle": "Vous pouvez personnaliser votre Virtual Datacenter en ajoutant des Virtual Hosts. Vous serez ensuite redirigé vers un nouvel onglet pour finaliser votre commande. Sélectionner un type de Virtual Host.", + "managed_vcd_vdc_order_storage_subtitle": "Vous pouvez personnaliser votre Virtual Datacenter en ajoutant de la capacité de stockage. Vous serez ensuite redirigé vers un nouvel onglet pour finaliser votre commande. Sélectionner votre capacité de stockage.", + "managed_vcd_vdc_order_unavailable": "Veuillez contacter le support OVHcloud", + "managed_vcd_vdc_order_vhost": "Virtual Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}} GB", + "managed_vcd_vdc_order_vcpu_count": "Nombre de vCPU", + "managed_vcd_vdc_order_type": "Type", + "managed_vcd_vdc_order_price": "Prix", + "managed_vcd_vdc_order_price_detail": "Prix pour 1 mois", + "managed_vcd_vdc_order_quantity_title": "Choisir une quantité", + "managed_vcd_vdc_order_quantity_label": "Quantité", + "managed_vcd_vdc_order_cancel_cta": "Annuler", + "managed_vcd_vdc_order_confirm_cta": "Commander" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_FR.json new file mode 100644 index 000000000000..ca03439fd8a8 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_FR.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Commander de la capacité de stockage", + "managed_vcd_vdc_order_compute_subtitle": "Vous pouvez personnaliser votre Virtual Datacenter en ajoutant des Virtual Hosts. Vous serez ensuite redirigé vers un nouvel onglet pour finaliser votre commande. Sélectionner un type de Virtual Host.", + "managed_vcd_vdc_order_storage_subtitle": "Vous pouvez personnaliser votre Virtual Datacenter en ajoutant de la capacité de stockage. Vous serez ensuite redirigé vers un nouvel onglet pour finaliser votre commande. Sélectionner votre capacité de stockage.", + "managed_vcd_vdc_order_unavailable": "Veuillez contacter le support OVHcloud", + "managed_vcd_vdc_order_vhost": "Virtual Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}} GB", + "managed_vcd_vdc_order_vcpu_count": "Nombre de vCPU", + "managed_vcd_vdc_order_type": "Type", + "managed_vcd_vdc_order_price": "Prix", + "managed_vcd_vdc_order_price_detail": "Prix pour 1 mois", + "managed_vcd_vdc_order_quantity_title": "Choisir une quantité", + "managed_vcd_vdc_order_quantity_label": "Quantité", + "managed_vcd_vdc_order_cancel_cta": "Annuler", + "managed_vcd_vdc_order_confirm_cta": "Commander" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_it_IT.json new file mode 100644 index 000000000000..2a48b14a5990 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_it_IT.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Ordina capacità di storage", + "managed_vcd_vdc_order_compute_subtitle": "Per personalizzare il proprio Virtual Datacenter è possibile aggiungere Host Virtuali. Verrai reindirizzato a una nuova pagina per completare l’ordine. Seleziona un tipo di Virtual Host.", + "managed_vcd_vdc_order_storage_subtitle": "È possibile personalizzare il proprio Datacenter virtuale aggiungendo capacità di storage. Verrai reindirizzato a una nuova pagina per completare l’ordine. Seleziona la capacità di storage.", + "managed_vcd_vdc_order_unavailable": "Contatta il supporto OVHcloud", + "managed_vcd_vdc_order_vhost": "Virtual Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}} GB", + "managed_vcd_vdc_order_vcpu_count": "Numero di vCPU", + "managed_vcd_vdc_order_type": "Tipo", + "managed_vcd_vdc_order_price": "Prezzo", + "managed_vcd_vdc_order_price_detail": "Prezzo per 1 mese", + "managed_vcd_vdc_order_quantity_title": "Scegli la quantità", + "managed_vcd_vdc_order_quantity_label": "Quantità", + "managed_vcd_vdc_order_cancel_cta": "Annulla", + "managed_vcd_vdc_order_confirm_cta": "Ordina" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pl_PL.json new file mode 100644 index 000000000000..264db0526378 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pl_PL.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Zamów przestrzeń dyskową", + "managed_vcd_vdc_order_compute_subtitle": "Możesz spersonalizować swoje Virtual Datacenter, dodając Virtual Hosts. Zostaniesz przekierowany/-a do nowej zakładki, aby sfinalizować zamówienie. Wybierz rodzaj Virtual Host.", + "managed_vcd_vdc_order_storage_subtitle": "Możesz dostosować wirtualne centrum danych, dodając przestrzeń dyskową. Zostaniesz przekierowany/-a do nowej zakładki, aby sfinalizować zamówienie. Wybierz rozmiar przestrzeni dyskowej.", + "managed_vcd_vdc_order_unavailable": "Skontaktuj się z pomocą OVHcloud", + "managed_vcd_vdc_order_vhost": "Wirtualny Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}} GB", + "managed_vcd_vdc_order_vcpu_count": "Liczba vCPU", + "managed_vcd_vdc_order_type": "Rodzaj", + "managed_vcd_vdc_order_price": "Cena", + "managed_vcd_vdc_order_price_detail": "Cena za 1 miesiąc", + "managed_vcd_vdc_order_quantity_title": "Wybierz ilość", + "managed_vcd_vdc_order_quantity_label": "Ilość", + "managed_vcd_vdc_order_cancel_cta": "Anuluj", + "managed_vcd_vdc_order_confirm_cta": "Zamów" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pt_PT.json new file mode 100644 index 000000000000..e986c6c99b4f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_pt_PT.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_vdc_order_storage_title": "Encomendar capacidade de armazenamento", + "managed_vcd_vdc_order_compute_subtitle": "Pode personalizar o seu Virtual Datacenter adicionando Hosts virtuais. De seguida, será redirecionado para um novo separador para finalizar a sua encomenda. Selecione um tipo de Host Virtual.", + "managed_vcd_vdc_order_storage_subtitle": "Pode personalizar o seu Virtual Datacenter adicionando capacidade de armazenamento. De seguida, será redirecionado para um novo separador para finalizar a sua encomenda. Selecione a sua capacidade de armazenamento.", + "managed_vcd_vdc_order_unavailable": "Contacte o suporte OVHcloud", + "managed_vcd_vdc_order_vhost": "Virtual Host", + "managed_vcd_vdc_order_cpu_speed": "CPU (GHz)", + "managed_vcd_vdc_order_ram": "RAM", + "managed_vcd_vdc_order_ram_value": "{{ram}} GB", + "managed_vcd_vdc_order_vcpu_count": "Número de vCPU", + "managed_vcd_vdc_order_type": "Tipo", + "managed_vcd_vdc_order_price": "Preço", + "managed_vcd_vdc_order_price_detail": "Preço por 1 mês", + "managed_vcd_vdc_order_quantity_title": "Escolher uma quantidade", + "managed_vcd_vdc_order_quantity_label": "Quantidade", + "managed_vcd_vdc_order_cancel_cta": "Anular", + "managed_vcd_vdc_order_confirm_cta": "Encomendar" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_de_DE.json new file mode 100644 index 000000000000..ce9348fc89fc --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_de_DE.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Name", + "managed_vcd_vdc_storage_profile": "Profil", + "managed_vcd_vdc_storage_type": "Typ", + "managed_vcd_vdc_storage_capacity": "Grösse", + "managed_vcd_vdc_storage_order_cta": "Storage bestellen" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_en_GB.json new file mode 100644 index 000000000000..fac38c489ef8 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_en_GB.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Name", + "managed_vcd_vdc_storage_profile": "Profile", + "managed_vcd_vdc_storage_type": "Type", + "managed_vcd_vdc_storage_capacity": "Size", + "managed_vcd_vdc_storage_order_cta": "Order a storage" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_es_ES.json new file mode 100644 index 000000000000..327dec785d4f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_es_ES.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Nombre", + "managed_vcd_vdc_storage_profile": "Perfil", + "managed_vcd_vdc_storage_type": "Tipo", + "managed_vcd_vdc_storage_capacity": "Tamaño", + "managed_vcd_vdc_storage_order_cta": "Contratar un Storage" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_CA.json new file mode 100644 index 000000000000..6c3230c94919 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_CA.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Nom", + "managed_vcd_vdc_storage_profile": "Profil", + "managed_vcd_vdc_storage_type": "Type", + "managed_vcd_vdc_storage_capacity": "Taille", + "managed_vcd_vdc_storage_order_cta": "Commander un Storage" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_FR.json new file mode 100644 index 000000000000..6c3230c94919 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_FR.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Nom", + "managed_vcd_vdc_storage_profile": "Profil", + "managed_vcd_vdc_storage_type": "Type", + "managed_vcd_vdc_storage_capacity": "Taille", + "managed_vcd_vdc_storage_order_cta": "Commander un Storage" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_it_IT.json new file mode 100644 index 000000000000..19eeab645217 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_it_IT.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Cognome", + "managed_vcd_vdc_storage_profile": "Profilo", + "managed_vcd_vdc_storage_type": "Tipo", + "managed_vcd_vdc_storage_capacity": "Dimensione", + "managed_vcd_vdc_storage_order_cta": "Ordina uno Storage" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pl_PL.json new file mode 100644 index 000000000000..0be5d936edd1 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pl_PL.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Nazwisko", + "managed_vcd_vdc_storage_profile": "Profil", + "managed_vcd_vdc_storage_type": "Rodzaj", + "managed_vcd_vdc_storage_capacity": "Rozmiar", + "managed_vcd_vdc_storage_order_cta": "Zamów Storage" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pt_PT.json new file mode 100644 index 000000000000..3466e156f1f0 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_pt_PT.json @@ -0,0 +1,7 @@ +{ + "managed_vcd_vdc_storage_name": "Nome", + "managed_vcd_vdc_storage_profile": "Perfil", + "managed_vcd_vdc_storage_type": "Tipo", + "managed_vcd_vdc_storage_capacity": "Tamanho", + "managed_vcd_vdc_storage_order_cta": "Encomendar um Storage" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_de_DE.json new file mode 100644 index 000000000000..bf0fba32976b --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_de_DE.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "Oops...!", + "manager_error_page_button_cancel": "Abbrechen", + "manager_error_page_detail_code": "Fehlercode: ", + "manager_error_page_action_reload_label": "Erneut versuchen", + "manager_error_page_action_home_label": "Zurück zur Startseite", + "manager_error_page_default": "Beim Laden der Seite ist ein Fehler aufgetreten." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_en_GB.json new file mode 100644 index 000000000000..b17691e2bc6d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_en_GB.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "Oops!", + "manager_error_page_button_cancel": "Cancel", + "manager_error_page_detail_code": "Error code: ", + "manager_error_page_action_reload_label": "Try again", + "manager_error_page_action_home_label": "Back to homepage", + "manager_error_page_default": "An error has occurred loading the page." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_es_ES.json new file mode 100644 index 000000000000..02cb3fbb1a80 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_es_ES.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "¡Vaya!", + "manager_error_page_button_cancel": "Cancelar", + "manager_error_page_detail_code": "Código de error: ", + "manager_error_page_action_reload_label": "Volver a intentarlo", + "manager_error_page_action_home_label": "Volver a la página de inicio", + "manager_error_page_default": "Se ha producido un error al cargar la página" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_CA.json new file mode 100644 index 000000000000..2c575c63588e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_CA.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "Oops …!", + "manager_error_page_button_cancel": "Annuler", + "manager_error_page_detail_code": "Code d'erreur : ", + "manager_error_page_action_reload_label": "Réessayer", + "manager_error_page_action_home_label": "Retour à la page d'accueil", + "manager_error_page_default": "Une erreur est survenue lors du chargement de la page." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_FR.json new file mode 100644 index 000000000000..2c575c63588e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_fr_FR.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "Oops …!", + "manager_error_page_button_cancel": "Annuler", + "manager_error_page_detail_code": "Code d'erreur : ", + "manager_error_page_action_reload_label": "Réessayer", + "manager_error_page_action_home_label": "Retour à la page d'accueil", + "manager_error_page_default": "Une erreur est survenue lors du chargement de la page." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_it_IT.json new file mode 100644 index 000000000000..ce0517c42dde --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_it_IT.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "Ops!", + "manager_error_page_button_cancel": "Annulla", + "manager_error_page_detail_code": "Codice di errore: ", + "manager_error_page_action_reload_label": "Riprova", + "manager_error_page_action_home_label": "Torna alla home page", + "manager_error_page_default": "Si è verificato un errore durante il caricamento della pagina." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pl_PL.json new file mode 100644 index 000000000000..6fc5dc1b135d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pl_PL.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "Ups ...!", + "manager_error_page_button_cancel": "Anuluj", + "manager_error_page_detail_code": "Kod błędu: ", + "manager_error_page_action_reload_label": "Spróbuj ponownie", + "manager_error_page_action_home_label": "Powrót do strony głównej", + "manager_error_page_default": "Wystąpił błąd podczas ładowania strony." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pt_PT.json new file mode 100644 index 000000000000..1edd72c0f09a --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/hpc-vmware-managed-vcd/error/Messages_pt_PT.json @@ -0,0 +1,8 @@ +{ + "manager_error_page_title": "Oops!", + "manager_error_page_button_cancel": "Anular", + "manager_error_page_detail_code": "Código de erro: ", + "manager_error_page_action_reload_label": "Tentar novamente", + "manager_error_page_action_home_label": "Voltar à página inicial", + "manager_error_page_default": "Ocorreu um erro aquando do carregamento da página." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_de_DE.json new file mode 100644 index 000000000000..4cbaf8105f34 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_de_DE.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "ID", + "managed_vcd_listing_name": "Name", + "managed_vcd_listing_location": "Region", + "managed_vcd_listing_description": "Beschreibung", + "managed_vcd_listing_web_interface_url": "Webinterface-URL" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_en_GB.json new file mode 100644 index 000000000000..d51162917cbc --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_en_GB.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "Id", + "managed_vcd_listing_name": "Name", + "managed_vcd_listing_location": "Region", + "managed_vcd_listing_description": "Description", + "managed_vcd_listing_web_interface_url": "Web interface URL" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_es_ES.json new file mode 100644 index 000000000000..b388e088641b --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_es_ES.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "Id", + "managed_vcd_listing_name": "Nombre", + "managed_vcd_listing_location": "Zona", + "managed_vcd_listing_description": "Descripción", + "managed_vcd_listing_web_interface_url": "URL interfaz web" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_CA.json new file mode 100644 index 000000000000..bf824fae2268 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_CA.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "Id", + "managed_vcd_listing_name": "Nom", + "managed_vcd_listing_location": "Région", + "managed_vcd_listing_description": "Description", + "managed_vcd_listing_web_interface_url": "URL interface web" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_FR.json new file mode 100644 index 000000000000..bf824fae2268 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_fr_FR.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "Id", + "managed_vcd_listing_name": "Nom", + "managed_vcd_listing_location": "Région", + "managed_vcd_listing_description": "Description", + "managed_vcd_listing_web_interface_url": "URL interface web" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_it_IT.json new file mode 100644 index 000000000000..c9baa3c52243 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_it_IT.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "Id", + "managed_vcd_listing_name": "Cognome", + "managed_vcd_listing_location": "Regione", + "managed_vcd_listing_description": "Descrizione", + "managed_vcd_listing_web_interface_url": "URL interfaccia web" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pl_PL.json new file mode 100644 index 000000000000..16b5fbcfc6f2 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pl_PL.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "Id", + "managed_vcd_listing_name": "Nazwisko", + "managed_vcd_listing_location": "Region", + "managed_vcd_listing_description": "Opis", + "managed_vcd_listing_web_interface_url": "URL interfejsu www" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pt_PT.json new file mode 100644 index 000000000000..9f5422e69977 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/listing/Messages_pt_PT.json @@ -0,0 +1,8 @@ +{ + "managed_vcd_listing_title": "Managed VCD", + "managed_vcd_listing_id": "Id", + "managed_vcd_listing_name": "Nome", + "managed_vcd_listing_location": "Area", + "managed_vcd_listing_description": "Descrição", + "managed_vcd_listing_web_interface_url": "URL interface web" +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_de_DE.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_de_DE.json new file mode 100644 index 000000000000..9a4158a2e7aa --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_de_DE.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "Managed VCD ist eine vollständig von OVHcloud betriebene Virtualisierungslösung, mit der Sie Ihre Anwendungen, VMs und Container ausführen können, ohne sich um die zugrunde liegenden Infrastrukturen kümmern zu müssen.", + "managed_vcd_onboarding_description_part2": "Sie verfügen über ein einfaches und einheitliches Interface für die flexible Verwaltung Ihrer Ressourcen-Pools in virtuellen Rechenzentren sowie über eine gemanagte Veeam Backup-Lösung.", + "managed_vcd_onboarding_order": "Bestellen", + "managed_vcd_onboarding_more_info": "Mehr erfahren", + "managed_vcd_onboarding_guide1_link": "Mehr erfahren", + "managed_vcd_onboarding_guide1_category": "Einführung", + "managed_vcd_onboarding_guide1_title": "Alles über Managed VCD", + "managed_vcd_onboarding_guide1_description": "Entdecken Sie das Managed VCD Produkt, seine Vorteile, seine Verwendung und seine Preise.", + "managed_vcd_onboarding_guide2_category": "Anleitung und Dokumentation", + "managed_vcd_onboarding_guide2_title": "Erste Schritte mit Managed VCD", + "managed_vcd_onboarding_guide2_link": "Die Dokumentation anzeigen", + "managed_vcd_onboarding_guide2_description": "Die Grundprinzipien von VCD. Entdecken Sie die Grundlagen der VCD.", + "managed_vcd_onboarding_guide3_category": "FAQ", + "managed_vcd_onboarding_guide3_title": "Häufig gestellte Fragen", + "managed_vcd_onboarding_guide3_link": "FAQ durchsuchen", + "managed_vcd_onboarding_guide3_description": "In den FAQ finden Sie Antworten auf häufig gestellte Fragen." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_en_GB.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_en_GB.json new file mode 100644 index 000000000000..719131659470 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_en_GB.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "Managed VCD is a virtualization solution fully operated by OVHcloud to run your applications, VMs and containers without having to worry about the underlying infrastructure.", + "managed_vcd_onboarding_description_part2": "You get a simple, unified interface to flexibly manage your resource pools within virtual datacentres, as well as a managed Veeam backup solution.", + "managed_vcd_onboarding_order": "Order now", + "managed_vcd_onboarding_more_info": "Find out more", + "managed_vcd_onboarding_guide1_link": "Find out more", + "managed_vcd_onboarding_guide1_category": "Introduction", + "managed_vcd_onboarding_guide1_title": "Discover Managed VCD", + "managed_vcd_onboarding_guide1_description": "Discover the Managed VCD product, its benefits, usage and pricing.", + "managed_vcd_onboarding_guide2_category": "Tutorial and Documentation", + "managed_vcd_onboarding_guide2_title": "Getting started with Managed VCD", + "managed_vcd_onboarding_guide2_link": "See the documentation", + "managed_vcd_onboarding_guide2_description": "The fundamentals of VCD. Discover the basic concepts of VCD.", + "managed_vcd_onboarding_guide3_category": "FAQs", + "managed_vcd_onboarding_guide3_title": "Frequently asked questions", + "managed_vcd_onboarding_guide3_link": "Browse FAQ", + "managed_vcd_onboarding_guide3_description": "Browse the FAQs for answers to common questions." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_es_ES.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_es_ES.json new file mode 100644 index 000000000000..bce8b08b7880 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_es_ES.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "Managed VCD es una solución de virtualización totalmente operada por OVHcloud para ejecutar sus aplicaciones, sus MV y sus contenedores sin tener que preocuparse por las infraestructuras subyacentes.", + "managed_vcd_onboarding_description_part2": "Dispone de una interfaz sencilla y unificada para gestionar sus pools de recursos de forma flexible en los datacenters virtuales, así como de una solución de backup Veeam administrada.", + "managed_vcd_onboarding_order": "Contratar", + "managed_vcd_onboarding_more_info": "Más información", + "managed_vcd_onboarding_guide1_link": "Más información", + "managed_vcd_onboarding_guide1_category": "Presentación", + "managed_vcd_onboarding_guide1_title": "Descubrir Managed VCD", + "managed_vcd_onboarding_guide1_description": "Descubra el producto Managed VCD, sus ventajas, su uso y su tarificación.", + "managed_vcd_onboarding_guide2_category": "Tutorial y documentación", + "managed_vcd_onboarding_guide2_title": "Primeros pasos para utilizar Managed VCD", + "managed_vcd_onboarding_guide2_link": "Ver la documentación", + "managed_vcd_onboarding_guide2_description": "Los principios fundamentales de VCD. Descubra los conceptos básicos del VCD.", + "managed_vcd_onboarding_guide3_category": "FAQ", + "managed_vcd_onboarding_guide3_title": "Preguntas frecuentes", + "managed_vcd_onboarding_guide3_link": "Examinar las FAQ", + "managed_vcd_onboarding_guide3_description": "Consulte las FAQ para obtener respuestas a las preguntas más frecuentes." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_CA.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_CA.json new file mode 100644 index 000000000000..f3b950fad43e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_CA.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "Managed VCD est une solution de virtualisation entièrement opérée par OVHcloud pour exécuter vos applications, vos VM et vos conteneurs sans avoir à vous soucier des infrastructures sous-jacentes.", + "managed_vcd_onboarding_description_part2": "Vous disposez d'une interface simple et unifiée pour gérer vos pools de ressources de façon flexible au sein des datacenters virtuels, ainsi qu'une solution de sauvegarde Veeam managé.", + "managed_vcd_onboarding_order": "Commander", + "managed_vcd_onboarding_more_info": "En savoir plus", + "managed_vcd_onboarding_guide1_link": "En savoir plus", + "managed_vcd_onboarding_guide1_category": "Présentation", + "managed_vcd_onboarding_guide1_title": "Découvrir Managed VCD", + "managed_vcd_onboarding_guide1_description": "Découvrez le produit Managed VCD, ses avantages, son utilisation et sa tarification.", + "managed_vcd_onboarding_guide2_category": "Tutoriel et Documentation", + "managed_vcd_onboarding_guide2_title": "Premiers pas pour utiliser Managed VCD", + "managed_vcd_onboarding_guide2_link": "Voir la documentation", + "managed_vcd_onboarding_guide2_description": "Les principes fondamentaux de VCD. Découvrez les concepts de base du VCD.", + "managed_vcd_onboarding_guide3_category": "FAQ", + "managed_vcd_onboarding_guide3_title": "Questions fréquentes", + "managed_vcd_onboarding_guide3_link": "Parcourir les FAQ", + "managed_vcd_onboarding_guide3_description": "Parcourez les FAQ pour trouver des réponses aux questions les plus fréquentes." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_FR.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_FR.json new file mode 100644 index 000000000000..f3b950fad43e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_fr_FR.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "Managed VCD est une solution de virtualisation entièrement opérée par OVHcloud pour exécuter vos applications, vos VM et vos conteneurs sans avoir à vous soucier des infrastructures sous-jacentes.", + "managed_vcd_onboarding_description_part2": "Vous disposez d'une interface simple et unifiée pour gérer vos pools de ressources de façon flexible au sein des datacenters virtuels, ainsi qu'une solution de sauvegarde Veeam managé.", + "managed_vcd_onboarding_order": "Commander", + "managed_vcd_onboarding_more_info": "En savoir plus", + "managed_vcd_onboarding_guide1_link": "En savoir plus", + "managed_vcd_onboarding_guide1_category": "Présentation", + "managed_vcd_onboarding_guide1_title": "Découvrir Managed VCD", + "managed_vcd_onboarding_guide1_description": "Découvrez le produit Managed VCD, ses avantages, son utilisation et sa tarification.", + "managed_vcd_onboarding_guide2_category": "Tutoriel et Documentation", + "managed_vcd_onboarding_guide2_title": "Premiers pas pour utiliser Managed VCD", + "managed_vcd_onboarding_guide2_link": "Voir la documentation", + "managed_vcd_onboarding_guide2_description": "Les principes fondamentaux de VCD. Découvrez les concepts de base du VCD.", + "managed_vcd_onboarding_guide3_category": "FAQ", + "managed_vcd_onboarding_guide3_title": "Questions fréquentes", + "managed_vcd_onboarding_guide3_link": "Parcourir les FAQ", + "managed_vcd_onboarding_guide3_description": "Parcourez les FAQ pour trouver des réponses aux questions les plus fréquentes." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_it_IT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_it_IT.json new file mode 100644 index 000000000000..fe2391573ca9 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_it_IT.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "Managed VCD è una soluzione di virtualizzazione totalmente gestita da OVHcloud per eseguire applicazioni, VM e container senza doversi preoccupare delle infrastrutture sottostanti.", + "managed_vcd_onboarding_description_part2": "Disporrete di un'interfaccia semplice e unificata per gestire i vostri pool di risorse in modo flessibile all'interno dei datacenter virtuali, oltre che di una soluzione di backup Veeam gestita.", + "managed_vcd_onboarding_order": "Ordina", + "managed_vcd_onboarding_more_info": "Scopri di più", + "managed_vcd_onboarding_guide1_link": "Scopri di più", + "managed_vcd_onboarding_guide1_category": "Presentazione", + "managed_vcd_onboarding_guide1_title": "Scopri Managed VCD", + "managed_vcd_onboarding_guide1_description": "Scopri il prodotto Managed VCD, i suoi vantaggi, il suo utilizzo e la sua tariffazione.", + "managed_vcd_onboarding_guide2_category": "Tutorial e documentazione", + "managed_vcd_onboarding_guide2_title": "Iniziare a utilizzare Managed VCD", + "managed_vcd_onboarding_guide2_link": "Consulta la documentazione", + "managed_vcd_onboarding_guide2_description": "I principi fondamentali di VCD. Scopri i concetti di base del VCD.", + "managed_vcd_onboarding_guide3_category": "FAQ", + "managed_vcd_onboarding_guide3_title": "FAQ", + "managed_vcd_onboarding_guide3_link": "Sfoglia le FAQ", + "managed_vcd_onboarding_guide3_description": "Consulta le FAQ per trovare le risposte alle domande più frequenti." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pl_PL.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pl_PL.json new file mode 100644 index 000000000000..b5fe284917e8 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pl_PL.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "Managed VCD to rozwiązanie do wirtualizacji, które jest w pełni obsługiwane przez OVHcloud i służy do uruchamiania aplikacji, wirtualnych maszyn oraz kontenerów bez konieczności martwienia się o infrastruktury.", + "managed_vcd_onboarding_description_part2": "Możesz w prosty i ujednolicony sposób zarządzać pulami zasobów w sposób elastyczny w wirtualnych centrach danych oraz korzystać z zarządzanego rozwiązania do tworzenia kopii zapasowych Veeam.", + "managed_vcd_onboarding_order": "Zamów", + "managed_vcd_onboarding_more_info": "Dowiedz się więcej", + "managed_vcd_onboarding_guide1_link": "Dowiedz się więcej", + "managed_vcd_onboarding_guide1_category": "Wprowadzenie", + "managed_vcd_onboarding_guide1_title": "Poznaj Managed VCD", + "managed_vcd_onboarding_guide1_description": "Sprawdź usługę Managed VCD i poznaj jej zalety, sposób użycia i ceny.", + "managed_vcd_onboarding_guide2_category": "Tutoriale i dokumentacja", + "managed_vcd_onboarding_guide2_title": "Pierwsze kroki z Managed VCD", + "managed_vcd_onboarding_guide2_link": "Wyświetl dokumentację", + "managed_vcd_onboarding_guide2_description": "Podstawowe zasady VCD. Zapoznaj się z podstawowymi koncepcjami VCD.", + "managed_vcd_onboarding_guide3_category": "FAQ", + "managed_vcd_onboarding_guide3_title": "Najczęstsze pytania", + "managed_vcd_onboarding_guide3_link": "Przejrzyj FAQ", + "managed_vcd_onboarding_guide3_description": "Przejrzyj FAQ, aby znaleźć odpowiedzi na najczęściej zadawane pytania." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pt_PT.json b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pt_PT.json new file mode 100644 index 000000000000..893a2c84e952 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/public/translations/onboarding/Messages_pt_PT.json @@ -0,0 +1,18 @@ +{ + "managed_vcd_onboarding_description_part1": "O Managed VCD é uma solução de virtualização inteiramente operada pela OVHcloud para executar aplicações, VMs e containers sem ter de se preocupar com as infraestruturas subjacentes.", + "managed_vcd_onboarding_description_part2": "Dispõe de uma interface simples e unificada para gerir as suas pools de recursos de forma flexível no seio dos datacenters virtuais, assim como uma solução de backup Veeam administrado.", + "managed_vcd_onboarding_order": "Encomendar", + "managed_vcd_onboarding_more_info": "Saber mais", + "managed_vcd_onboarding_guide1_link": "Saber mais", + "managed_vcd_onboarding_guide1_category": "Introdução", + "managed_vcd_onboarding_guide1_title": "Descobrir o Managed VCD", + "managed_vcd_onboarding_guide1_description": "Descubra o produto Managed VCD, as suas vantagens, a sua utilização e os seus preços.", + "managed_vcd_onboarding_guide2_category": "Tutorial e Documentação", + "managed_vcd_onboarding_guide2_title": "Primeiros passos para utilizar o Managed VCD", + "managed_vcd_onboarding_guide2_link": "Ver a documentação", + "managed_vcd_onboarding_guide2_description": "Princípios básicos do VCD. Descubra os conceitos de base do VCD.", + "managed_vcd_onboarding_guide3_category": "FAQ", + "managed_vcd_onboarding_guide3_title": "Questões frequentes", + "managed_vcd_onboarding_guide3_link": "Consultar as FAQ", + "managed_vcd_onboarding_guide3_description": "Consulte as FAQs para encontrar respostas às perguntas mais frequentes." +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/setupTests.ts b/packages/manager/apps/hpc-vmware-managed-vcd/setupTests.ts new file mode 100644 index 000000000000..35008dfde001 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/setupTests.ts @@ -0,0 +1,35 @@ +import { beforeAll, afterAll } from 'vitest'; +import { odsSetup } from '@ovhcloud/ods-common-core'; +import { setupServer } from 'msw/node'; +import { toMswHandlers } from '../../../../playwright-helpers'; +import { getAuthenticationMocks } from '../../../../playwright-helpers/mocks/auth'; +import '@testing-library/jest-dom'; +// PATCH for ODS Component to fix Error: Uncaught [TypeError: _this.attachInternals is not a function] +import 'element-internals-polyfill'; + +odsSetup(); + +const server = setupServer( + ...toMswHandlers([ + ...getAuthenticationMocks({ isAuthMocked: true, region: 'EU' }), + ]), +); + +beforeAll(() => { + server.listen({ onUnhandledRequest: 'warn' }); + + delete global.server; + global.__VERSION__ = null; + global.server = server; +}); + +afterAll(() => { + server.close(); + + delete global.__VERSION__; + delete global.server; +}); + +afterEach(() => { + server.resetHandlers(); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/App.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/App.tsx new file mode 100644 index 000000000000..2c333cefe6d7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/App.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { odsSetup } from '@ovhcloud/ods-common-core'; +import { RouterProvider, createHashRouter } from 'react-router-dom'; +import { Routes } from './routes/routes'; + +odsSetup(); + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 300_000, + }, + }, +}); + +function App() { + const router = createHashRouter(Routes); + + return ( + + + + + ); +} + +export default App; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/assets/VmwareBroadcomxOVHcloud.svg b/packages/manager/apps/hpc-vmware-managed-vcd/src/assets/VmwareBroadcomxOVHcloud.svg new file mode 100644 index 000000000000..97cae8f113b5 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/assets/VmwareBroadcomxOVHcloud.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/assets/error-banner-oops.png b/packages/manager/apps/hpc-vmware-managed-vcd/src/assets/error-banner-oops.png new file mode 100644 index 0000000000000000000000000000000000000000..413028afad19a473424e11656d3c6b0400a79fdf GIT binary patch literal 60234 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 literal 0 HcmV?d00001 diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/breadcrumb/Breadcrumb.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/breadcrumb/Breadcrumb.component.tsx new file mode 100644 index 000000000000..19bc2cd85464 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/breadcrumb/Breadcrumb.component.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { OsdsBreadcrumb } from '@ovhcloud/ods-components/react'; +import { + useBreadcrumb, + BreadcrumbItem, +} from '@/hooks/breadcrumb/useBreadcrumb'; +import appConfig from '@/hpc-vmware-managed-vcd.config'; + +export interface BreadcrumbProps { + customRootLabel?: string; + appName?: string; + items?: BreadcrumbItem[]; +} + +function Breadcrumb({ customRootLabel, items }: BreadcrumbProps): JSX.Element { + const label = customRootLabel || appConfig.rootLabel; + + const breadcrumbItems = useBreadcrumb({ + rootLabel: label, + items, + }); + return ; +} + +export default Breadcrumb; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/dashboard/layout/VcdDashboardLayout.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/dashboard/layout/VcdDashboardLayout.component.tsx new file mode 100644 index 000000000000..6aabda0848d0 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/dashboard/layout/VcdDashboardLayout.component.tsx @@ -0,0 +1,84 @@ +import React, { useEffect, useState } from 'react'; +import { + HeadersProps, + BaseLayout, + Notifications, +} from '@ovh-ux/manager-react-components'; +import { + OsdsTabBar, + OsdsTabBarItem, + OsdsTabs, +} from '@ovhcloud/ods-components/react'; +import { NavLink, Outlet, useLocation, useNavigate } from 'react-router-dom'; +import Breadcrumb from '@/components/breadcrumb/Breadcrumb.component'; +import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb'; + +export type DashboardTabItemProps = { + name: string; + title: string; + to: string; +}; + +export type TDashboardLayoutProps = { + tabs: DashboardTabItemProps[]; + breadcrumbItems: BreadcrumbItem[]; + header: HeadersProps; + backLinkLabel?: string; + onClickReturn?: () => void; +}; + +export default function VcdDashboardLayout({ + tabs, + breadcrumbItems, + header, + backLinkLabel, + onClickReturn, +}: TDashboardLayoutProps) { + const [panel, setActivePanel] = useState(''); + const { pathname: path } = useLocation(); + const navigate = useNavigate(); + + useEffect(() => { + const findActiveTab = (tabList: DashboardTabItemProps[]) => + tabList.find((tab) => tab.to === path); + const findActiveParentTab = (tabList: DashboardTabItemProps[]) => + tabList.find((tab) => tab.to === path.slice(0, path.lastIndexOf('/'))); + + const activeTab = findActiveTab(tabs) || findActiveParentTab(tabs); + if (activeTab) { + setActivePanel(activeTab.name); + } else { + setActivePanel(tabs[0].name); + navigate(`${tabs[0].to}`); + } + }, [path]); + + return ( +
+ + + {tabs.map((tab: DashboardTabItemProps) => ( + + + {tab.title} + + + ))} + + + } + breadcrumb={} + message={} + backLinkLabel={backLinkLabel} + onClickReturn={onClickReturn} + /> + +
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/compute/ComputeOrderCells.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/compute/ComputeOrderCells.component.tsx new file mode 100644 index 000000000000..839fddb6f188 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/compute/ComputeOrderCells.component.tsx @@ -0,0 +1,71 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + DataGridTextCell, + Description, +} from '@ovh-ux/manager-react-components'; +import { OsdsRadio, OsdsRadioButton } from '@ovhcloud/ods-components/react'; +import { ODS_RADIO_BUTTON_SIZE } from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { IVdcOrderableVhostPriced } from '@/types/vcd-vdc-orderable-resource.interface'; +import { getVdcResourcePriceLabel } from '@/utils/getPricedOrderableResource'; +import { useDatacentreOrderContext } from '@/context/DatacentreOrder.context'; + +export const ComputeOrderSelectCell = (vHost: IVdcOrderableVhostPriced) => { + const { selectedResource, setSelectedResource } = useDatacentreOrderContext(); + return ( + + + setSelectedResource(vHost.profile)} + size={ODS_RADIO_BUTTON_SIZE.sm} + color={ODS_THEME_COLOR_INTENT.primary} + /> + + + ); +}; + +export const ComputeOrderVhostCell = (vHost: IVdcOrderableVhostPriced) => ( + {vHost.profile} +); + +export const ComputeOrderCpuSpeedCell = (vHost: IVdcOrderableVhostPriced) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + return ( + + {t('managed_vcd_vdc_vcpu_value', { speed: vHost.vCPUSpeed })} + + ); +}; + +export const ComputeOrderRamCell = (vHost: IVdcOrderableVhostPriced) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/order'); + return ( + + {t('managed_vcd_vdc_order_ram_value', { + ram: vHost.memoryQuota, + })} + + ); +}; + +export const ComputeOrderCpuCountCell = (vHost: IVdcOrderableVhostPriced) => ( + {vHost.vCPUCount} +); + +export const ComputeOrderPriceCell = (vHost: IVdcOrderableVhostPriced) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/order'); + return ( + + + {getVdcResourcePriceLabel(vHost)} + + {t('managed_vcd_vdc_order_price_detail')} + + ); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.component.tsx new file mode 100644 index 000000000000..afd8f9567d90 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.component.tsx @@ -0,0 +1,127 @@ +import { + Datagrid, + ErrorBanner, + Subtitle, + Title, + useResourcesIcebergV2, +} from '@ovh-ux/manager-react-components'; +import { OsdsDivider } from '@ovhcloud/ods-components/react'; +import React, { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import Loading from '@/components/loading/Loading.component'; +import TDatagridRoute from '@/types/datagrid-route.type'; +import { useAutoRefetch } from '@/data/hooks/useAutoRefetch'; +import { + hasResourceUpdatingTargetSpec, + UpdatableResource, +} from '@/utils/refetchConditions'; +import { icebergListingQueryKey } from '@/utils/queryKeys'; + +export type TDatagridContainerProps = { + route: TDatagridRoute; + title: string; + isEmbedded?: boolean; + queryKey: string[]; + columns: any[]; + orderButton?: React.JSX.Element; +}; + +export default function DatagridContainer({ + title, + queryKey, + isEmbedded = false, + route: { api, onboarding }, + columns, + orderButton, +}: Readonly) { + const [flattenData, setFlattenData] = useState[]>([]); + const navigate = useNavigate(); + const listingQueryKey = [...queryKey, icebergListingQueryKey]; + + const { + data, + fetchNextPage, + hasNextPage, + isError, + isLoading, + error, + status, + sorting, + setSorting, + } = useResourcesIcebergV2({ + route: api, + queryKey: listingQueryKey, + }); + + useAutoRefetch({ + queryKey: listingQueryKey, + enabled: hasResourceUpdatingTargetSpec( + (flattenData as unknown) as UpdatableResource[], + ), + interval: 4000, + }); + + useEffect(() => { + if ( + status === 'success' && + data?.pages[0].data.length === 0 && + onboarding + ) { + navigate(onboarding); + } + const flatten = data?.pages.map((page: any) => page.data).flat(); + setFlattenData(flatten ?? []); + }, [data]); + + if (isError) { + // return ; + // TODO temporary fix + return ( + + ); + } + + if (isLoading && !flattenData.length) { + return ( +
+ +
+ ); + } + + const layoutCss = `px-10 pt-${isEmbedded ? '0' : '5'}`; + + const header = isEmbedded ? ( + {title} + ) : ( + {title} + ); + + return ( +
+
{header}
+ + {orderButton &&
{orderButton}
} + + {flattenData.length && ( + + )} + +
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.spec.tsx new file mode 100644 index 000000000000..4b1e7892fca8 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/container/DatagridContainer.spec.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { render } from '@testing-library/react'; +import { describe, vi } from 'vitest'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import DatagridContainer, { + TDatagridContainerProps, +} from './DatagridContainer.component'; + +const navigationMock = vi.fn(); + +vi.mock('react-router-dom', () => ({ + useNavigate: () => ({ + navigate: navigationMock, + }), + useLocation: () => ({ + pathname: '/stublocation', + }), +})); + +vi.mock('@ovh-ux/manager-react-components', async (managerComonents) => { + const module = await managerComonents< + typeof import('@ovh-ux/manager-react-components') + >(); + return { + ...module, + useResourcesIcebergV2: vi.fn().mockReturnValue({ + data: { pages: [{ data: [{ id: 'value for id' }] }] }, + isLoading: false, + }), + useDatagridSearchParams: vi.fn().mockReturnValue({ + pagination: { + pageIndex: 0, + pageSize: 10, + }, + setPagination: vi.fn(), + sorting: { desc: false, id: 'value for id' }, + setSorting: vi.fn(), + }), + }; +}); + +const renderComponent = (props: TDatagridContainerProps) => { + const queryClient = new QueryClient(); + return render( + + + , + ); +}; + +describe('DatagridContainer component unit test suite', () => { + it.each([ + [true, 'pt-0'], + [false, 'pt-5'], + ])( + 'should create datagrid container with right css when isEmbedded=%s', + (isEmbedded, css) => { + // given + const props: TDatagridContainerProps = { + route: { + api: 'stubapi', + onboarding: 'onboarding', + }, + queryKey: ['queryKey'], + columns: [ + { + id: 'id', + cell: ({ id }) => {id}, + label: 'title for id', + }, + ], + isEmbedded, + title: 'my datagrid', + }; + + // when + const { getByTestId, container, getByText } = renderComponent(props); + + // then + expect(getByTestId('header-id')).toHaveTextContent('title for id'); + + // and + expect(container).toContainHTML(`class="px-10 ${css}"`); + + // and + expect(getByText(props.title)).toBeDefined(); + + // and + expect(getByText('value for id')).toBeDefined(); + }, + ); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/storage/StorageOrderCells.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/storage/StorageOrderCells.component.tsx new file mode 100644 index 000000000000..b94e76afee5b --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/datagrid/storage/StorageOrderCells.component.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + DataGridTextCell, + Description, +} from '@ovh-ux/manager-react-components'; +import { OsdsRadio, OsdsRadioButton } from '@ovhcloud/ods-components/react'; +import { ODS_RADIO_BUTTON_SIZE } from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { IVdcOrderableStoragePriced } from '@/types/vcd-vdc-orderable-resource.interface'; +import { getVdcResourcePriceLabel } from '@/utils/getPricedOrderableResource'; +import { useDatacentreOrderContext } from '@/context/DatacentreOrder.context'; + +export const StorageOrderSelectCell = (storage: IVdcOrderableStoragePriced) => { + const { selectedResource, setSelectedResource } = useDatacentreOrderContext(); + return ( + + + setSelectedResource(storage.profile)} + size={ODS_RADIO_BUTTON_SIZE.xs} + color={ODS_THEME_COLOR_INTENT.primary} + /> + + + ); +}; + +export const StorageOrderTypeCell = (storage: IVdcOrderableStoragePriced) => ( + {storage.name} +); + +export const StorageOrderPriceCell = (storage: IVdcOrderableStoragePriced) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/order'); + return ( + + + {getVdcResourcePriceLabel(storage)} + + {t('managed_vcd_vdc_order_price_detail')} + + ); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.component.tsx new file mode 100644 index 000000000000..66f2a411a7fa --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.component.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { ShellContext } from '@ovh-ux/manager-react-shell-client'; +import { + ErrorMessage, + TRACKING_LABELS, +} from '@ovh-ux/manager-react-components/src/components/'; +import { ErrorBanner } from '@ovh-ux/manager-react-components'; + +interface ErrorObject { + [key: string]: any; +} + +function getTrackingTypology(error: ErrorMessage) { + if (error?.detail?.status && Math.floor(error.detail.status / 100) === 4) { + return [401, 403].includes(error.detail.status) + ? TRACKING_LABELS.UNAUTHORIZED + : TRACKING_LABELS.SERVICE_NOT_FOUND; + } + return TRACKING_LABELS.PAGE_LOAD; +} + +const Errors: React.FC = ({ error }) => { + const navigate = useNavigate(); + const location = useLocation(); + const { shell } = React.useContext(ShellContext); + const { tracking, environment } = shell; + const env = environment.getEnvironment(); + + React.useEffect(() => { + env.then((response) => { + const { applicationName } = response; + const name = `errors::${getTrackingTypology(error)}::${applicationName}`; + tracking.trackPage({ + name, + level2: '81', + type: 'navigation', + page_category: location.pathname, + }); + }); + }, []); + + return ( + navigate(location.pathname, { replace: true })} + onRedirectHome={() => navigate('/', { replace: true })} + /> + ); +}; + +export default Errors; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.scss b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.scss new file mode 100644 index 000000000000..c73220cd3be3 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/error/Error.scss @@ -0,0 +1,18 @@ +.manager-error-page { + margin-left: auto; + margin-right: auto; + max-width: 600px; + width: 100%; + display: grid; + height: 100%; + overflow: hidden; + .manager-error-page-image { + img { + width: 100%; + } + } + .manager-error-page-footer { + text-align: right; + overflow: hidden; + } +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/DatacentreOrder.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/DatacentreOrder.component.tsx new file mode 100644 index 000000000000..85500ec03e87 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/DatacentreOrder.component.tsx @@ -0,0 +1,152 @@ +import React, { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import { + Datagrid, + DatagridColumn, + Description, + ErrorBanner, + Subtitle, +} from '@ovh-ux/manager-react-components'; +import { OsdsButton } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { ODS_BUTTON_SIZE, ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components'; +import { QuantitySelector } from './QuantitySelector.component'; +import { useDatacentreOrderContext } from '@/context/DatacentreOrder.context'; +import { useVdcOrderableResource } from '@/data/hooks/useOrderableResource'; +import { useVcdCatalog } from '@/data/hooks/useVcdCatalog'; +import useVcdOrder from '@/data/hooks/useVcdOrder'; +import { validateQuantity } from '@/utils/formValidation'; +import { getPricedVdcResources } from '@/utils/getPricedOrderableResource'; +import Loading from '../loading/Loading.component'; +import { + IVdcOrderableStoragePriced, + IVdcOrderableVhostPriced, +} from '@/types/vcd-vdc-orderable-resource.interface'; + +type OrderType = 'compute' | 'storage'; +type OrderColumns = T extends 'compute' + ? DatagridColumn[] + : DatagridColumn[]; + +interface DatacentreOrderProps { + orderType: T; + columns: OrderColumns; + title: string; + subtitle: string; + backLink: string; + minQuantity?: number; + maxQuantity?: number; +} + +export const DatacentreOrder = ({ + orderType, + columns, + title, + subtitle, + backLink, + minQuantity = 1, + maxQuantity = 100, +}: DatacentreOrderProps) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/order'); + const navigate = useNavigate(); + const { id, vdcId } = useParams(); + const { + selectedResource, + setSelectedResource, + selectedQuantity, + setSelectedQuantity, + } = useDatacentreOrderContext(); + const { + data: orderableResource, + isLoading: isLoadingResource, + isError: isResourceError, + } = useVdcOrderableResource(id, vdcId); + const { + data: catalog, + isLoading: isLoadingCatalog, + isError: isCatalogError, + } = useVcdCatalog(id); + const { redirectToOrder } = useVcdOrder({ + serviceName: id, + planCode: selectedResource, + quantity: selectedQuantity, + vdcOrgId: vdcId, + }); + + const isValidQuantity = validateQuantity({ + quantity: selectedQuantity, + min: minQuantity, + max: maxQuantity, + }); + const pricedResources = getPricedVdcResources({ + catalog: catalog?.data, + resources: + orderType === 'compute' + ? orderableResource?.data?.compute + : orderableResource?.data?.storage, + }); + + useEffect(() => { + if (pricedResources?.length && !selectedResource) { + setSelectedResource(pricedResources[0].profile); + } + }, [selectedResource, pricedResources]); + + if (isLoadingResource || isLoadingCatalog) return ; + if (isResourceError || isCatalogError || !pricedResources?.length) { + return ( + + ); + } + + return ( +
+ {title} + {subtitle} + +
+ +
+
+ navigate(backLink)} + > + {t('managed_vcd_vdc_order_cancel_cta')} + + + {t('managed_vcd_vdc_order_confirm_cta')} + +
+
+ ); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/QuantitySelector.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/QuantitySelector.component.tsx new file mode 100644 index 000000000000..324ac00a0a15 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/form/QuantitySelector.component.tsx @@ -0,0 +1,82 @@ +import React, { SetStateAction } from 'react'; +import { Subtitle, Description } from '@ovh-ux/manager-react-components'; +import { + OsdsButton, + OsdsIcon, + OsdsInput, + OsdsQuantity, +} from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_VARIANT, + ODS_BUTTON_SIZE, + ODS_ICON_NAME, + ODS_ICON_SIZE, + ODS_INPUT_TYPE, +} from '@ovhcloud/ods-components'; + +type QuantitySelectorProps = { + quantity: number; + setQuantity: React.Dispatch>; + isValid: boolean; + min?: number; + max?: number; + title?: string; + label?: string; +}; + +export const QuantitySelector = ({ + quantity, + setQuantity, + isValid, + min = 1, + max = 100, + title, + label, +}: QuantitySelectorProps) => ( + + {title && {title}} + {label && {label}} + + + + + setQuantity(Number(event.detail.value))} + min={min} + max={max} + /> + + + + + +); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/loading/Loading.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/loading/Loading.component.tsx new file mode 100644 index 000000000000..47f2176c97ac --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/loading/Loading.component.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { OsdsSpinner } from '@ovhcloud/ods-components/react'; + +export default function Loading(props: React.HTMLAttributes) { + return ( +
+
+ +
+
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/EditDetailModal.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/EditDetailModal.tsx new file mode 100644 index 000000000000..c6ccb0827b11 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/EditDetailModal.tsx @@ -0,0 +1,135 @@ +import { ApiError } from '@ovh-ux/manager-core-api'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_VARIANT, + ODS_INPUT_TYPE, + ODS_MESSAGE_TYPE, + ODS_TEXT_LEVEL, + ODS_TEXT_SIZE, + OdsInputValueChangeEventDetail, + OsdsInputCustomEvent, +} from '@ovhcloud/ods-components'; +import { + OsdsButton, + OsdsFormField, + OsdsInput, + OsdsMessage, + OsdsModal, + OsdsText, +} from '@ovhcloud/ods-components/react'; +import { AxiosResponse } from 'axios'; +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +interface EditModalProps { + detailValue: string; + headline: string; + inputLabel: string; + errorHelper: string; + validateDetail: (detail: string) => boolean; + onCloseModal: () => void; + onEdit: (detail: string) => Promise>; + error: ApiError | null; +} + +export const EditDetailModal = ({ + detailValue, + headline, + inputLabel, + errorHelper, + validateDetail, + onCloseModal, + onEdit, + error, +}: EditModalProps) => { + const { t } = useTranslation('dashboard'); + const [newDetail, setNewDetail] = useState(detailValue || ''); + const [isErrorVisible, setIsErrorVisible] = useState(false); + const isValidDetail = validateDetail(newDetail); + const isButtonEnabled = isValidDetail && newDetail !== detailValue; + + const handleSubmit = async () => { + if (isValidDetail) { + setIsErrorVisible(false); + try { + await onEdit(newDetail); + } catch (err) { + setIsErrorVisible(true); + } + } + }; + + return ( + + {!!error && isErrorVisible && ( + setIsErrorVisible(false)} + > + + {t('managed_vcd_dashboard_edit_modal_error', { + error: error.response?.data?.message, + })} + + + )} + + + {inputLabel} + + , + ) => setNewDetail(e.target.value as string)} + color={ + isValidDetail + ? ODS_THEME_COLOR_INTENT.info + : ODS_THEME_COLOR_INTENT.error + } + /> + + {errorHelper} + + + + + {t('managed_vcd_dashboard_edit_modal_cta_cancel')} + + + {t('managed_vcd_dashboard_edit_modal_cta_edit')} + + + ); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/UpdateDetailModalHandler.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/UpdateDetailModalHandler.tsx new file mode 100644 index 000000000000..e5092bce2b54 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/modal/UpdateDetailModalHandler.tsx @@ -0,0 +1,89 @@ +import React from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { useNotifications } from '@ovh-ux/manager-react-components'; +import useManagedVcdOrganization from '@/data/hooks/useManagedVcdOrganization'; +import { useUpdateVcdOrganizationDetails } from '@/data/hooks/useUpdateVcdOrganization'; +import { IVcdOrganizationState } from '@/types/vcd-organization.interface'; +import { + validateDescription, + validateOrganizationName, +} from '@/utils/formValidation'; +import { EditDetailModal } from './EditDetailModal'; + +type OrganizationDetailName = 'name' | 'description'; +type TValidationFunctions = { + [key in OrganizationDetailName]: (value: string) => boolean; +}; +type TOrganizationDetails = { + [key in OrganizationDetailName]: string; +}; + +export const UpdateDetailModalHandler = ({ + detailName, +}: { + detailName: OrganizationDetailName; +}) => { + const { t } = useTranslation('dashboard'); + const navigate = useNavigate(); + const closeModal = () => navigate('..'); + const { addSuccess } = useNotifications(); + const { id } = useParams(); + const { data: vcdOrganization } = useManagedVcdOrganization({ id }); + const { updateDetails, error, isError } = useUpdateVcdOrganizationDetails({ + id, + onSuccess: () => { + addSuccess( + t(`managed_vcd_dashboard_edit_${detailName}_modal_success`), + true, + ); + closeModal(); + }, + }); + const currentDetails: IVcdOrganizationState = vcdOrganization.data.targetSpec; + + const getOrganizationDetailKey = (key: OrganizationDetailName) => { + const detailKeys: TOrganizationDetails = { + name: 'fullName', + description: 'description', + }; + return detailKeys[key]; + }; + const getOrganizationDetailValue = (key: OrganizationDetailName) => { + const details: TOrganizationDetails = { + name: vcdOrganization?.data?.currentState?.fullName, + description: vcdOrganization?.data?.currentState?.description, + }; + return details[key]; + }; + const getValidationFunction = (key: OrganizationDetailName) => { + const validationFunctions: TValidationFunctions = { + name: validateOrganizationName, + description: validateDescription, + }; + return validationFunctions[key]; + }; + + return ( + + updateDetails({ + id, + details: { + ...currentDetails, + [getOrganizationDetailKey(detailName)]: newValue, + }, + }) + } + onCloseModal={closeModal} + error={isError ? error : null} + /> + ); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.component.tsx new file mode 100644 index 000000000000..0a6c85e7028d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.component.tsx @@ -0,0 +1,121 @@ +import React from 'react'; +import { + DashboardTile, + Description, + useServiceDetails, +} from '@ovh-ux/manager-react-components'; +import { + OsdsChip, + OsdsIcon, + OsdsLink, + OsdsSkeleton, + OsdsTooltip, + OsdsTooltipContent, +} from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_CHIP_SIZE, + ODS_ICON_NAME, + ODS_ICON_SIZE, +} from '@ovhcloud/ods-components'; +import useCurrentUser from '@/hooks/user/useCurrentUser'; + +type TBillingTileProps = { + id: string; +}; + +function ServiceRenew({ id }: TBillingTileProps) { + const { data: billingService, isLoading } = useServiceDetails({ + resourceName: id, + }); + const { dateTimeFormat } = useCurrentUser(); + + const nextBillingDate = billingService?.data?.billing?.nextBillingDate; + + if (isLoading) { + return ; + } + + return nextBillingDate ? ( + + {dateTimeFormat?.format(new Date(nextBillingDate))} + + ) : ( + - + ); +} + +export default function BillingTile({ id }: TBillingTileProps) { + const { t } = useTranslation('dashboard'); + const { user } = useCurrentUser(); + + return ( +
+ {user?.email}, + }, + { + id: 'serviceRenew', + label: t('managed_vcd_dashboard_service_renew'), + value: , + }, + { + id: 'cancellation', + label: t('managed_vcd_dashboard_service_cancellation'), + value: ( + + {t('managed_vcd_dashboard_coming_soon')} + + ), + }, + { + id: 'password', + label: t('managed_vcd_dashboard_password'), + value: ( +
+
+ + {t('managed_vcd_dashboard_password_renew')} + + + + + {t('managed_vcd_dashboard_password_tooltip')} + + +
+ + {t('managed_vcd_dashboard_coming_soon')} + +
+ ), + }, + ]} + /> +
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.spec.tsx new file mode 100644 index 000000000000..ccfcd4782f07 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/billing-tile/BillingTile.spec.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import { + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import BillingTile from './BillingTile.component'; + +const shellContext = { + environment: { + getUser: vi.fn(), + getUserLocale: vi.fn().mockReturnValue('fr_FR'), + }, +}; + +const renderComponent = () => { + const queryClient = new QueryClient(); + + return render( + + + + + , + ); +}; + +describe.skip('BillingTile component unit test suite', () => { + it('should define all sections with correct typo', () => { + // when + const { getByText } = renderComponent(); + + // then + const billingTitle = getByText('managed_vcd_dashboard_service_management'); + expect(billingTitle).toHaveAttribute( + 'size', + ODS_THEME_TYPOGRAPHY_SIZE._400, + ); + expect(billingTitle).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.heading, + ); + + // and + const mailingTitle = getByText('managed_vcd_dashboard_mailing_list'); + const renewTitle = getByText('managed_vcd_dashboard_service_renew'); + const cancelTitle = getByText('managed_vcd_dashboard_service_cancellation'); + const pwdTitle = getByText('managed_vcd_dashboard_password'); + const subtitles = [mailingTitle, renewTitle, cancelTitle, pwdTitle]; + + subtitles.forEach((title: HTMLElement) => { + expect(title).toHaveAttribute('size', ODS_THEME_TYPOGRAPHY_SIZE._200); + expect(title).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.heading, + ); + }); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.component.tsx new file mode 100644 index 000000000000..66edd14e1fb7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.component.tsx @@ -0,0 +1,115 @@ +import { + Description, + LinkType, + Links, + Clipboard, + DashboardTile, +} from '@ovh-ux/manager-react-components'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core'; +import IVcdDatacentre from '@/types/vcd-datacenter.interface'; +import IVcdOrganization from '@/types/vcd-organization.interface'; +import { subRoutes } from '@/routes/routes.constant'; +import { iamActions } from '@/utils/iam.constants'; +import EditableTileItem from '../editable-tile-item/EditableTileItem.component'; +import { capitalize } from '@/utils/capitalize'; + +type TTileProps = { + vcdDatacentre: IVcdDatacentre; + vcdOrganization: IVcdOrganization; +}; + +export default function DatacentreGenerationInformationTile({ + vcdDatacentre, + vcdOrganization, +}: TTileProps) { + const { t } = useTranslation('dashboard'); + const { t: tVdc } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + const navigate = useNavigate(); + + return ( + navigate(subRoutes.editDescription)} + /> + ), + }, + { + id: 'commercialRange', + label: tVdc('managed_vcd_vdc_commercial_range'), + value: ( + + {capitalize(vcdDatacentre?.currentState?.commercialRange)} + + ), + }, + { + id: 'cpuCount', + label: tVdc('managed_vcd_vdc_vcpu_count'), + value: ( + + {vcdDatacentre?.currentState?.vCPUCount?.toString()} + + ), + }, + { + id: 'ramCount', + label: tVdc('managed_vcd_vdc_ram_count'), + value: ( + + {tVdc('managed_vcd_vdc_quota_value', { + quota: vcdDatacentre?.currentState?.memoryQuota, + })} + + ), + }, + { + id: 'vcpuSpeed', + label: tVdc('managed_vcd_vdc_vcpu_speed'), + value: ( + + {tVdc('managed_vcd_vdc_vcpu_value', { + speed: vcdDatacentre?.currentState?.vCPUSpeed, + })} + + ), + }, + { + id: 'interface', + label: t('managed_vcd_dashboard_management_interface'), + value: ( + + ), + }, + { + id: 'apiUrl', + label: t('managed_vcd_dashboard_api_url'), + value: , + }, + { + id: 'vdcId', + label: tVdc('managed_vcd_vdc_id'), + value: , + }, + ]} + /> + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.spec.tsx new file mode 100644 index 000000000000..eef4a6e1616e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.spec.tsx @@ -0,0 +1,107 @@ +import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { describe, expect, it, vi } from 'vitest'; +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; +import React from 'react'; +import DatacentreGeneralInformationTile from './DatacentreGeneralInformationTile.component'; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + mutations: { + retry: false, + }, + }, +}); + +vi.mock('react-router-dom', () => ({ + useNavigate: () => ({ navigate: vi.fn() }), + useParams: () => ({ id: 'id' }), +})); + +describe.skip('DatacentreGeneralInformationTile component unit test suite', () => { + it('should define all sections with correct typo', () => { + // given + const vcdOrg = { + currentState: { + apiUrl: 'https://vcd.my.demo.lab', + description: 'My demo VCD Organization', + fullName: 'Demo VCD', + region: 'CA-EAST-BHS', + name: 'org-ca-east-bhs-61ebdcec-0623-4a61-834f-a1719cd475b4', + spla: true, + webInterfaceUrl: 'https://vcd.my.second.lab', + }, + id: '61ebdcec-0623-4a61-834f-a1719cd475b4', + resourceStatus: 'READY', + targetSpec: { + description: 'My demo VCD Organization', + fullName: 'Demo VCD', + }, + iam: { + id: 'iam:id', + urn: 'test:urn', + }, + }; + + const datacentre = { + currentState: { + commercialRange: 'NSX', + ipQuota: 4, + storageQuota: 128, + vCPUCount: 8, + region: 'EU-WEST-GRA', + description: 'organization Virtual DataCenter', + memoryQuota: 16, + name: 'vdc-eu-west-gra-f88f2da8-b12a-4796-8765-1e2afb323ad2', + vCPUSpeed: 60, + }, + id: 'f88f2da8-b12a-4796-8765-1e2afb323ad2', + resourceStatus: 'UPDATING', + targetSpec: { + description: 'Primary organization Virtual DataCenter', + vCPUSpeed: 60, + }, + iam: { + id: 'iam:id', + urn: 'test2:urn', + }, + }; + + // when + const { getByText } = render( + + + , + ); + + // then + const title = getByText('managed_vcd_dashboard_general_information'); + expect(title).toHaveAttribute('size', ODS_THEME_TYPOGRAPHY_SIZE._400); + expect(title).toHaveAttribute('level', ODS_THEME_TYPOGRAPHY_LEVEL.heading); + + // and + const description = getByText(datacentre.currentState.description); + expect(description).toHaveAttribute('size', ODS_THEME_TYPOGRAPHY_SIZE._400); + expect(description).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.body, + ); + + // and + const webUrlLink = getByText( + 'managed_vcd_dashboard_management_interface_access', + ).closest('osds-link'); + expect(webUrlLink?.href).toBe(vcdOrg.currentState.webInterfaceUrl); + expect(webUrlLink).toHaveAttribute('color', ODS_THEME_COLOR_INTENT.primary); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.component.tsx new file mode 100644 index 000000000000..1fc9a10e3de6 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.component.tsx @@ -0,0 +1,56 @@ +import React, { Suspense } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Description, ManagerButton } from '@ovh-ux/manager-react-components'; +import { OsdsIcon } from '@ovhcloud/ods-components/react'; +import { + ODS_BUTTON_SIZE, + ODS_BUTTON_TYPE, + ODS_BUTTON_VARIANT, + ODS_ICON_NAME, + ODS_ICON_SIZE, +} from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; + +type EditableTileItemProps = { + label: string; + urn: string; + iamActions: string[]; + onClickEdit: () => void; +}; + +export default function EditableTileItem({ + label, + urn, + iamActions, + onClickEdit, +}: EditableTileItemProps) { + const { t } = useTranslation('dashboard'); + + return ( +
+ {label} +
+ + + + + +
+
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.spec.tsx new file mode 100644 index 000000000000..4bad76561537 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/editable-tile-item/EditableTileItem.spec.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { describe, it } from 'vitest'; +import { ODS_ICON_NAME, ODS_ICON_SIZE } from '@ovhcloud/ods-components'; +import EditableTileItem from './EditableTileItem.component'; + +describe.skip('EditableTileItem component unit test suite', () => { + it('should display a label and the correct icon', () => { + // given + const label = 'Editable label'; + + // when + const { getByTestId, getByText } = render( + {}} + />, + ); + + // then + expect(getByText(label)).toBeInTheDocument(); + + const icon = getByTestId('editIcon'); + expect(icon).toBeInTheDocument(); + expect(icon).toHaveAttribute('name', ODS_ICON_NAME.PEN); + expect(icon).toHaveAttribute('size', ODS_ICON_SIZE.xxs); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.component.tsx new file mode 100644 index 000000000000..8d984f1c6b4e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.component.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { DashboardTile } from '@ovh-ux/manager-react-components'; +import { OsdsChip } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { ODS_CHIP_SIZE } from '@ovhcloud/ods-components'; +import { + DATA_PROTECTION_BACKUP_TITLE, + DATA_PROTECTION_RECOVERY_TITLE, +} from '@/pages/dashboard/organization/OrganizationDashboard.constants'; +import BackupTileItem from './backup-tile-item/BackupTileItem.component'; + +export default function DataProtectionTile() { + const { t } = useTranslation('dashboard'); + + return ( +
+ , + }, + { + id: 'recovery', + label: DATA_PROTECTION_RECOVERY_TITLE, + value: ( + + {t('managed_vcd_dashboard_coming_soon')} + + ), + }, + ]} + /> +
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.spec.tsx new file mode 100644 index 000000000000..87a584ac98a9 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/OrganizationDataProtectionTile.spec.tsx @@ -0,0 +1,145 @@ +import { act, render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import { + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; +import React from 'react'; +import { + QueryClient, + QueryClientProvider, + UseQueryResult, +} from '@tanstack/react-query'; +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import OrganizationDataProtectionTile from './OrganizationDataProtectionTile.component'; +import { useManagedVcdOrganizationBackup } from '../../../data/hooks/useManagedVcdOrganization'; +import IVcdOrganizationBackup, { + BackupResourceStatus, +} from '../../../types/vcd-organization-backup.interface'; + +vi.mock('../../../data/hooks/useManagedVcdOrganization', () => ({ + useManagedVcdOrganizationBackup: vi.fn(), +})); +vi.mocked(useManagedVcdOrganizationBackup).mockReturnValue( + {} as UseQueryResult, ApiError>, +); + +const shellContext = { + shell: { + navigation: { + getURL: vi.fn().mockResolvedValue('https://www.ovh.com'), + }, + }, +}; + +const renderComponent = () => { + const queryClient = new QueryClient(); + + return render( + + + + + , + ); +}; + +describe('OrganizationDataProtectionTile component unit test suite', () => { + it('should define all sections with correct typo', async () => { + // when + await act(async () => renderComponent()); + const { getByText } = screen; + + // then + const dataTitle = getByText('managed_vcd_dashboard_data_protection'); + expect(dataTitle).toHaveAttribute('size', ODS_THEME_TYPOGRAPHY_SIZE._400); + expect(dataTitle).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.heading, + ); + + // and + const backupTitle = getByText('Managed Backup'); + expect(backupTitle).toHaveAttribute('size', ODS_THEME_TYPOGRAPHY_SIZE._200); + expect(backupTitle).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.heading, + ); + + // and + const recoveryTitle = getByText('Managed Backup'); + expect(recoveryTitle).toHaveAttribute( + 'size', + ODS_THEME_TYPOGRAPHY_SIZE._200, + ); + expect(recoveryTitle).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.heading, + ); + }); +}); + +describe('OrganizationDataProtectionTile query state-based behavior unit test suite', () => { + it('should display backupLoading when query isLoading', async () => { + vi.mocked(useManagedVcdOrganizationBackup).mockReturnValue({ + isLoading: true, + } as UseQueryResult, ApiError>); + + // when + await act(async () => renderComponent()); + const { getByTestId } = screen; + + // then + expect(getByTestId('backupLoading')).toBeInTheDocument(); + }); + + it('should display backupError when query isError', async () => { + vi.mocked(useManagedVcdOrganizationBackup).mockReturnValue({ + isError: true, + } as UseQueryResult, ApiError>); + + // when + await act(async () => renderComponent()); + const { getByTestId } = screen; + + // then + expect(getByTestId('backupError')).toHaveTextContent( + 'managed_vcd_dashboard_backup_status_error', + ); + }); + + it('should display noBackup when query isError 404', async () => { + vi.mocked(useManagedVcdOrganizationBackup).mockReturnValue({ + isError: true, + error: { response: { status: 404 } }, + } as UseQueryResult, ApiError>); + + // when + await act(async () => renderComponent()); + const { getByTestId } = screen; + + // then + expect(getByTestId('noBackup')).toBeInTheDocument(); + }); + + it('should display backupStatus when query isSuccess', async () => { + const testStatus = BackupResourceStatus.CREATING; + vi.mocked(useManagedVcdOrganizationBackup).mockReturnValue({ + isSuccess: true, + data: { data: { resourceStatus: testStatus } }, + } as UseQueryResult, ApiError>); + + // when + await act(async () => renderComponent()); + const { getByTestId } = screen; + + // then + expect(getByTestId('backupStatus')).toBeInTheDocument(); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/backup-tile-item/BackupTileItem.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/backup-tile-item/BackupTileItem.component.tsx new file mode 100644 index 000000000000..fc792de7b300 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-data-tile/backup-tile-item/BackupTileItem.component.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { useParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { ShellContext } from '@ovh-ux/manager-react-shell-client'; +import { Links, LinkType } from '@ovh-ux/manager-react-components'; +import { ODS_CHIP_SIZE } from '@ovhcloud/ods-components'; +import { OsdsChip, OsdsSkeleton } from '@ovhcloud/ods-components/react'; +import { veeamBackupAppName } from '@/routes/routes.constant'; +import { useManagedVcdOrganizationBackup } from '@/data/hooks/useManagedVcdOrganization'; +import { + BackupBadgeParams, + getBackupBadgeParams, + getBackupBadgeStatus, +} from '@/utils/getBackupBadge'; + +export default function BackupTileItem() { + const { id } = useParams(); + const { t } = useTranslation('dashboard'); + const { shell } = React.useContext(ShellContext); + const { data: vcdBackup, isLoading, error } = useManagedVcdOrganizationBackup( + id, + ); + const [veeamHref, setVeeamHref] = React.useState(''); + const badgeParams: BackupBadgeParams = getBackupBadgeParams( + getBackupBadgeStatus({ + errorStatus: error?.response?.status, + backupStatus: vcdBackup?.data?.resourceStatus, + }), + ); + + React.useEffect(() => { + shell.navigation + .getURL(veeamBackupAppName, '', {}) + .then((url: string) => setVeeamHref(url)); + }, []); + + return ( +
+ {isLoading && } + + {t(badgeParams.translationKey)} + + +
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/DatacentresCount.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/DatacentresCount.component.tsx new file mode 100644 index 000000000000..e40b52bcf946 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/DatacentresCount.component.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Description } from '@ovh-ux/manager-react-components'; +import { useParams } from 'react-router-dom'; +import { OsdsSkeleton, OsdsMessage } from '@ovhcloud/ods-components/react'; +import { ODS_MESSAGE_TYPE, ODS_SKELETON_SIZE } from '@ovhcloud/ods-components'; +import useManagedVcdDatacentres from '@/data/hooks/useManagedVcdDatacentres'; + +export const DatacentresCount: React.FC = () => { + const { id } = useParams(); + const { + data: vDatacentres, + isError, + error, + isLoading, + } = useManagedVcdDatacentres(id); + + if (isError) { + return ( + + {error?.response?.data?.message} + + ); + } + + return isLoading ? ( + + ) : ( + {vDatacentres?.data?.length.toString()} + ); +}; + +export default DatacentresCount; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.component.tsx new file mode 100644 index 000000000000..9b6b5b5268f6 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.component.tsx @@ -0,0 +1,110 @@ +import { + LinkType, + Links, + Clipboard, + DashboardTile, + Region, +} from '@ovh-ux/manager-react-components'; +import { + ODS_THEME_COLOR_HUE, + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; +import { OsdsText } from '@ovhcloud/ods-components/react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core'; +import IVcdOrganization from '@/types/vcd-organization.interface'; +import { subRoutes } from '@/routes/routes.constant'; +import { iamActions } from '@/utils/iam.constants'; +import EditableTileItem from '../editable-tile-item/EditableTileItem.component'; +import DatacentresCount from './DatacentresCount.component'; + +type TTileProps = { + vcdOrganization: IVcdOrganization; +}; + +export default function OrganizationGenerationInformationTile({ + vcdOrganization, +}: TTileProps) { + const { t } = useTranslation('dashboard'); + const navigate = useNavigate(); + + return ( + navigate(subRoutes.editName)} + /> + ), + }, + { + id: 'description', + label: t('managed_vcd_dashboard_description'), + value: ( + navigate(subRoutes.editDescription)} + /> + ), + }, + { + id: 'location', + label: t('managed_vcd_dashboard_localisation'), + value: ( + + + + ), + }, + { + id: 'datacentresCount', + label: t('managed_vcd_dashboard_datacentres_count'), + value: , + }, + { + id: 'interface', + label: t('managed_vcd_dashboard_management_interface'), + value: ( + + ), + }, + { + id: 'apiUrl', + label: t('managed_vcd_dashboard_api_url'), + value: , + }, + ]} + /> + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.spec.tsx new file mode 100644 index 000000000000..66db2fef25aa --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.spec.tsx @@ -0,0 +1,66 @@ +import { render } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; +import React from 'react'; +import OrganizationGeneralInformationTile from './OrganizationGeneralInformationTile.component'; + +vi.mock('react-router-dom', () => ({ + useNavigate: () => ({ navigate: vi.fn() }), + useParams: () => ({ id: 'id' }), +})); + +describe.skip('OrganizationGeneralInformationTile component unit test suite', () => { + it('should define all sections with correct typo', () => { + // given + const vcdOrg = { + currentState: { + apiUrl: 'https://vcd.my.demo.lab', + description: 'My demo VCD Organization', + fullName: 'Demo VCD', + region: 'CA-EAST-BHS', + name: 'org-ca-east-bhs-61ebdcec-0623-4a61-834f-a1719cd475b4', + spla: true, + webInterfaceUrl: 'https://vcd.my.second.lab', + }, + id: '61ebdcec-0623-4a61-834f-a1719cd475b4', + resourceStatus: 'READY', + targetSpec: { + description: 'My demo VCD Organization', + fullName: 'Demo VCD', + }, + iam: { + id: 'iam:id', + urn: 'test:urn', + }, + }; + + // when + const { getByText } = render( + , + ); + + // then + const title = getByText('managed_vcd_dashboard_general_information'); + expect(title).toHaveAttribute('size', ODS_THEME_TYPOGRAPHY_SIZE._400); + expect(title).toHaveAttribute('level', ODS_THEME_TYPOGRAPHY_LEVEL.heading); + + // and + const description = getByText(vcdOrg.currentState.description); + expect(description).toHaveAttribute('size', ODS_THEME_TYPOGRAPHY_SIZE._400); + expect(description).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.body, + ); + + // and + const webUrlLink = getByText( + 'managed_vcd_dashboard_management_interface_access', + ).closest('osds-link'); + expect(webUrlLink?.href).toBe(vcdOrg.currentState.webInterfaceUrl); + expect(webUrlLink).toHaveAttribute('color', ODS_THEME_COLOR_INTENT.primary); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.component.tsx new file mode 100644 index 000000000000..2d60a54f917e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.component.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { + ActionMenu, + DashboardTile, + Description, +} from '@ovh-ux/manager-react-components'; +import { useTranslation } from 'react-i18next'; +import { ODS_ICON_NAME } from '@ovhcloud/ods-components'; +import { useParams } from 'react-router-dom'; +import useVcdOrder from '@/data/hooks/useVcdOrder'; +import { WINDOWS_LICENSE_PLANCODE } from '@/utils/planCode.constants'; + +export default function OrganizationOptionsTile({ + isLicenseActive, +}: Readonly<{ + isLicenseActive: boolean; +}>) { + const { t } = useTranslation('dashboard'); + const { id } = useParams(); + const { redirectToOrder } = useVcdOrder({ + serviceName: id, + planCode: WINDOWS_LICENSE_PLANCODE, + }); + + return ( +
+ + {t('managed_vcd_dashboard_windows_license_active')} + + ) : ( +
+ + {t('managed_vcd_dashboard_windows_license_unactive')} + + +
+ ), + }, + ]} + /> +
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.spec.tsx new file mode 100644 index 000000000000..6bd0d1b5913e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/organization-options-tile/OrganizationOptionsTile.spec.tsx @@ -0,0 +1,63 @@ +import { render } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import { + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; +import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { + ShellContext, + ShellContextType, +} from '@ovh-ux/manager-react-shell-client'; +import OrganizationOptionsTile from './OrganizationOptionsTile.component'; + +const shellContext = { + environment: { + getRegion: vi.fn(), + getUser: vi.fn(), + }, +}; + +const renderComponent = () => { + const queryClient = new QueryClient(); + + return render( + + + + + , + ); +}; + +describe('OrganizationOptionsTile component unit test suite', () => { + it('should define all sections with correct typo', () => { + // when + const { getByText } = renderComponent(); + + // then + const optionsTitle = getByText('managed_vcd_dashboard_options'); + expect(optionsTitle).toHaveAttribute( + 'size', + ODS_THEME_TYPOGRAPHY_SIZE._400, + ); + expect(optionsTitle).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.heading, + ); + + // and + const licenceTitle = getByText('managed_vcd_dashboard_windows_license'); + expect(licenceTitle).toHaveAttribute( + 'size', + ODS_THEME_TYPOGRAPHY_SIZE._200, + ); + expect(licenceTitle).toHaveAttribute( + 'level', + ODS_THEME_TYPOGRAPHY_LEVEL.heading, + ); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.component.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.component.tsx new file mode 100644 index 000000000000..7519c188c365 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.component.tsx @@ -0,0 +1,17 @@ +import { CommonTitle } from '@ovh-ux/manager-react-components'; +import { ODS_THEME_TYPOGRAPHY_SIZE } from '@ovhcloud/ods-common-theming'; +import React from 'react'; + +export type TChildrenProps = { + children: string; +}; + +const TileSubtitle = ({ children }: TChildrenProps) => { + return ( + + {children} + + ); +}; + +export default TileSubtitle; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.spec.tsx new file mode 100644 index 000000000000..3ab92e6c3ace --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/components/tiles/tile-subtitle/TileSubtitle.spec.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; +import { ODS_THEME_TYPOGRAPHY_SIZE } from '@ovhcloud/ods-common-theming'; +import TileSubtitle from './TileSubtitle.component'; + +describe('TileSubtitle component unit test suite', () => { + it('should set default typo size for given text', () => { + // given + const titleText = 'my title'; + + // when + const { getByText } = render({titleText}); + + // then + expect(getByText(titleText)).toHaveAttribute( + 'size', + ODS_THEME_TYPOGRAPHY_SIZE._200, + ); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/context/DatacentreOrder.context.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/context/DatacentreOrder.context.tsx new file mode 100644 index 000000000000..859cc780399c --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/context/DatacentreOrder.context.tsx @@ -0,0 +1,56 @@ +import React, { + createContext, + Dispatch, + ReactNode, + SetStateAction, + useContext, + useMemo, + useState, +} from 'react'; + +type DatacentreOrderContextType = { + selectedResource: string; + setSelectedResource: Dispatch>; + selectedQuantity: number; + setSelectedQuantity: Dispatch>; +}; + +type DatacentreOrderProviderProps = { + children: ReactNode; +}; + +const DatacentreOrderContext = createContext< + DatacentreOrderContextType | undefined +>(undefined); + +export const DatacentreOrderProvider: React.FC = ({ + children, +}) => { + const [selectedResource, setSelectedResource] = useState(''); + const [selectedQuantity, setSelectedQuantity] = useState(1); + const contextValue = useMemo( + () => ({ + selectedResource, + setSelectedResource, + selectedQuantity, + setSelectedQuantity, + }), + [selectedResource, selectedQuantity], + ); + + return ( + + {children} + + ); +}; + +export const useDatacentreOrderContext = (): DatacentreOrderContextType => { + const context = useContext(DatacentreOrderContext); + if (context === undefined) { + throw new Error( + 'useDatacentreOrderContext must be used within a DatacentreOrderProvider', + ); + } + return context; +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-cart.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-cart.ts new file mode 100644 index 000000000000..9e8e6e190601 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-cart.ts @@ -0,0 +1,9 @@ +import apiClient, { ApiResponse } from '@ovh-ux/manager-core-api'; +import { TVcdCatalog } from '@/types/vcd-catalog.interface'; + +export const getVcdCatalog = async ( + serviceName: string, +): Promise> => + apiClient.v6.get( + `/order/cartServiceOption/vmwareCloudDirector/${serviceName}`, + ); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-datacentre.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-datacentre.ts new file mode 100644 index 000000000000..e47ec1cb7918 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd-datacentre.ts @@ -0,0 +1,58 @@ +import { ApiResponse, apiClient } from '@ovh-ux/manager-core-api'; +import IVcdDatacentre, { + IVcdDatacentreState, +} from '@/types/vcd-datacenter.interface'; +import { VCD_ORGANIZATION_ROUTE } from './hpc-vmware-managed-vcd.constants'; +import { IVdcOrderableResourceData } from '@/types/vcd-vdc-orderable-resource.interface'; + +export type UpdateVdcDetailsParams = { + id: string; + vdcId: string; + details: IVcdDatacentreState; +}; + +export const getVcdDatacentresRoute = (id: string) => { + return `${VCD_ORGANIZATION_ROUTE}/${id}/virtualDataCenter`; +}; + +export const getVcdDatacentreRoute = (id: string, vdcId: string) => { + return `${getVcdDatacentresRoute(id)}/${vdcId}`; +}; + +export const getVcdDatacentreComputeRoute = (id: string, vdcId: string) => { + return `${getVcdDatacentreRoute(id, vdcId)}/compute`; +}; + +export const getVcdDatacentreStorageRoute = (id: string, vdcId: string) => { + return `${getVcdDatacentreRoute(id, vdcId)}/storage`; +}; + +export const getVdcOrderableResourceRoute = (id: string, vdcId: string) => { + return `${getVcdDatacentreRoute(id, vdcId)}/orderableResource`; +}; + +export const getVcdDatacentre = async ( + id: string, + vdcId: string, +): Promise> => + apiClient.v2.get(getVcdDatacentreRoute(id, vdcId)); + +export const getVcdDatacentres = async ( + id: string, +): Promise> => + apiClient.v2.get(getVcdDatacentresRoute(id)); + +export const updateVdcDetails = async ({ + id, + vdcId, + details, +}: UpdateVdcDetailsParams) => + apiClient.v2.put(getVcdDatacentreRoute(id, vdcId), { + targetSpec: details, + }); + +export const getVdcOrderableResource = async ( + id: string, + vdcId: string, +): Promise> => + apiClient.v2.get(getVdcOrderableResourceRoute(id, vdcId)); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.constants.ts new file mode 100644 index 000000000000..52f99990905f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.constants.ts @@ -0,0 +1 @@ +export const VCD_ORGANIZATION_ROUTE = '/vmwareCloudDirector/organization'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.ts new file mode 100644 index 000000000000..113cee5b6970 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/api/hpc-vmware-managed-vcd.ts @@ -0,0 +1,47 @@ +import { ApiResponse, apiClient } from '@ovh-ux/manager-core-api'; +import IVcdOrganization, { + IVcdOrganizationState, +} from '@/types/vcd-organization.interface'; +import { VCD_ORGANIZATION_ROUTE } from './hpc-vmware-managed-vcd.constants'; +import IVcdOrganizationBackup from '@/types/vcd-organization-backup.interface'; + +export type GetVcdOrganizationListParams = { + /** Filter resources on IAM tags */ + iamTags: any; +}; + +export type UpdateVcdOrganizationDetailsParams = { + id: string; + details: IVcdOrganizationState; +}; + +/** + * VMware on OVHcloud : Get VMware on OVHcloud + */ +export const getVcdOrganization = async ( + id: string, +): Promise> => + apiClient.v2.get(`${VCD_ORGANIZATION_ROUTE}/${id}`); + +/** + * Get VCD Backup + */ +export const getVcdOrganizationBackup = async ( + organizationId: string, +): Promise> => + apiClient.v2.get( + `/vmwareCloudDirector/backup/${organizationId}-veeam-backup`, + ); + +/** + * Edit VCD Organization + */ +export const updateVcdOrganizationDetails = async ({ + id, + details, +}: UpdateVcdOrganizationDetailsParams): Promise> => + apiClient.v2.put(`${VCD_ORGANIZATION_ROUTE}/${id}`, { + targetSpec: details, + }); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useAutoRefetch.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useAutoRefetch.ts new file mode 100644 index 000000000000..c96dc35f9677 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useAutoRefetch.ts @@ -0,0 +1,29 @@ +import { useQueryClient } from '@tanstack/react-query'; +import { useEffect } from 'react'; + +type AutoRefetchProps = { + queryKey: string[]; + enabled: boolean; + interval?: number; +}; + +export const useAutoRefetch = ({ + queryKey, + enabled, + interval = 10_000, +}: AutoRefetchProps) => { + const queryClient = useQueryClient(); + + useEffect(() => { + if (!enabled) return; + + const refetchQueries = () => { + queryClient.invalidateQueries({ queryKey }); + }; + + const refetchInterval = setInterval(() => refetchQueries(), interval); + + // eslint-disable-next-line consistent-return + return () => clearInterval(refetchInterval); + }, [enabled, interval, queryKey, queryClient]); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdDatacentres.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdDatacentres.ts new file mode 100644 index 000000000000..731f91d80b79 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdDatacentres.ts @@ -0,0 +1,31 @@ +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import { + getVcdDatacentre, + getVcdDatacentres, +} from '../api/hpc-vmware-managed-vcd-datacentre'; +import IVcdDatacentre from '@/types/vcd-datacenter.interface'; +import { + getVcdDatacentresQueryKey, + getVcdDatacentreQueryKey, +} from '@/utils/queryKeys'; + +const useManagedVcdDatacentres = (id: string) => { + return useQuery, ApiError>({ + queryKey: getVcdDatacentresQueryKey(id), + queryFn: () => getVcdDatacentres(id), + retry: false, + placeholderData: keepPreviousData, + }); +}; + +export const useManagedVcdDatacentre = (id: string, vdcId: string) => { + return useQuery, ApiError>({ + queryKey: getVcdDatacentreQueryKey(id, vdcId), + queryFn: () => getVcdDatacentre(id, vdcId), + retry: false, + placeholderData: keepPreviousData, + }); +}; + +export default useManagedVcdDatacentres; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdOrganization.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdOrganization.ts new file mode 100644 index 000000000000..2d008866546d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useManagedVcdOrganization.ts @@ -0,0 +1,47 @@ +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; +import { + keepPreviousData, + useQuery, + UseQueryOptions, +} from '@tanstack/react-query'; +import { + getVcdOrganization, + getVcdOrganizationBackup, +} from '../api/hpc-vmware-managed-vcd'; +import IVcdOrganization from '@/types/vcd-organization.interface'; +import IVcdOrganizationBackup from '@/types/vcd-organization-backup.interface'; +import { + getVcdOrganizationQueryKey, + getVcdOrganizationBackupQueryKey, +} from '@/utils/queryKeys'; + +interface IUseManagedVcdOrganization + extends Pick { + id: string; +} + +const useManagedVcdOrganization = ({ + id, + refetchInterval, + refetchOnWindowFocus, +}: IUseManagedVcdOrganization) => { + return useQuery, ApiError>({ + queryKey: getVcdOrganizationQueryKey(id), + queryFn: () => getVcdOrganization(id), + retry: false, + refetchInterval, + refetchOnWindowFocus, + placeholderData: keepPreviousData, + }); +}; + +export const useManagedVcdOrganizationBackup = (id: string) => { + return useQuery, ApiError>({ + queryKey: getVcdOrganizationBackupQueryKey(id), + queryFn: () => getVcdOrganizationBackup(id), + retry: false, + placeholderData: keepPreviousData, + }); +}; + +export default useManagedVcdOrganization; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useOrderableResource.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useOrderableResource.ts new file mode 100644 index 000000000000..5b885ff5902f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useOrderableResource.ts @@ -0,0 +1,13 @@ +import { ApiResponse, ApiError } from '@ovh-ux/manager-core-api'; +import { useQuery, keepPreviousData } from '@tanstack/react-query'; +import { IVdcOrderableResourceData } from '@/types/vcd-vdc-orderable-resource.interface'; +import { getVdcOrderableResource } from '../api/hpc-vmware-managed-vcd-datacentre'; +import { getVdcOrderableResourceQueryKey } from '@/utils/queryKeys'; + +export const useVdcOrderableResource = (id: string, vdcId: string) => { + return useQuery, ApiError>({ + queryKey: getVdcOrderableResourceQueryKey(vdcId), + queryFn: () => getVdcOrderableResource(id, vdcId), + placeholderData: keepPreviousData, + }); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdDatacentre.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdDatacentre.ts new file mode 100644 index 000000000000..463e5fad9923 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdDatacentre.ts @@ -0,0 +1,39 @@ +import { ApiError } from '@ovh-ux/manager-core-api'; +import { useQueryClient, useMutation } from '@tanstack/react-query'; +import { + UpdateVdcDetailsParams, + updateVdcDetails, +} from '../api/hpc-vmware-managed-vcd-datacentre'; +import { + getVcdDatacentresQueryKey, + updateVdcDetailsMutationKey, +} from '@/utils/queryKeys'; + +export const useUpdateVdcDetails = ({ + id, + vdcId, + onSuccess, + onError, +}: { + id: string; + vdcId: string; + onSuccess?: () => void; + onError?: (result: ApiError) => void; +}) => { + const queryClient = useQueryClient(); + + const { mutateAsync: updateDetails, error, isError } = useMutation({ + mutationKey: updateVdcDetailsMutationKey(vdcId), + mutationFn: ({ details }: UpdateVdcDetailsParams) => + updateVdcDetails({ id, vdcId, details }), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getVcdDatacentresQueryKey(id), + }); + onSuccess?.(); + }, + onError: (result: ApiError) => onError?.(result), + }); + + return { updateDetails, error, isError }; +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdOrganization.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdOrganization.ts new file mode 100644 index 000000000000..384bdfc37e61 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useUpdateVcdOrganization.ts @@ -0,0 +1,44 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { ApiError } from '@ovh-ux/manager-core-api'; +import { + updateVcdOrganizationDetails, + UpdateVcdOrganizationDetailsParams, +} from '../api/hpc-vmware-managed-vcd'; +import { + getVcdOrganizationsQueryKey, + getVcdOrganizationQueryKey, + icebergListingQueryKey, + updateVcdOrganizationDetailsMutationKey, +} from '@/utils/queryKeys'; + +export const useUpdateVcdOrganizationDetails = ({ + id, + onSuccess, + onError, +}: { + id: string; + onSuccess?: () => void; + onError?: (result: ApiError) => void; +}) => { + const queryClient = useQueryClient(); + + const { mutateAsync: updateDetails, error, isError } = useMutation({ + mutationKey: updateVcdOrganizationDetailsMutationKey(id), + mutationFn: ({ details }: UpdateVcdOrganizationDetailsParams) => + updateVcdOrganizationDetails({ id, details }), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getVcdOrganizationQueryKey(id), + exact: true, + }); + queryClient.invalidateQueries({ + queryKey: [...getVcdOrganizationsQueryKey(), icebergListingQueryKey], + exact: true, + }); + onSuccess?.(); + }, + onError: (result: ApiError) => onError?.(result), + }); + + return { updateDetails, error, isError }; +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdCatalog.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdCatalog.ts new file mode 100644 index 000000000000..fe7948c0a534 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdCatalog.ts @@ -0,0 +1,13 @@ +import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; +import { getVcdCatalog } from '../api/hpc-vmware-managed-vcd-cart'; +import { TVcdCatalog } from '@/types/vcd-catalog.interface'; +import { getVcdCatalogQueryKey } from '@/utils/queryKeys'; + +export const useVcdCatalog = (serviceName: string) => { + return useQuery, ApiError>({ + queryKey: getVcdCatalogQueryKey(serviceName), + queryFn: () => getVcdCatalog(serviceName), + placeholderData: keepPreviousData, + }); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdOrder.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdOrder.ts new file mode 100644 index 000000000000..0998f4d2b675 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/data/hooks/useVcdOrder.ts @@ -0,0 +1,34 @@ +import { + useOrderURL, + getVcdProductSettings, +} from '@ovh-ux/manager-module-order'; + +interface IVcdOrder { + serviceName: string; + planCode: string; + quantity?: number; + vdcOrgId?: string; +} + +const useVcdOrder = ({ + serviceName, + planCode, + quantity, + vdcOrgId, +}: IVcdOrder) => { + const orderBaseUrl = useOrderURL('express_review_base'); + const vcdProductSettings = getVcdProductSettings({ + serviceName, + planCode, + quantity, + vdcOrgId, + }); + const orderLink = `${orderBaseUrl}?products=~(${vcdProductSettings})`; + const redirectToOrder = () => { + window.open(orderLink, '_blank', 'noopener,noreferrer'); + }; + + return { orderLink, redirectToOrder }; +}; + +export default useVcdOrder; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/breadcrumb/useBreadcrumb.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/breadcrumb/useBreadcrumb.tsx new file mode 100644 index 000000000000..43465f579d81 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/breadcrumb/useBreadcrumb.tsx @@ -0,0 +1,54 @@ +import { useEffect, useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { urls } from '@/routes/routes.constant'; + +export type BreadcrumbItem = { + id: string; + label: string | undefined; +}; + +type BreadcrumbEvent = Event & { + target: { isCollapsed?: boolean; isLast?: boolean }; +}; + +type BreadcrumbNavigationItem = BreadcrumbItem & { + onClick?: (event?: BreadcrumbEvent) => void; +}; + +export interface BreadcrumbProps { + rootLabel?: string; + items?: BreadcrumbItem[]; +} + +export const useBreadcrumb = ({ rootLabel, items }: BreadcrumbProps) => { + const [paths, setPaths] = useState([]); + const location = useLocation(); + const pathnames = location.pathname.split('/').filter((x) => x); + const navigate = useNavigate(); + + const rootItem = { + id: rootLabel, + label: rootLabel, + onClick: () => navigate(urls.root), + }; + + useEffect(() => { + const pathsTab = pathnames.map((value, index) => { + const item = items?.find(({ id }) => id === value); + + return { + id: item?.id ?? value, + label: item?.label ?? value, + onClick: (event: BreadcrumbEvent) => { + const { isCollapsed, isLast } = event.target; + if (!isCollapsed && !isLast) { + navigate(`/${pathnames.slice(0, index + 1).join('/')}`); + } + }, + }; + }); + setPaths(pathsTab); + }, [location, items]); + + return [rootItem, ...paths]; +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/guide/useGuideUtils.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/guide/useGuideUtils.tsx new file mode 100644 index 000000000000..337b7028c3e7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/guide/useGuideUtils.tsx @@ -0,0 +1,125 @@ +import { useContext, useEffect, useState } from 'react'; +import { CountryCode } from '@ovh-ux/manager-config'; +import { ShellContext } from '@ovh-ux/manager-react-shell-client'; + +type GuideLinks = { [key in CountryCode]: string }; + +const GUIDE_LIST: { [guideName: string]: Partial } = { + guideLink1: { + DE: 'https://www.ovhcloud.com/de/lp/vmware-vcd-evolution/', + ES: 'https://www.ovhcloud.com/es/lp/vmware-vcd-evolution/', + IE: 'https://www.ovhcloud.com/en-ie/lp/vmware-vcd-evolution/', + IT: 'https://www.ovhcloud.com/it/lp/vmware-vcd-evolution/', + PL: 'https://www.ovhcloud.com/pl/lp/vmware-vcd-evolution/', + PT: 'https://www.ovhcloud.com/pt/lp/vmware-vcd-evolution/', + FR: 'https://www.ovhcloud.com/fr/lp/vmware-vcd-evolution/', + MA: 'https://www.ovhcloud.com/fr/lp/vmware-vcd-evolution/', + SN: 'https://www.ovhcloud.com/fr/lp/vmware-vcd-evolution/', + TN: 'https://www.ovhcloud.com/fr/lp/vmware-vcd-evolution/', + NL: 'https://www.ovhcloud.com/nl/lp/vmware-vcd-evolution/', + GB: 'https://www.ovhcloud.com/en-gb/lp/vmware-vcd-evolution/', + CA: 'https://www.ovhcloud.com/en-ca/lp/vmware-vcd-evolution/', + QC: 'https://www.ovhcloud.com/fr/lp/vmware-vcd-evolution/', + US: + 'https://support.us.ovhcloud.com/hc/en-us/articles/28330641929491-VMware-Cloud-Director-How-to-Use-the-vCD-User-Interface', + }, + guideLink2: { + DE: + 'https://help.ovhcloud.com/csm/de-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + ES: + 'https://help.ovhcloud.com/csm/es-es-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + IE: + 'https://help.ovhcloud.com/csm/en-ie-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + IT: + 'https://help.ovhcloud.com/csm/it-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + PL: + 'https://help.ovhcloud.com/csm/pl-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + PT: + 'https://help.ovhcloud.com/csm/pt-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + FR: + 'https://help.ovhcloud.com/csm/fr-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad&spa=1', + MA: + 'https://help.ovhcloud.com/csm/fr-ma-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + SN: + 'https://help.ovhcloud.com/csm/fr-sn-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + TN: + 'https://help.ovhcloud.com/csm/fr-tn-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + GB: + 'https://help.ovhcloud.com/csm/en-gb-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + CA: + 'https://help.ovhcloud.com/csm/en-ca-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + QC: + 'https://help.ovhcloud.com/csm/fr-ca-documentation-hosted-private-cloud-hosted-private-cloud-powered-by-vmware-vcd?id=kb_browse_cat&kb_id=62e4cfed55d574502d4c6e78b7421953&kb_category=a249c12ef5adca941e11c2f7954b95ad', + US: + 'https://support.us.ovhcloud.com/hc/en-us/articles/28330367397139-VMware-Cloud-Director-The-Fundamentals-of-VCD', + }, + guideLink3: { + DE: + 'https://help.ovhcloud.com/csm/de-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062552', + ES: + '/https://help.ovhcloud.com/csm/es-es-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062605', + IE: + 'https://help.ovhcloud.com/csm/en-ie-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062555', + IT: + 'https://help.ovhcloud.com/csm/it-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062556', + PL: + 'https://help.ovhcloud.com/csm/pl-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062561', + PT: + 'https://help.ovhcloud.com/csm/pt-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062562', + FR: + 'https://help.ovhcloud.com/csm/fr-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062602', + MA: + 'https://help.ovhcloud.com/csm/fr-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062602', + SN: + 'https://help.ovhcloud.com/csm/fr-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062602', + TN: + 'https://help.ovhcloud.com/csm/fr-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062602', + GB: + 'https://help.ovhcloud.com/csm/en-gb-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062557', + CA: + 'https://help.ovhcloud.com/csm/en-ca-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062603', + QC: + 'https://help.ovhcloud.com/csm/fr-ca-vmware-vcd-faq?id=kb_article_view&sysparm_article=KB0062601', + US: + 'https://support.us.ovhcloud.com/hc/en-us/articles/28329887272467-VMware-Cloud-Director-FAQ', + }, +}; + +type GetGuideLinkProps = { + name?: string; + subsidiary: CountryCode | string; +}; + +function getGuideListLink({ subsidiary }: GetGuideLinkProps) { + const list: { [guideName: string]: string } = {}; + const keys = Object.entries(GUIDE_LIST); + keys.forEach((key) => { + list[key[0]] = + GUIDE_LIST[key[0]][subsidiary as CountryCode] ?? + GUIDE_LIST[key[0]][CountryCode.GB]; + }); + return list; +} + +interface GuideLinkProps { + [guideName: string]: string; +} + +function useGuideUtils() { + const { shell } = useContext(ShellContext); + const { environment } = shell; + const [list, setList] = useState({}); + + useEffect(() => { + const getSubSidiary = async () => { + const env = await environment.getEnvironment(); + const { ovhSubsidiary } = env.getUser(); + const guideList = getGuideListLink({ subsidiary: ovhSubsidiary }); + setList(guideList); + }; + getSubSidiary(); + }, []); + return list as GuideLinkProps; +} + +export default useGuideUtils; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/user/useCurrentUser.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/user/useCurrentUser.ts new file mode 100644 index 000000000000..095ab4356d26 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/hooks/user/useCurrentUser.ts @@ -0,0 +1,32 @@ +import { User } from '@ovh-ux/manager-config'; +import { ShellContext } from '@ovh-ux/manager-react-shell-client'; +import { useContext, useEffect, useState } from 'react'; + +type TCurrentUserData = { + user: User; + dateTimeFormat: Intl.DateTimeFormat; +}; + +const useCurrentUser = () => { + const { environment } = useContext(ShellContext); + + const [currentUserData, setCurrentUserData] = useState({ + user: null, + dateTimeFormat: null, + }); + + useEffect(() => { + const user = environment.getUser(); + const dateTimeFormat = new Intl.DateTimeFormat( + environment.getUserLocale().replace('_', '-'), + { + dateStyle: 'medium', + }, + ); + setCurrentUserData({ user, dateTimeFormat }); + }, [environment]); + + return currentUserData; +}; + +export default useCurrentUser; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/hpc-vmware-managed-vcd.config.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/hpc-vmware-managed-vcd.config.ts new file mode 100644 index 000000000000..d480bea061ad --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/hpc-vmware-managed-vcd.config.ts @@ -0,0 +1,8 @@ +export default { + listing: { + datagrid: { + serviceKey: 'id', + }, + }, + rootLabel: 'Managed VCD', +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/index.scss b/packages/manager/apps/hpc-vmware-managed-vcd/src/index.scss new file mode 100644 index 000000000000..65dd5f63a7df --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/index.scss @@ -0,0 +1 @@ +@tailwind utilities; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/index.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/index.tsx new file mode 100644 index 000000000000..7a2d7b569719 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/index.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { + ShellContext, + initShellContext, + initI18n, +} from '@ovh-ux/manager-react-shell-client'; +import App from './App'; +import '@ovhcloud/ods-theme-blue-jeans/dist/index.css'; +import './index.scss'; +import './vite-hmr'; + +import { UNIVERSE, SUB_UNIVERSE, APP_NAME, LEVEL2 } from './tracking.constant'; + +const trackingContext = { + chapter1: UNIVERSE, + chapter2: SUB_UNIVERSE, + chapter3: APP_NAME, + appName: APP_NAME, + pageTheme: UNIVERSE, + level2Config: LEVEL2, +}; + +const init = async (appName: string) => { + const context = await initShellContext(appName, trackingContext); + + await initI18n({ + context, + reloadOnLocaleChange: true, + defaultNS: appName, + ns: ['listing', 'dashboard', 'onboarding'], + }); + + const region = context.environment.getRegion(); + context.shell.tracking.setConfig(region, LEVEL2); + try { + await import(`./config-${region}.js`); + } catch (error) { + // nothing to do + } + + ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + , + ); +}; + +init('hpc-vmware-managed-vcd'); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/404.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/404.tsx new file mode 100644 index 000000000000..d052f1ebcbbf --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/404.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +export default function NotFound() { + // @TODO: add a redirection here in order to catch /:serviceName given from iframe + + return

404 - route not found

; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.constant.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.constant.ts new file mode 100644 index 000000000000..2ff0183ba413 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.constant.ts @@ -0,0 +1,2 @@ +export const COMPUTE_TITLE = 'Compute'; +export const STORAGE_TITLE = 'Storage'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.page.tsx new file mode 100644 index 000000000000..33687d51b868 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/DatacentreDashboard.page.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { useNavigate, useParams, useResolvedPath } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb'; +import VcdDashboardLayout from '@/components/dashboard/layout/VcdDashboardLayout.component'; +import { useManagedVcdDatacentre } from '@/data/hooks/useManagedVcdDatacentres'; +import useManagedVcdOrganization from '@/data/hooks/useManagedVcdOrganization'; +import { COMPUTE_TITLE, STORAGE_TITLE } from './DatacentreDashboard.constant'; +import { subRoutes, urls } from '@/routes/routes.constant'; +import { useAutoRefetch } from '@/data/hooks/useAutoRefetch'; +import { isUpdatingTargetSpec } from '@/utils/refetchConditions'; +import { getVcdDatacentresQueryKey } from '@/utils/queryKeys'; + +function DatacentreDashboardPage() { + const { id, vdcId } = useParams(); + const { t } = useTranslation('dashboard'); + const { data: vcdDatacentre } = useManagedVcdDatacentre(id, vdcId); + const { data: vcdOrganization } = useManagedVcdOrganization({ id }); + const navigate = useNavigate(); + useAutoRefetch({ + queryKey: getVcdDatacentresQueryKey(id), + enabled: isUpdatingTargetSpec(vcdDatacentre?.data), + interval: 4000, + }); + + const tabsList = [ + { + name: 'general_information', + title: t('managed_vcd_dashboard_general_information'), + to: useResolvedPath('').pathname, + }, + { + name: 'compute', + title: COMPUTE_TITLE, + to: useResolvedPath('compute').pathname, + }, + { + name: 'storage', + title: STORAGE_TITLE, + to: useResolvedPath('storage').pathname, + }, + ]; + + const serviceName = vcdDatacentre?.data?.currentState?.description ?? vdcId; + const hasServiceRenamed = vdcId !== serviceName; + + const header = hasServiceRenamed + ? { + description: vdcId, + title: serviceName, + } + : { title: vdcId }; + + const breadcrumbItems: BreadcrumbItem[] = [ + { + id, + label: vcdOrganization?.data?.currentState?.fullName, + }, + { + id: 'datacentres', + label: t('managed_vcd_dashboard_datacentres_label'), + }, + { + id: vdcId, + label: serviceName, + }, + ]; + + return ( + + navigate(urls.datacentres.replace(subRoutes.dashboard, id)) + } + /> + ); +} + +export default DatacentreDashboardPage; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.constants.ts new file mode 100644 index 000000000000..1619e3fd63a0 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.constants.ts @@ -0,0 +1,2 @@ +export const COMPUTE_ORDER_MIN_QUANTITY = 1; +export const COMPUTE_ORDER_MAX_QUANTITY = 20; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.page.tsx new file mode 100644 index 000000000000..a49f82bcbe33 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.page.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { DatagridColumn } from '@ovh-ux/manager-react-components'; +import { DatacentreOrderProvider } from '@/context/DatacentreOrder.context'; +import { IVdcOrderableVhostPriced } from '@/types/vcd-vdc-orderable-resource.interface'; +import { DatacentreOrder } from '@/components/form/DatacentreOrder.component'; +import { + ComputeOrderSelectCell, + ComputeOrderVhostCell, + ComputeOrderCpuSpeedCell, + ComputeOrderRamCell, + ComputeOrderCpuCountCell, + ComputeOrderPriceCell, +} from '@/components/datagrid/compute/ComputeOrderCells.component'; +import { + COMPUTE_ORDER_MAX_QUANTITY, + COMPUTE_ORDER_MIN_QUANTITY, +} from './DatacentreComputeOrder.constants'; +import { subRoutes } from '@/routes/routes.constant'; + +export default function ComputeOrderPage() { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/order'); + const { t: tCompute } = useTranslation( + 'hpc-vmware-managed-vcd/datacentres/compute', + ); + const columns: DatagridColumn[] = [ + { + id: 'select', + cell: ComputeOrderSelectCell, + label: '', + isSortable: false, + }, + { + id: 'vhost', + cell: ComputeOrderVhostCell, + label: t('managed_vcd_vdc_order_vhost'), + isSortable: false, + }, + { + id: 'cpuSpeed', + cell: ComputeOrderCpuSpeedCell, + label: t('managed_vcd_vdc_order_cpu_speed'), + isSortable: false, + }, + { + id: 'ram', + cell: ComputeOrderRamCell, + label: t('managed_vcd_vdc_order_ram'), + isSortable: false, + }, + { + id: 'cpuCount', + cell: ComputeOrderCpuCountCell, + label: t('managed_vcd_vdc_order_vcpu_count'), + isSortable: false, + }, + { + id: 'price', + cell: ComputeOrderPriceCell, + label: t('managed_vcd_vdc_order_price'), + }, + ]; + + return ( + + + + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.constants.ts new file mode 100644 index 000000000000..0b3bd61e466e --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.constants.ts @@ -0,0 +1 @@ +export const VHOSTS_TITLE = 'Virtual Hosts'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.page.tsx new file mode 100644 index 000000000000..83e34db61f45 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/compute/DatacentreCompute.page.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { OsdsButton } from '@ovhcloud/ods-components/react'; +import { ODS_BUTTON_SIZE, ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { VHOSTS_TITLE } from './DatacentreCompute.constants'; +import DatagridContainer from '@/components/datagrid/container/DatagridContainer.component'; +import IVcdCompute from '@/types/vcd-compute.interface'; +import { getVcdDatacentreComputeRoute } from '@/data/api/hpc-vmware-managed-vcd-datacentre'; +import { subRoutes, urls } from '@/routes/routes.constant'; +import { getVdcComputeQueryKey } from '@/utils/queryKeys'; + +const DatagridIdCell = (vcdCompute: IVcdCompute) => ( + {vcdCompute?.id} +); +const DatagridVHostProfilCell = (vcdCompute: IVcdCompute) => ( + {vcdCompute?.currentState?.profile} +); + +const DatagridCpuCountCell = (vcdCompute: IVcdCompute) => ( + {vcdCompute.currentState?.vCPUCount} +); +const DatagridBillingCell = (vcdCompute: IVcdCompute) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/compute'); + return ( + + {t( + `managed_vcd_vdc_compute_billing_${vcdCompute.currentState?.billingType}`, + )} + + ); +}; + +const DatagridRamCountCell = (vcdCompute: IVcdCompute) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + + return ( + + {t('managed_vcd_vdc_quota_value', { + quota: vcdCompute.currentState?.memoryQuota, + })} + + ); +}; + +export default function ComputeListingPage() { + const { id, vdcId } = useParams(); + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/compute'); + const { t: tVdc } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + const navigate = useNavigate(); + + const columns = [ + { + id: 'id', + cell: DatagridIdCell, + label: t('managed_vcd_vdc_compute_id'), + isSortable: false, + }, + { + id: 'vHostProfile', + cell: DatagridVHostProfilCell, + label: t('managed_vcd_vdc_compute_vhost_profile'), + isSortable: false, + }, + { + id: 'cpuCount', + cell: DatagridCpuCountCell, + label: tVdc('managed_vcd_vdc_vcpu_count'), + isSortable: false, + }, + { + id: 'ramCount', + cell: DatagridRamCountCell, + label: tVdc('managed_vcd_vdc_ram_count'), + isSortable: false, + }, + { + id: 'billing', + cell: DatagridBillingCell, + label: t('managed_vcd_vdc_compute_billing'), + isSortable: false, + }, + ]; + + return ( + navigate(subRoutes.order)} + > + {t('managed_vcd_vdc_compute_order_cta')} + + } + /> + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/DatacentreGeneralInformation.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/DatacentreGeneralInformation.page.tsx new file mode 100644 index 000000000000..6b019d6829ee --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/DatacentreGeneralInformation.page.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { Outlet, useParams } from 'react-router-dom'; +import DatacentreGenerationInformationTile from '@/components/tiles/datacentre-general-information-tile/DatacentreGeneralInformationTile.component'; +import useManagedVcdOrganization from '@/data/hooks/useManagedVcdOrganization'; +import { useManagedVcdDatacentre } from '@/data/hooks/useManagedVcdDatacentres'; +import Loading from '@/components/loading/Loading.component'; + +export default function DatacentresGeneralInformationPage() { + const { id, vdcId } = useParams(); + const { data: vcdOrganization, isLoading } = useManagedVcdOrganization({ + id, + }); + const { + data: vcdDatacentre, + isLoading: isLoadingVdc, + } = useManagedVcdDatacentre(id, vdcId); + + if (isLoading || isLoadingVdc) { + return ( +
+ +
+ ); + } + + return ( + }> +
+ + +
+
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/edit/EditVdcDescription.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/edit/EditVdcDescription.page.tsx new file mode 100644 index 000000000000..f1a618d9c607 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/general-informations/edit/EditVdcDescription.page.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { useManagedVcdDatacentre } from '@/data/hooks/useManagedVcdDatacentres'; +import { useUpdateVdcDetails } from '@/data/hooks/useUpdateVcdDatacentre'; +import { validateDescription } from '@/utils/formValidation'; +import { IVcdDatacentreState } from '@/types/vcd-datacenter.interface'; +import { EditDetailModal } from '@/components/modal/EditDetailModal'; + +export default function EditVdcDescription() { + const { t } = useTranslation('dashboard'); + const navigate = useNavigate(); + const closeModal = () => navigate('..'); + const { addSuccess } = useNotifications(); + const { id, vdcId } = useParams(); + const { data: vcdDatacentre } = useManagedVcdDatacentre(id, vdcId); + const { updateDetails, error, isError } = useUpdateVdcDetails({ + id, + vdcId, + onSuccess: () => { + addSuccess( + t('managed_vcd_dashboard_edit_description_modal_success'), + true, + ); + closeModal(); + }, + }); + + const currentVdcDetails: IVcdDatacentreState = vcdDatacentre.data.targetSpec; + + return ( + + updateDetails({ + id, + vdcId, + details: { ...currentVdcDetails, description }, + }) + } + error={isError ? error : null} + /> + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.constants.ts new file mode 100644 index 000000000000..fdcfb737c473 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.constants.ts @@ -0,0 +1,2 @@ +export const STORAGE_ORDER_MIN_QUANTITY = 1; +export const STORAGE_ORDER_MAX_QUANTITY = 50; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.page.tsx new file mode 100644 index 000000000000..c68a7a7e1967 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.page.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { DatagridColumn } from '@ovh-ux/manager-react-components'; +import { DatacentreOrderProvider } from '@/context/DatacentreOrder.context'; +import { IVdcOrderableStoragePriced } from '@/types/vcd-vdc-orderable-resource.interface'; +import { DatacentreOrder } from '@/components/form/DatacentreOrder.component'; +import { + StorageOrderPriceCell, + StorageOrderSelectCell, + StorageOrderTypeCell, +} from '@/components/datagrid/storage/StorageOrderCells.component'; +import { + STORAGE_ORDER_MAX_QUANTITY, + STORAGE_ORDER_MIN_QUANTITY, +} from './DatacentreStorageOrder.constants'; +import { subRoutes } from '@/routes/routes.constant'; + +export default function StorageOrderPage() { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/order'); + + const columns: DatagridColumn[] = [ + { + id: 'select', + cell: StorageOrderSelectCell, + label: '', + isSortable: false, + }, + { + id: 'storage', + cell: StorageOrderTypeCell, + label: t('managed_vcd_vdc_order_type'), + isSortable: false, + }, + { + id: 'price', + cell: StorageOrderPriceCell, + label: t('managed_vcd_vdc_order_price'), + isSortable: false, + }, + ]; + + return ( + + + + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage/DatacentreStorage.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage/DatacentreStorage.page.tsx new file mode 100644 index 000000000000..98ebbbfebe12 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/datacentre/storage/DatacentreStorage.page.tsx @@ -0,0 +1,123 @@ +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import React from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { OsdsButton } from '@ovhcloud/ods-components/react'; +import { ODS_BUTTON_SIZE, ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import IVcdStorage from '@/types/vcd-storage.interface'; +import DatagridContainer from '@/components/datagrid/container/DatagridContainer.component'; +import { STORAGE_TITLE } from '../DatacentreDashboard.constant'; +import { getVcdDatacentreStorageRoute } from '@/data/api/hpc-vmware-managed-vcd-datacentre'; +import { subRoutes, urls } from '@/routes/routes.constant'; +import { getVdcStorageQueryKey } from '@/utils/queryKeys'; +import { capitalize } from '@/utils/capitalize'; + +const DatagridIdCell = (vcdStorage: IVcdStorage) => ( + {vcdStorage?.id} +); +const DatagridNameCell = (vcdStorage: IVcdStorage) => ( + {vcdStorage?.currentState?.name} +); +const DatagridProfileCell = (vcdStorage: IVcdStorage) => ( + {vcdStorage?.currentState?.profile} +); +const DatagridTypeCell = (vcdStorage: IVcdStorage) => ( + + {capitalize(vcdStorage?.currentState?.type)} + +); +const DatagridCapacityCell = (vcdStorage: IVcdStorage) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + return ( + + {t('managed_vcd_vdc_quota_value', { + quota: vcdStorage?.currentState.capacity, + })} + + ); +}; +const DatagridBillingCell = (vcdStorage: IVcdStorage) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/compute'); + return ( + + {t( + `managed_vcd_vdc_compute_billing_${vcdStorage?.currentState?.billingType}`, + )} + + ); +}; + +export default function StorageListingPage() { + const { id, vdcId } = useParams(); + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres/storage'); + const { t: tVdc } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + const { t: tCompute } = useTranslation( + 'hpc-vmware-managed-vcd/datacentres/compute', + ); + const navigate = useNavigate(); + + const columns = [ + { + id: 'id', + cell: DatagridIdCell, + label: tVdc('managed_vcd_vdc_id'), + isSortable: false, + }, + { + id: 'name', + cell: DatagridNameCell, + label: t('managed_vcd_vdc_storage_name'), + isSortable: false, + }, + { + id: 'profile', + cell: DatagridProfileCell, + label: t('managed_vcd_vdc_storage_profile'), + isSortable: false, + }, + { + id: 'type', + cell: DatagridTypeCell, + label: t('managed_vcd_vdc_storage_type'), + isSortable: false, + }, + { + id: 'capacity', + cell: DatagridCapacityCell, + label: t('managed_vcd_vdc_storage_capacity'), + isSortable: false, + }, + { + id: 'billing', + cell: DatagridBillingCell, + label: tCompute('managed_vcd_vdc_compute_billing'), + isSortable: false, + }, + ]; + + return ( + navigate(subRoutes.order)} + > + {t('managed_vcd_vdc_storage_order_cta')} + + } + /> + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.constants.ts new file mode 100644 index 000000000000..c6d4b02d83a3 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.constants.ts @@ -0,0 +1,3 @@ +export const DATA_PROTECTION_BACKUP_TITLE = 'Managed Backup'; +export const DATA_PROTECTION_RECOVERY_TITLE = + 'Managed Disaster Recovery Services'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.page.tsx new file mode 100644 index 000000000000..f0cafe3cb654 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.page.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams, useResolvedPath } from 'react-router-dom'; + +import VcdDashboardLayout from '@/components/dashboard/layout/VcdDashboardLayout.component'; +import useManagedVcdOrganization from '@/data/hooks/useManagedVcdOrganization'; +import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb'; +import { urls } from '@/routes/routes.constant'; + +export default function DashboardPage() { + const { id } = useParams(); + const { t } = useTranslation('dashboard'); + const { data: vcdOrganisation } = useManagedVcdOrganization({ id }); + const navigate = useNavigate(); + + const tabsList = [ + { + name: 'general_information', + title: t('managed_vcd_dashboard_general_information'), + to: useResolvedPath('').pathname, + }, + { + name: 'datacentres', + title: t('managed_vcd_dashboard_datacentres_title'), + to: useResolvedPath('datacentres').pathname, + }, + ]; + + const serviceName = vcdOrganisation?.data?.currentState?.fullName; + const hasServiceRenamed = id !== serviceName; + + const header = hasServiceRenamed + ? { + description: id, + title: serviceName, + } + : { title: id }; + + const breadcrumbItems: BreadcrumbItem[] = [ + { + id, + label: serviceName, + }, + ]; + + return ( + navigate(urls.listing)} + /> + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.spec.tsx new file mode 100644 index 000000000000..1b8937e08a26 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/OrganizationDashboard.spec.tsx @@ -0,0 +1,37 @@ +import userEvents from '@testing-library/user-event'; +import { screen, waitFor } from '@testing-library/react'; +import { renderTest, labels } from '../../../test-utils'; +import { organizationList } from '../../../../mocks/vcd-organization/vcd-organization.mock'; + +describe('Organization Dashboard Page', () => { + it('display the dashboard page', async () => { + await renderTest(); + const link = screen.getByText(organizationList[0].currentState.fullName); + await waitFor(() => userEvents.click(link)); + + await waitFor( + () => + expect( + screen.getByText( + labels.dashboard.managed_vcd_dashboard_data_protection, + ), + ).toBeVisible(), + { timeout: 30000 }, + ); + + expect( + screen.getByText(organizationList[0].currentState.description), + ).toBeVisible(); + }); + + it('display an error', async () => { + await renderTest({ + initialRoute: `/${organizationList[0].id}`, + isOrganizationKo: true, + }); + await waitFor( + () => expect(screen.getByText('Organization error')).toBeVisible(), + { timeout: 30000 }, + ); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.page.tsx new file mode 100644 index 000000000000..cbceeb0cabb0 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.page.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { Outlet, useParams } from 'react-router-dom'; +import Errors from '@/components/error/Error.component'; +import Loading from '@/components/loading/Loading.component'; +import BillingTile from '@/components/tiles/billing-tile/BillingTile.component'; +import OrganizationGenerationInformationTile from '@/components/tiles/organization-general-information-tile/OrganizationGeneralInformationTile.component'; +import OrganizationOptionsTile from '@/components/tiles/organization-options-tile/OrganizationOptionsTile.component'; +import useManagedVcdOrganization from '@/data/hooks/useManagedVcdOrganization'; +import DataProtectionTile from '@/components/tiles/organization-data-tile/OrganizationDataProtectionTile.component'; + +function GeneralInformation() { + const { id } = useParams(); + const { + data: vcdOrganization, + isError, + isRefetchError, + error, + isLoading, + } = useManagedVcdOrganization({ + id, + refetchOnWindowFocus: true, + refetchInterval: 60 * 1000, + }); + + if (isError || isRefetchError) { + return ; + } + + if (isLoading) { + return ( +
+ +
+ ); + } + + return ( +
+ +
+ + +
+
+ +
+ +
+ ); +} + +export default GeneralInformation; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.spec.tsx new file mode 100644 index 000000000000..1f99d56cac88 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/OrganizationGeneralInformation.spec.tsx @@ -0,0 +1,159 @@ +import userEvents from '@testing-library/user-event'; +import { screen, waitFor, fireEvent, within } from '@testing-library/react'; +import { renderTest, labels } from '../../../../test-utils'; +import { organizationList } from '../../../../../mocks/vcd-organization/vcd-organization.mock'; + +const changeInputAndSubmit = async () => { + const input = screen.getByLabelText('edit-input'); + const event = new CustomEvent('odsValueChange'); + Object.defineProperty(event, 'target', { value: { value: 'new name' } }); + await waitFor(() => fireEvent(input, event)); + + const modifyButton = screen.getByText( + labels.dashboard.managed_vcd_dashboard_edit_modal_cta_edit, + { exact: true }, + ); + + return waitFor(() => userEvents.click(modifyButton)); +}; + +const checkModal = async ({ + container, + isVisible, +}: { + container: HTMLElement; + isVisible: boolean; +}) => + waitFor( + () => { + const modal = container.querySelector('osds-modal'); + return isVisible + ? expect(modal).toBeInTheDocument() + : expect(modal).not.toBeInTheDocument(); + }, + { timeout: 30000 }, + ); + +describe('Organization General Information Page', () => { + it('modify the name of the company', async () => { + const { container } = await renderTest({ + initialRoute: `/${organizationList[1].id}`, + }); + + await waitFor( + () => + expect( + screen.getByText( + labels.dashboard.managed_vcd_dashboard_data_protection, + ), + ).toBeVisible(), + { timeout: 30000 }, + ); + + let editButton; + await waitFor( + () => { + editButton = screen.getAllByTestId('editIcon').at(0); + return expect(editButton).not.toHaveAttribute('disabled'); + }, + { timeout: 30000 }, + ); + await waitFor(() => userEvents.click(editButton)); + + await checkModal({ container, isVisible: true }); + + await changeInputAndSubmit(); + + await checkModal({ container, isVisible: false }); + + expect( + screen.queryByText( + labels.dashboard.managed_vcd_dashboard_edit_name_modal_success, + ), + ).toBeVisible(); + }); + + it('trying to update name displays an error if update organization service is KO', async () => { + const { container } = await renderTest({ + initialRoute: `/${organizationList[0].id}/edit-name`, + isOrganizationUpdateKo: true, + }); + + await checkModal({ container, isVisible: true }); + + await changeInputAndSubmit(); + + await checkModal({ container, isVisible: true }); + + await waitFor( + () => + expect( + within( + container.querySelector('osds-modal') as HTMLElement, + ).getByText('Organization update error', { exact: false }), + ).toBeVisible(), + { timeout: 30000 }, + ); + }); + + it('modify the description of the company', async () => { + const { container } = await renderTest({ + initialRoute: `/${organizationList[1].id}`, + }); + + await waitFor( + () => + expect( + screen.getByText( + labels.dashboard.managed_vcd_dashboard_data_protection, + ), + ).toBeVisible(), + { timeout: 30000 }, + ); + + let editButton; + await waitFor( + () => { + editButton = screen.getAllByTestId('editIcon').at(1); + return expect(editButton).not.toHaveAttribute('disabled'); + }, + { timeout: 30000 }, + ); + await waitFor(() => userEvents.click(editButton)); + + await checkModal({ container, isVisible: true }); + + await changeInputAndSubmit(); + + await checkModal({ container, isVisible: false }); + + expect( + screen.queryByText( + labels.dashboard.managed_vcd_dashboard_edit_description_modal_success, + ), + ).toBeVisible(); + }); + + it('trying to update description displays an error if update organization service is KO', async () => { + const { container } = await renderTest({ + initialRoute: `/${organizationList[0].id}/edit-description`, + isOrganizationUpdateKo: true, + }); + + await checkModal({ container, isVisible: true }); + + await changeInputAndSubmit(); + + await checkModal({ container, isVisible: true }); + + await waitFor( + () => + expect( + within( + container.querySelector('osds-modal') as HTMLElement, + ).getByText('Organization update error', { exact: false }), + ).toBeVisible(), + { timeout: 30000 }, + ); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditDescription.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditDescription.page.tsx new file mode 100644 index 000000000000..1c2754ac9f8c --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditDescription.page.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { UpdateDetailModalHandler } from '@/components/modal/UpdateDetailModalHandler'; + +export default function EditDescription() { + return ; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditName.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditName.page.tsx new file mode 100644 index 000000000000..05d7103a5874 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/dashboard/organization/general-information/edit/EditName.page.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { UpdateDetailModalHandler } from '@/components/modal/UpdateDetailModalHandler'; + +export default function EditName() { + return ; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/layout.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/layout.tsx new file mode 100644 index 000000000000..d928957e896d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/layout.tsx @@ -0,0 +1,31 @@ +import React, { useEffect, useContext } from 'react'; +import { defineCurrentPage } from '@ovh-ux/request-tagger'; +import { Outlet, useLocation, useMatches } from 'react-router-dom'; +import { + useOvhTracking, + useRouteSynchro, + ShellContext, +} from '@ovh-ux/manager-react-shell-client'; + +export default function Layout() { + const location = useLocation(); + const { shell } = useContext(ShellContext); + const matches = useMatches(); + const { trackCurrentPage } = useOvhTracking(); + useRouteSynchro(); + + useEffect(() => { + const match = matches.slice(-1); + defineCurrentPage(`app.hpc-vmware-managed-vcd-${match[0]?.id}`); + }, [location]); + + useEffect(() => { + trackCurrentPage(); + }, [location]); + + useEffect(() => { + shell.ux.hidePreloader(); + }, []); + + return ; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/datacentres/datacentres.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/datacentres/datacentres.page.tsx new file mode 100644 index 000000000000..fe2f8bb62a9d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/datacentres/datacentres.page.tsx @@ -0,0 +1,124 @@ +import { DataGridTextCell, Links } from '@ovh-ux/manager-react-components'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import DatagridContainer, { + TDatagridContainerProps, +} from '@/components/datagrid/container/DatagridContainer.component'; +import { subRoutes, urls } from '@/routes/routes.constant'; +import IVcdDatacentre from '@/types/vcd-datacenter.interface'; +import { getVcdDatacentresRoute } from '@/data/api/hpc-vmware-managed-vcd-datacentre'; +import { getVcdDatacentresQueryKey } from '@/utils/queryKeys'; +import { capitalize } from '@/utils/capitalize'; + +/* ========= datagrid cells ========= */ +const DatagridIdCell = (vcdDatacentre: IVcdDatacentre) => { + const navigate = useNavigate(); + const { id } = useParams(); + + return ( + + + navigate( + urls.datacentreDashboard + .replace(subRoutes.dashboard, id) + .replace(subRoutes.vdcId, vcdDatacentre.id), + ) + } + label={vcdDatacentre.currentState.name} + > + + ); +}; + +const DatagridDescriptionCell = (vcdDatacentre: IVcdDatacentre) => ( + {vcdDatacentre.currentState?.description} +); + +const DatagridCpuCountCell = (vcdDatacentre: IVcdDatacentre) => ( + {vcdDatacentre.currentState?.vCPUCount} +); + +const DatagridCpuSpeedCell = (vcdDatacentre: IVcdDatacentre) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + + return ( + + {t('managed_vcd_vdc_vcpu_value', { + speed: vcdDatacentre.currentState?.vCPUSpeed, + })} + + ); +}; + +const DatagridRamCountCell = (vcdDatacentre: IVcdDatacentre) => { + const { t } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + + return ( + + {t('managed_vcd_vdc_quota_value', { + quota: vcdDatacentre.currentState?.memoryQuota, + })} + + ); +}; + +const DatagridCommercialRange = (vcdDatacentre: IVcdDatacentre) => ( + + {capitalize(vcdDatacentre.currentState?.commercialRange)} + +); + +/* ======= listing page ======== */ +export default function DatacentresListing() { + const { t } = useTranslation('listing'); + const { t: tVdc } = useTranslation('hpc-vmware-managed-vcd/datacentres'); + const { id } = useParams(); + + const columns = [ + { + id: 'id', + cell: DatagridIdCell, + label: t('managed_vcd_listing_id'), + }, + { + id: 'description', + cell: DatagridDescriptionCell, + label: t('managed_vcd_listing_description'), + }, + { + id: 'commercialRange', + cell: DatagridCommercialRange, + label: tVdc('managed_vcd_vdc_commercial_range'), + }, + { + id: 'cpuCount', + cell: DatagridCpuCountCell, + label: tVdc('managed_vcd_vdc_vcpu_count'), + }, + { + id: 'ramCount', + cell: DatagridRamCountCell, + label: tVdc('managed_vcd_vdc_ram_count'), + }, + { + id: 'vCpuSpeed', + cell: DatagridCpuSpeedCell, + label: tVdc('managed_vcd_vdc_vcpu_speed'), + }, + ]; + + const datagridProps: TDatagridContainerProps = { + title: tVdc('managed_vcd_vdc_title'), + queryKey: getVcdDatacentresQueryKey(id), + isEmbedded: true, + route: { + api: getVcdDatacentresRoute(id), + onboarding: urls.onboarding, + }, + columns, + }; + + return ; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.page.tsx new file mode 100644 index 000000000000..b163ca53ff90 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.page.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; + +import { + DataGridTextCell, + Links, + LinkType, + Region, +} from '@ovh-ux/manager-react-components'; +import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core'; + +import DatagridContainer from '@/components/datagrid/container/DatagridContainer.component'; +import { urls } from '@/routes/routes.constant'; +import IVcdOrganization from '@/types/vcd-organization.interface'; +import { VCD_ORGANIZATION_ROUTE } from '@/data/api/hpc-vmware-managed-vcd.constants'; +import { getVcdOrganizationsQueryKey } from '@/utils/queryKeys'; + +/* ========= datagrid cells ========== */ +const DatagridIdCell = (vdcOrg: IVcdOrganization) => { + const navigate = useNavigate(); + return ( + + navigate(`/${vdcOrg.id}`)} + label={vdcOrg.currentState?.fullName} + > + + ); +}; + +const DatagridRegionCell = (vdcOrg: IVcdOrganization) => ( + + + +); + +const DatagridDescriptionCell = (vdcOrg: IVcdOrganization) => ( + {vdcOrg.currentState?.description} +); + +const DatagridWebInterfaceCell = (vdcOrg: IVcdOrganization) => ( + + + +); + +/* ======= listing page ======= */ +export default function Listing() { + const { t } = useTranslation('listing'); + + const columns = [ + { + id: 'name', + cell: DatagridIdCell, + label: t('managed_vcd_listing_name'), + }, + { + id: 'location', + cell: DatagridRegionCell, + label: t('managed_vcd_listing_location'), + }, + { + id: 'description', + cell: DatagridDescriptionCell, + label: t('managed_vcd_listing_description'), + }, + { + id: 'webInterfaceURL', + cell: DatagridWebInterfaceCell, + label: t('managed_vcd_listing_web_interface_url'), + }, + ]; + + return ( + + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.spec.tsx new file mode 100644 index 000000000000..1b9eabbdbb84 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/listing/organizations/Organizations.spec.tsx @@ -0,0 +1,21 @@ +import { screen, waitFor } from '@testing-library/react'; +import { renderTest, labels } from '../../../test-utils'; +import { organizationList } from '../../../../mocks/vcd-organization/vcd-organization.mock'; + +describe('Organizations Listing Page', () => { + it('display the listing page if there is at least one organization', async () => { + await renderTest({ nbOrganization: 1 }); + + await waitFor(() => + expect( + screen.getByText(labels.listing.managed_vcd_listing_description), + ).toBeVisible(), + ); + + await waitFor(() => + expect( + screen.getByText(organizationList[0].currentState.fullName), + ).toBeVisible(), + ); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.page.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.page.tsx new file mode 100644 index 000000000000..1801f27f92ea --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.page.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Card, OnboardingLayout } from '@ovh-ux/manager-react-components'; +import useGuideUtils from '@/hooks/guide/useGuideUtils'; +import vmwareBroadcomOVHCloud from '@/assets/VmwareBroadcomxOVHcloud.svg'; + +export default function Onboarding() { + const { t } = useTranslation('onboarding'); + const link = useGuideUtils(); + + const tileList = [ + { + id: 1, + texts: { + title: t('managed_vcd_onboarding_guide1_title'), + description: t('managed_vcd_onboarding_guide1_description'), + category: t('managed_vcd_onboarding_guide1_category').toUpperCase(), + }, + href: link?.guideLink1, + hrefLabel: t('managed_vcd_onboarding_guide1_link'), + }, + { + id: 2, + texts: { + title: t('managed_vcd_onboarding_guide2_title'), + description: t('managed_vcd_onboarding_guide2_description'), + category: t('managed_vcd_onboarding_guide2_category').toUpperCase(), + }, + href: link?.guideLink2, + hrefLabel: t('managed_vcd_onboarding_guide2_link'), + }, + { + id: 3, + texts: { + title: t('managed_vcd_onboarding_guide3_title'), + description: t('managed_vcd_onboarding_guide3_description'), + category: t('managed_vcd_onboarding_guide3_category').toUpperCase(), + }, + href: link?.guideLink3, + hrefLabel: t('managed_vcd_onboarding_guide3_link'), + }, + ]; + + const description: React.ReactNode = ( + <> +

{t('managed_vcd_onboarding_description_part1')}

+ {t('managed_vcd_onboarding_description_part2')} + + ); + const imgSrc = { + src: vmwareBroadcomOVHCloud, + }; + + return ( +
+ + {tileList.map((tile) => ( + + ))} + +
+ ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.spec.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.spec.tsx new file mode 100644 index 000000000000..74612cb296ea --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/pages/onboarding/Onboarding.spec.tsx @@ -0,0 +1,15 @@ +import { screen, waitFor } from '@testing-library/react'; +import { renderTest, labels } from '../../test-utils'; + +describe('Onboarding Page', () => { + it('display the onboarding page if there is no VCD Organization', async () => { + await renderTest({ nbOrganization: 0 }); + await waitFor(() => + expect( + screen.getByText( + labels.onboarding.managed_vcd_onboarding_description_part1, + ), + ).toBeVisible(), + ); + }); +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.constant.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.constant.ts new file mode 100644 index 000000000000..1eb746e97450 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.constant.ts @@ -0,0 +1,29 @@ +export const subRoutes = { + onboarding: 'onboarding', + dashboard: ':id', + order: 'order', + editName: 'edit-name', + editDescription: 'edit-description', + vdcId: ':vdcId', + datacentres: 'datacentres', + datacentreStorage: 'storage', + datacentreCompute: 'compute', +}; + +export const urls = { + root: '/', + listing: '/', + onboarding: `/${subRoutes.onboarding}`, + dashboard: `/${subRoutes.dashboard}`, + editName: `/${subRoutes.dashboard}/${subRoutes.editName}`, + editDescription: `/${subRoutes.dashboard}/${subRoutes.editDescription}`, + datacentres: `/${subRoutes.dashboard}/${subRoutes.datacentres}`, + datacentreDashboard: `/${subRoutes.dashboard}/${subRoutes.datacentres}/${subRoutes.vdcId}`, + datacentreEditDescription: `/${subRoutes.dashboard}/${subRoutes.datacentres}/${subRoutes.vdcId}/${subRoutes.editDescription}`, + datacentreStorage: `/${subRoutes.dashboard}/${subRoutes.datacentres}/${subRoutes.vdcId}/${subRoutes.datacentreStorage}`, + datacentreStorageOrder: `/${subRoutes.dashboard}/${subRoutes.datacentres}/${subRoutes.vdcId}/${subRoutes.datacentreStorage}/${subRoutes.order}`, + datacentreCompute: `/${subRoutes.dashboard}/${subRoutes.datacentres}/${subRoutes.vdcId}/${subRoutes.datacentreCompute}`, + datacentreComputeOrder: `/${subRoutes.dashboard}/${subRoutes.datacentres}/${subRoutes.vdcId}/${subRoutes.datacentreCompute}/${subRoutes.order}`, +}; + +export const veeamBackupAppName = 'veeam-backup'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.tsx new file mode 100644 index 000000000000..6513397f02e7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/routes/routes.tsx @@ -0,0 +1,228 @@ +import React from 'react'; +import { RouteObject } from 'react-router-dom'; +import { PageType } from '@ovh-ux/manager-react-shell-client'; +import NotFound from '@/pages/404'; +import { urls } from '@/routes/routes.constant'; + +const lazyRouteConfig = (importFn: CallableFunction): Partial => { + return { + lazy: async () => { + const { default: moduleDefault, ...moduleExports } = await importFn(); + return { + Component: moduleDefault, + ...moduleExports, + }; + }, + }; +}; + +export const Routes: any = [ + { + path: urls.root, + ...lazyRouteConfig(() => import('@/pages/layout')), + children: [ + { + id: 'listing', + path: urls.listing, + ...lazyRouteConfig(() => + import('@/pages/listing/organizations/Organizations.page'), + ), + handle: { + tracking: { + pageName: 'listing', + pageType: PageType.listing, + }, + }, + }, + { + path: urls.dashboard, + ...lazyRouteConfig(() => + import('@/pages/dashboard/organization/OrganizationDashboard.page'), + ), + children: [ + { + id: 'dashboard', + path: '', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/organization/general-information/OrganizationGeneralInformation.page' + ), + ), + handle: { + tracking: { + pageName: 'dashboard', + pageType: PageType.dashboard, + }, + }, + children: [ + { + id: 'edit-name', + path: urls.editName, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/organization/general-information/edit/EditName.page' + ), + ), + handle: { + tracking: { + pageName: 'edit-name', + pageType: PageType.popup, + }, + }, + }, + { + id: 'edit-description', + path: urls.editDescription, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/organization/general-information/edit/EditDescription.page' + ), + ), + handle: { + tracking: { + pageName: 'edit-description', + pageType: PageType.popup, + }, + }, + }, + ], + }, + { + id: 'datacentres', + path: urls.datacentres, + ...lazyRouteConfig(() => + import('@/pages/listing/datacentres/datacentres.page'), + ), + handle: { + tracking: { + pageName: 'datacentres', + pageType: PageType.listing, + }, + }, + }, + ], + }, + { + path: urls.datacentreDashboard, + ...lazyRouteConfig(() => + import('@/pages/dashboard/datacentre/DatacentreDashboard.page'), + ), + handle: { + tracking: { + pageName: 'datacentre', + pageType: PageType.dashboard, + }, + }, + children: [ + { + id: 'vDcDashboard', + path: '', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/datacentre/general-informations/DatacentreGeneralInformation.page' + ), + ), + handle: { + tracking: { + pageName: 'dashboard', + pageType: PageType.dashboard, + }, + }, + children: [ + { + id: 'vdc-edit-description', + path: urls.datacentreEditDescription, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/datacentre/general-informations/edit/EditVdcDescription.page' + ), + ), + handle: { + tracking: { + pageName: 'vdc-edit-description', + pageType: PageType.popup, + }, + }, + }, + ], + }, + { + id: 'vDcStorage', + path: urls.datacentreStorage, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/datacentre/storage/DatacentreStorage.page' + ), + ), + handle: { + tracking: { + pageName: 'dashboard', + pageType: PageType.listing, + }, + }, + }, + { + id: 'vDcStorage-order', + path: urls.datacentreStorageOrder, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/datacentre/storage-order/DatacentreStorageOrder.page' + ), + ), + handle: { + tracking: { + pageName: 'storage-order', + pageType: PageType.funnel, + }, + }, + }, + { + id: 'vDcCompute', + path: urls.datacentreCompute, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/datacentre/compute/DatacentreCompute.page' + ), + ), + handle: { + tracking: { + pageName: 'dashboard', + pageType: PageType.listing, + }, + }, + }, + { + id: 'vDcCompute-order', + path: urls.datacentreComputeOrder, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/datacentre/compute-order/DatacentreComputeOrder.page' + ), + ), + handle: { + tracking: { + pageName: 'compute-order', + pageType: PageType.funnel, + }, + }, + }, + ], + }, + { + id: 'onboarding', + path: urls.onboarding, + ...lazyRouteConfig(() => import('@/pages/onboarding/Onboarding.page')), + handle: { + tracking: { + pageName: 'onboarding', + pageType: PageType.onboarding, + }, + }, + }, + ], + }, + { + path: '*', + element: , + }, +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/TestApp.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/TestApp.tsx new file mode 100644 index 000000000000..f2fe8695cbc1 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/TestApp.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; +import { createMemoryRouter, RouterProvider } from 'react-router-dom'; +import { Routes } from '../routes/routes'; + +export function TestApp({ initialRoute = '/' }) { + const router = createMemoryRouter(Routes, { + initialEntries: [initialRoute], + initialIndex: 0, + }); + + const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false }, mutations: { retry: false } }, + }); + + return ( + + + + ); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/index.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/index.ts new file mode 100644 index 000000000000..0b72d348bfc9 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/index.ts @@ -0,0 +1,2 @@ +export { renderTest } from './render-test'; +export { labels } from './test-i18n'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/render-test.tsx b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/render-test.tsx new file mode 100644 index 000000000000..1d58a246af9f --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/render-test.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { SetupServer } from 'msw/node'; +import { i18n } from 'i18next'; +import { I18nextProvider } from 'react-i18next'; +import { expect } from 'vitest'; +import { + ShellContext, + ShellContextType, + initShellContext, +} from '@ovh-ux/manager-react-shell-client'; +import { render, waitFor, screen } from '@testing-library/react'; +import { + getServicesMocks, + GetServicesMocksParams, +} from '@ovh-ux/manager-react-components/src/hooks/services/mocks/services.mock'; +import { toMswHandlers } from '../../../../../../playwright-helpers'; +import { getAuthenticationMocks } from '../../../../../../playwright-helpers/mocks/auth'; +import { + getVeeamBackupMocks, + getOrganizationMocks, + GetOrganizationMocksParams, + GetVeeamBackupMocksParams, + getIamMocks, +} from '../../mocks'; +import { initTestI18n, labels } from './test-i18n'; +import { TestApp } from './TestApp'; +import { APP_NAME } from '@/tracking.constant'; + +let context: ShellContextType; +let i18nState: i18n; + +export const renderTest = async ({ + initialRoute, + ...mockParams +}: { + initialRoute?: string; +} & GetOrganizationMocksParams & + GetVeeamBackupMocksParams & + GetServicesMocksParams = {}) => { + ((global as unknown) as { server: SetupServer }).server?.resetHandlers( + ...toMswHandlers([ + ...getAuthenticationMocks({ isAuthMocked: true }), + ...getVeeamBackupMocks(mockParams), + ...getOrganizationMocks(mockParams), + ...getIamMocks(), + ...getServicesMocks(mockParams), + ]), + ); + + if (!context) { + context = await initShellContext(APP_NAME); + } + + if (!i18nState) { + i18nState = await initTestI18n(); + } + + const result = render( + + + + + , + ); + + if (!initialRoute || initialRoute === '/') { + await waitFor( + () => + expect( + screen.getAllByText(labels.listing.managed_vcd_listing_title, { + exact: false, + }).length, + ).toBeGreaterThan(0), + { timeout: 30000 }, + ); + } + + return result; +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/test-i18n.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/test-i18n.ts new file mode 100644 index 000000000000..662699b33450 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/test-utils/test-i18n.ts @@ -0,0 +1,80 @@ +import i18next, { i18n } from 'i18next'; +import error from '@ovh-ux/manager-react-components/src/components/templates/error/translations/Messages_fr_FR.json'; +import listing from '../../public/translations/listing/Messages_fr_FR.json'; +import dashboard from '../../public/translations/dashboard/Messages_fr_FR.json'; +import onboarding from '../../public/translations/onboarding/Messages_fr_FR.json'; +import common from '../../public/translations/hpc-vmware-managed-vcd/Messages_fr_FR.json'; +import datacentres from '../../public/translations/hpc-vmware-managed-vcd/datacentres/Messages_fr_FR.json'; +import datacentresCompute from '../../public/translations/hpc-vmware-managed-vcd/datacentres/compute/Messages_fr_FR.json'; +import datacentresOrder from '../../public/translations/hpc-vmware-managed-vcd/datacentres/order/Messages_fr_FR.json'; +import datacentresStorage from '../../public/translations/hpc-vmware-managed-vcd/datacentres/storage/Messages_fr_FR.json'; +import { APP_NAME } from '../tracking.constant'; + +export const defaultLocale = 'fr_FR'; +export const defaultAvailableLocales = [defaultLocale]; + +function addTranslations() { + i18next + .addResources(defaultLocale, APP_NAME, common) + .addResources(defaultLocale, 'listing', listing) + .addResources(defaultLocale, 'dashboard', dashboard) + .addResources(defaultLocale, 'onboarding', onboarding) + .addResources(defaultLocale, `${APP_NAME}/datacentres`, datacentres) + .addResources( + defaultLocale, + `${APP_NAME}/datacentres/compute`, + datacentresCompute, + ) + .addResources( + defaultLocale, + `${APP_NAME}/datacentres/order`, + datacentresOrder, + ) + .addResources( + defaultLocale, + `${APP_NAME}/datacentres/storage`, + datacentresStorage, + ) + .addResources(defaultLocale, 'error', error) + .use({ + type: 'postProcessor', + name: 'normalize', + process: (value: string) => + value ? value.replace(/&/g, '&') : value, + }); +} + +export const initTestI18n = () => + new Promise((resolve) => { + i18next.init({ + lng: defaultLocale, + defaultNS: APP_NAME, + ns: [], + supportedLngs: defaultAvailableLocales, + postProcess: 'normalize', + interpolation: { + escapeValue: false, + }, + }); + + if (i18next.isInitialized) { + addTranslations(); + } else { + i18next.on('initialized', () => { + addTranslations(); + resolve(i18next); + }); + } + }); + +export const labels = { + common, + onboarding, + dashboard, + listing, + error, + datacentres, + datacentresCompute, + datacentresOrder, + datacentresStorage, +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/tracking.constant.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/tracking.constant.ts new file mode 100644 index 000000000000..dbb8bdea4ebf --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/tracking.constant.ts @@ -0,0 +1,20 @@ +export const LEVEL2 = { + EU: { + config: { + level2: '56', + }, + }, + CA: { + config: { + level2: '56', + }, + }, + US: { + config: { + level2: '56', + }, + }, +}; +export const UNIVERSE = 'HostedPrivatedCloud'; +export const SUB_UNIVERSE = 'HostedPrivatedCloud'; +export const APP_NAME = 'hpc-vmware-managed-vcd'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/datagrid-route.type.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/datagrid-route.type.ts new file mode 100644 index 000000000000..64c74236d3aa --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/datagrid-route.type.ts @@ -0,0 +1,6 @@ +type TDatagridRoute = { + api: string; + onboarding: string; +}; + +export default TDatagridRoute; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-catalog.interface.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-catalog.interface.ts new file mode 100644 index 000000000000..2e2541312b33 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-catalog.interface.ts @@ -0,0 +1,53 @@ +import { Price } from '@ovh-ux/manager-module-order'; + +export enum ProductPricingCapacity { + CONSUMPTION = 'consumption', + DETACH = 'detach', + DOWNGRADE = 'downgrade', + DYNAMIC = 'dynamic', + INSTALLATION = 'installation', + RENEW = 'renew', + UPGRADE = 'upgrade', +} +enum ProductPricingType { + CONSUMPTION = 'consumption', + PURCHASE = 'purchase', + RENTAL = 'rental', +} +enum CatalogProductType { + CLOUD_SERVICE = 'cloud_service', + DELIVERY = 'delivery', + DEPOSIT = 'deposit', + DOMAIN = 'domain', + IMPLEMENTATION_SERVICES = 'implementation_servies', + SAAS_LICENSE = 'saas_license', + SHIPPING = 'shipping', + STORAGE = 'storage', +} + +export interface IVcdCatalogProductPricing { + capacities: ProductPricingCapacity[]; + description: string; + duration: unknown; + interval: number; + minimumQuantity: number; + maximumQuantity: number | null; + minimumRepeat: number; + maximumRepeat: number | null; + price: Price; + priceInUcents: number; + pricingMode: string; + pricingType: ProductPricingType; +} + +export interface IVcdCatalogProduct { + family: string; + planCode: string; + productName: string; + productType: CatalogProductType; + prices: IVcdCatalogProductPricing[]; + exclusive: boolean; + mandatory: boolean; +} + +export type TVcdCatalog = IVcdCatalogProduct[]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-compute.interface.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-compute.interface.ts new file mode 100644 index 000000000000..d2749a60418a --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-compute.interface.ts @@ -0,0 +1,14 @@ +export interface IVcdComputeState { + vCPUCount: number; + billingType: string; + memoryQuota: number; + name: string; + profile: string; +} + +export default interface IVcdCompute { + id: string; + resourceStatus: string; + currentState: IVcdComputeState; + currentTasks?: any[]; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-datacenter.interface.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-datacenter.interface.ts new file mode 100644 index 000000000000..f08cd1fdc29c --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-datacenter.interface.ts @@ -0,0 +1,26 @@ +import { IamObject } from '@ovh-ux/manager-react-components'; + +export interface IVcdDatacentreState { + vCPUSpeed: number; + description: string; +} + +export interface IVcdDatacentreCurrentState extends IVcdDatacentreState { + commercialRange: string; + ipQuota: number; + storageQuota: number; + vCPUCount: number; + region: string; + memoryQuota: number; + name: string; +} + +export default interface IVcdDatacentre { + id: string; + resourceStatus: string; + currentState: IVcdDatacentreCurrentState; + targetSpec: IVcdDatacentreState; + currentTasks?: any[]; + iam: IamObject; + updatedAt: string; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization-backup.interface.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization-backup.interface.ts new file mode 100644 index 000000000000..4da774b4f2af --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization-backup.interface.ts @@ -0,0 +1,48 @@ +import { IamObject } from '@ovh-ux/manager-react-components/src/hooks/iam'; + +export enum BackupResourceStatus { + CREATING = 'CREATING', + DISABLED = 'DISABLED', + DISABLING = 'DISABLING', + READY = 'READY', + REMOVED = 'REMOVED', + UPDATING = 'UPDATING', +} + +interface IBackupOffer { + name: string; + quotaInTB: number; + status: string; + usedSpaceInGB: number; +} + +interface IVcdOrganizationBackupState { + offers: IBackupOffer[]; + region: string; +} + +interface IVcdOrganizationBackupSpecs { + offers: { + name: string; + quotaInTB: number; + status: string; + }[]; +} + +interface IVcdOrganizationBackupTask { + id: string; + link: string; + status: string | null; + type: string; +} + +export default interface IVcdOrganizationBackup { + id: string; + resourceStatus: BackupResourceStatus; + currentState: IVcdOrganizationBackupState; + targetSpec: IVcdOrganizationBackupSpecs; + currentTasks?: IVcdOrganizationBackupTask[]; + createdAt?: string; + updatedAt?: string; + iam: IamObject; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization.interface.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization.interface.ts new file mode 100644 index 000000000000..0d470beaf099 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-organization.interface.ts @@ -0,0 +1,25 @@ +import { IamObject } from '@ovh-ux/manager-react-components'; + +export interface IVcdOrganizationState { + fullName: string; + description: string; +} + +export interface IVcdOrganizationCurrentState extends IVcdOrganizationState { + apiUrl?: string; + region: string; + name: string; + spla: boolean; + billingType: 'DEMO' | 'MONTHLY'; + webInterfaceUrl: string; +} + +export default interface IVcdOrganization { + id: string; + resourceStatus: string; + currentState: IVcdOrganizationCurrentState; + targetSpec: IVcdOrganizationState; + currentTasks?: any[]; + iam: IamObject; + updatedAt: string; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-storage.interface.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-storage.interface.ts new file mode 100644 index 000000000000..60bd8f4b5727 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-storage.interface.ts @@ -0,0 +1,21 @@ +export interface IVcdStorageState { + billingType: string; + capacity: number; + name: string; + profile: string; + type: string; +} + +interface IVcdStorageTask { + id: string; + link: string; + status: string; + type: string; +} + +export default interface IVcdStorage { + id: string; + resourceStatus: string; + currentState: IVcdStorageState; + currentTasks?: IVcdStorageTask[]; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-vdc-orderable-resource.interface.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-vdc-orderable-resource.interface.ts new file mode 100644 index 000000000000..511a74134db3 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/types/vcd-vdc-orderable-resource.interface.ts @@ -0,0 +1,26 @@ +import { IVcdCatalogProductPricing } from './vcd-catalog.interface'; +import { IVcdComputeState } from './vcd-compute.interface'; +import { IVcdStorageState } from './vcd-storage.interface'; + +export interface IVdcOrderableVHost + extends Omit { + vCPUSpeed: number; +} +export interface IVdcOrderableVhostPriced extends IVdcOrderableVHost { + pricing: IVcdCatalogProductPricing; +} + +export type IVdcOrderableStorage = Omit; +export interface IVdcOrderableStoragePriced extends IVdcOrderableStorage { + pricing: IVcdCatalogProductPricing; +} + +export type IVdcOrderableResource = IVdcOrderableVHost | IVdcOrderableStorage; +export type IVdcOrderableResourcePriced = + | IVdcOrderableVhostPriced + | IVdcOrderableStoragePriced; + +export interface IVdcOrderableResourceData { + compute: IVdcOrderableVHost[]; + storage: IVdcOrderableStorage[]; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/capitalize.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/capitalize.ts new file mode 100644 index 000000000000..9ff53205ef56 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/capitalize.ts @@ -0,0 +1,3 @@ +export function capitalize(str = '') { + return `${str.charAt(0).toUpperCase()}${str.substring(1).toLowerCase()}`; +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/formValidation.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/formValidation.ts new file mode 100644 index 000000000000..7ece7606d0e9 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/formValidation.ts @@ -0,0 +1,15 @@ +export const validateOrganizationName = (name: string) => + /^.{1,128}$/.test(name); + +export const validateDescription = (description: string) => + /^.{1,255}$/.test(description); + +export const validateQuantity = ({ + quantity, + min, + max, +}: { + quantity: number; + min: number; + max: number; +}) => quantity >= min && quantity <= max; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getBackupBadge.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getBackupBadge.ts new file mode 100644 index 000000000000..4d0e03eca207 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getBackupBadge.ts @@ -0,0 +1,65 @@ +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { BackupResourceStatus } from '@/types/vcd-organization-backup.interface'; + +type BadgeStatus = BackupResourceStatus | 'none' | 'error'; +export type BackupBadgeParams = { + color: ODS_THEME_COLOR_INTENT; + translationKey: string; + testIdLabel: string; +}; + +const getBadgeColor = (status: BadgeStatus) => { + const colors: Record = { + error: ODS_THEME_COLOR_INTENT.error, + none: ODS_THEME_COLOR_INTENT.default, + DISABLED: ODS_THEME_COLOR_INTENT.default, + REMOVED: ODS_THEME_COLOR_INTENT.default, + CREATING: ODS_THEME_COLOR_INTENT.primary, + DISABLING: ODS_THEME_COLOR_INTENT.primary, + UPDATING: ODS_THEME_COLOR_INTENT.primary, + READY: ODS_THEME_COLOR_INTENT.success, + }; + return colors[status] || ODS_THEME_COLOR_INTENT.default; +}; + +const getBadgeTranslationKey = (status: BadgeStatus) => { + const prefix = 'managed_vcd_dashboard_backup_status_'; + const translationKeys: Record = { + error: 'error', + none: 'unsubscribed', + DISABLED: 'unsubscribed', + REMOVED: 'unsubscribed', + CREATING: 'creating', + UPDATING: 'updating', + DISABLING: 'disabling', + READY: 'subscribed', + }; + return `${prefix}${translationKeys[status] || 'error'}`; +}; + +const getBadgeTestId = (status: BadgeStatus) => { + if (status === 'error') return 'backupError'; + if (status === 'none') return 'noBackup'; + return 'backupStatus'; +}; + +export const getBackupBadgeParams = ( + status: BadgeStatus, +): BackupBadgeParams => { + return { + color: getBadgeColor(status), + translationKey: getBadgeTranslationKey(status), + testIdLabel: getBadgeTestId(status), + }; +}; + +export const getBackupBadgeStatus = ({ + errorStatus, + backupStatus, +}: { + errorStatus: number; + backupStatus: BackupResourceStatus; +}): BadgeStatus => { + if (backupStatus) return backupStatus; + return errorStatus === 404 ? 'none' : 'error'; +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getPricedOrderableResource.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getPricedOrderableResource.ts new file mode 100644 index 000000000000..3ea1cd011e8d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/getPricedOrderableResource.ts @@ -0,0 +1,38 @@ +import { + IVdcOrderableResource, + IVdcOrderableResourcePriced, +} from '@/types/vcd-vdc-orderable-resource.interface'; +import { + ProductPricingCapacity, + TVcdCatalog, +} from '@/types/vcd-catalog.interface'; + +export const getVdcResourcePrice = (resource: IVdcOrderableResourcePriced) => + resource.pricing?.priceInUcents; + +export const getVdcResourcePriceLabel = ( + resource: IVdcOrderableResourcePriced, +) => resource.pricing.price.text; + +export const getPricedVdcResources = ({ + resources, + catalog, +}: { + resources: IVdcOrderableResource[]; + catalog: TVcdCatalog; +}): IVdcOrderableResourcePriced[] => { + if (!resources || !catalog) { + return []; + } + return resources + .reduce((list: IVdcOrderableResourcePriced[], resource) => { + const prices = catalog.find( + ({ planCode }) => planCode === resource.profile, + )?.prices; + const pricing = prices?.find(({ capacities }) => + capacities.includes(ProductPricingCapacity.RENEW), + ); + return pricing ? [...list, { ...resource, pricing }] : list; + }, []) + .sort((a, b) => getVdcResourcePrice(a) - getVdcResourcePrice(b)); +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/iam.constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/iam.constants.ts new file mode 100644 index 000000000000..11675016baf2 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/iam.constants.ts @@ -0,0 +1,6 @@ +export const iamActions = { + vmwareCloudDirectorApiovhOrganizationEdit: + 'vmwareCloudDirector:apiovh:organization/edit', + vmwareCloudDirectorApiovhOrganizationVirtualDataCenterEdit: + 'vmwareCloudDirector:apiovh:organization/virtualDataCenter/edit', +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/planCode.constants.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/planCode.constants.ts new file mode 100644 index 000000000000..72a52bf2acc0 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/planCode.constants.ts @@ -0,0 +1 @@ +export const WINDOWS_LICENSE_PLANCODE = 'vcd-microsoft-license'; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/queryKeys.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/queryKeys.ts new file mode 100644 index 000000000000..5ed87dc0edf6 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/queryKeys.ts @@ -0,0 +1,56 @@ +const vcdBaseKey = 'vmwareCloudDirector'; +const vdcBaseKey = 'virtualDataCenter'; +export const icebergListingQueryKey = 'servicesListingIceberg'; + +// VCD organizations +export const getVcdOrganizationsQueryKey = () => [vcdBaseKey, 'organizations']; +export const getVcdOrganizationQueryKey = (id: string) => [ + ...getVcdOrganizationsQueryKey(), + id, +]; +export const getVcdOrganizationBackupQueryKey = (id: string) => [ + ...getVcdOrganizationQueryKey(id), + 'backup', +]; +export const getVcdCatalogQueryKey = (serviceName: string) => [ + 'order', + 'cartServiceOption', + vcdBaseKey, + serviceName, +]; + +// VCD Organization virtualDataCenters +export const getVcdDatacentresQueryKey = (id: string) => [ + ...getVcdOrganizationQueryKey(id), + vdcBaseKey, +]; +export const getVcdDatacentreQueryKey = (id: string, vdcId: string) => [ + ...getVcdDatacentresQueryKey(id), + vdcId, +]; + +// VirtualDataCenter resources +const getVdcQueryKey = (vdcId: string) => [vdcBaseKey, vdcId]; + +export const getVdcComputeQueryKey = (vdcId: string) => [ + ...getVdcQueryKey(vdcId), + 'compute', +]; +export const getVdcStorageQueryKey = (vdcId: string) => [ + ...getVdcQueryKey(vdcId), + 'storage', +]; +export const getVdcOrderableResourceQueryKey = (vdcId: string) => [ + ...getVdcQueryKey(vdcId), + 'orderableResource', +]; + +// Mutation keys +export const updateVcdOrganizationDetailsMutationKey = (id: string) => [ + 'put', + ...getVcdOrganizationQueryKey(id), +]; +export const updateVdcDetailsMutationKey = (vdcId: string) => [ + 'put', + ...getVdcQueryKey(vdcId), +]; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/refetchConditions.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/refetchConditions.ts new file mode 100644 index 000000000000..a6accb3020c7 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/utils/refetchConditions.ts @@ -0,0 +1,13 @@ +import IVcdDatacentre from '@/types/vcd-datacenter.interface'; +import IVcdOrganization from '@/types/vcd-organization.interface'; + +export type UpdatableResource = IVcdOrganization | IVcdDatacentre; + +const targetSpecKey = 'configure-target-spec'; + +export const isUpdatingTargetSpec = (resource: UpdatableResource | undefined) => + resource?.currentTasks?.some((task) => task.type === targetSpecKey); + +export const hasResourceUpdatingTargetSpec = ( + resources: UpdatableResource[] | undefined, +) => resources?.some((resource) => isUpdatingTargetSpec(resource)); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/src/vite-hmr.ts b/packages/manager/apps/hpc-vmware-managed-vcd/src/vite-hmr.ts new file mode 100644 index 000000000000..473d87630039 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/src/vite-hmr.ts @@ -0,0 +1,5 @@ +if (import.meta.hot) { + import.meta.hot.on('iframe-reload', () => { + window.location.reload(); + }); +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/tailwind.config.js b/packages/manager/apps/hpc-vmware-managed-vcd/tailwind.config.js new file mode 100644 index 000000000000..657ab11bb87d --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/tailwind.config.js @@ -0,0 +1,14 @@ +import path from 'path'; +import config from '@ovh-ux/manager-tailwind-config'; + +/** @type {import('tailwindcss').Config} */ +module.exports = { + ...config, + content: [ + './src/**/*.{js,jsx,ts,tsx}', + path.join( + path.dirname(require.resolve('@ovh-ux/manager-react-components')), + '**/*.{js,jsx,ts,tsx}', + ), + ], +}; diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.json b/packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.json new file mode 100644 index 000000000000..70b519f06c61 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "lib": ["dom", "es2021"], + "noEmit": true, + "target": "es2020", + "types": ["vite/client", "node"], + "module": "ES2020", + "moduleResolution": "node", + "removeComments": true, + "outDir": "dist", + "esModuleInterop": true, + "isolatedModules": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "noImplicitAny": true, + "declaration": true, + "resolveJsonModule": true, + "allowJs": true, + "jsx": "react", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "exclude": ["node_modules", "dist", "types", "**/*.spec.ts*"] +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.test.json b/packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.test.json new file mode 100644 index 000000000000..7048c297c8f6 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/tsconfig.test.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS" + } +} diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/vite.config.mjs b/packages/manager/apps/hpc-vmware-managed-vcd/vite.config.mjs new file mode 100644 index 000000000000..f33ab6dc98cd --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/vite.config.mjs @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite'; +import { getBaseConfig } from '@ovh-ux/manager-vite-config'; +import { resolve } from 'path'; + +export default defineConfig({ + ...getBaseConfig(), + root: resolve(process.cwd()), +}); diff --git a/packages/manager/apps/hpc-vmware-managed-vcd/vitest.config.js b/packages/manager/apps/hpc-vmware-managed-vcd/vitest.config.js new file mode 100644 index 000000000000..a5e80ab7f4a3 --- /dev/null +++ b/packages/manager/apps/hpc-vmware-managed-vcd/vitest.config.js @@ -0,0 +1,41 @@ +import path from 'path'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + test: { + globals: true, + environment: 'jsdom', + setupFiles: './setupTests.ts', + coverage: { + include: ['src'], + exclude: [ + 'src/types', + 'src/test-utils', + 'src/vite-*.ts', + 'src/App.tsx', + 'src/index.tsx', + 'src/tracking.constant.ts', + ], + }, + testTimeout: 60000, + fileParallelism: false, + maxWorkers: 1, + pollOptions: { + forks: { + singleFork: true, + }, + threads: { + singleThread: true, + }, + }, + }, + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, + mainFields: ['module'], + }, +}); diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_de_DE.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_de_DE.json index aacc94185ec5..159724837b4b 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_de_DE.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_de_DE.json @@ -69,7 +69,7 @@ "billing_autorenew_service_type_DEDICATED_SERVER": "Dedicated Server", "billing_autorenew_service_type_dedicated_server": "Dedicated Server", "billing_autorenew_service_type_DEDICATED_HOUSING": "Server-Housing", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Domain", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -153,5 +153,6 @@ "billing_autorenew_service_activate_alert_renew2016": "Diese Meldung betrifft nicht die Bare-Metal- und VPS-Dienste.", "billing_autorenew_service_type_DEDICATED_CLUSTER": "Region 3-AZ", "billing_autorenew_service_type_OKMS_RESOURCE": "OVHcloud KMS", - "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services" + "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD" } diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_en_GB.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_en_GB.json index f0090d75a16f..dec2e79237e0 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_en_GB.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_en_GB.json @@ -69,7 +69,7 @@ "billing_autorenew_service_type_DEDICATED_SERVER": "Dedicated Server", "billing_autorenew_service_type_dedicated_server": "Dedicated Server", "billing_autorenew_service_type_DEDICATED_HOUSING": "Housing server ", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Domain", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -153,5 +153,6 @@ "billing_autorenew_service_activate_alert_renew2016": "This message does not apply to Bare Metal and VPS services.", "billing_autorenew_service_type_DEDICATED_CLUSTER": " 3-AZ Region", "billing_autorenew_service_type_OKMS_RESOURCE": "OVHcloud KMS", - "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services" + "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD" } diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_es_ES.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_es_ES.json index cb6596c13e91..c35c53413f7b 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_es_ES.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_es_ES.json @@ -69,7 +69,7 @@ "billing_autorenew_service_type_DEDICATED_SERVER": "Servidor dedicado", "billing_autorenew_service_type_dedicated_server": "Servidor dedicado", "billing_autorenew_service_type_DEDICATED_HOUSING": "Servidor en housing", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Dominio", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -153,5 +153,6 @@ "billing_autorenew_service_activate_alert_renew2016": "Este mensaje no se aplica a los servicios Bare Metal y VPS.", "billing_autorenew_service_type_DEDICATED_CLUSTER": "Región 3-AZ", "billing_autorenew_service_type_OKMS_RESOURCE": "OVHcloud KMS", - "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services" + "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD" } diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_CA.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_CA.json index 2bb9908b7bd7..a2061afbd2e6 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_CA.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_CA.json @@ -77,7 +77,7 @@ "billing_autorenew_service_type_DEDICATED_CLUSTER": "Région 3-AZ", "billing_autorenew_service_type_dedicated_server": "Serveur Dédié", "billing_autorenew_service_type_DEDICATED_HOUSING": "Serveur Housing", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Domaine", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -123,6 +123,7 @@ "billing_autorenew_service_type_SHAREPOINT": "Sharepoint", "billing_autorenew_service_type_VEEAM_CLOUD_CONNECT": "Veeam Cloud Connect", "billing_autorenew_service_type_VEEAM_ENTERPRISE": "Veeam Enterprise", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD", "billing_autorenew_service_type_METRICS": "Metrics", "billing_autorenew_service_type_kube": "Kubernetes", "billing_autorenew_service_type_WEBCOACH": "WebCoach", diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_FR.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_FR.json index 2bb9908b7bd7..a2061afbd2e6 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_FR.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_fr_FR.json @@ -77,7 +77,7 @@ "billing_autorenew_service_type_DEDICATED_CLUSTER": "Région 3-AZ", "billing_autorenew_service_type_dedicated_server": "Serveur Dédié", "billing_autorenew_service_type_DEDICATED_HOUSING": "Serveur Housing", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Domaine", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -123,6 +123,7 @@ "billing_autorenew_service_type_SHAREPOINT": "Sharepoint", "billing_autorenew_service_type_VEEAM_CLOUD_CONNECT": "Veeam Cloud Connect", "billing_autorenew_service_type_VEEAM_ENTERPRISE": "Veeam Enterprise", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD", "billing_autorenew_service_type_METRICS": "Metrics", "billing_autorenew_service_type_kube": "Kubernetes", "billing_autorenew_service_type_WEBCOACH": "WebCoach", diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_it_IT.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_it_IT.json index 8b64a3cecaa9..21cbddd2200c 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_it_IT.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_it_IT.json @@ -69,7 +69,7 @@ "billing_autorenew_service_type_DEDICATED_SERVER": "Server dedicati", "billing_autorenew_service_type_dedicated_server": "Server dedicati", "billing_autorenew_service_type_DEDICATED_HOUSING": "Server in housing", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Domini", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -153,5 +153,6 @@ "billing_autorenew_service_activate_alert_renew2016": "Questo messaggio non si applica ai servizi Bare Metal e VPS.", "billing_autorenew_service_type_DEDICATED_CLUSTER": "Region 3-AZ", "billing_autorenew_service_type_OKMS_RESOURCE": "OVHcloud KMS", - "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services" + "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD" } diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_pl_PL.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_pl_PL.json index cb6746c04870..e3a6fc88ece7 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_pl_PL.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_pl_PL.json @@ -69,7 +69,7 @@ "billing_autorenew_service_type_DEDICATED_SERVER": "Serwer dedykowany", "billing_autorenew_service_type_dedicated_server": "Serwer dedykowany", "billing_autorenew_service_type_DEDICATED_HOUSING": "Housing", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Domena", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -153,5 +153,6 @@ "billing_autorenew_service_activate_alert_renew2016": "Ta wiadomość nie dotyczy usług Bare Metal i VPS.", "billing_autorenew_service_type_DEDICATED_CLUSTER": "Region 3-AZ", "billing_autorenew_service_type_OKMS_RESOURCE": "OVHcloud KMS", - "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services" + "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD" } diff --git a/packages/manager/modules/billing/src/autoRenew/translations/Messages_pt_PT.json b/packages/manager/modules/billing/src/autoRenew/translations/Messages_pt_PT.json index 94406d021a8c..f110014f341d 100644 --- a/packages/manager/modules/billing/src/autoRenew/translations/Messages_pt_PT.json +++ b/packages/manager/modules/billing/src/autoRenew/translations/Messages_pt_PT.json @@ -69,7 +69,7 @@ "billing_autorenew_service_type_DEDICATED_SERVER": "Servidor dedicado", "billing_autorenew_service_type_dedicated_server": "Servidor dedicado", "billing_autorenew_service_type_DEDICATED_HOUSING": "Servidor housing", - "billing_autorenew_service_type_DEDICATED_CLOUD": "VMware", + "billing_autorenew_service_type_DEDICATED_CLOUD": "Managed VMware vSphere", "billing_autorenew_service_type_ESSENTIALS": "Managed Bare Metal", "billing_autorenew_service_type_DOMAIN": "Domínio", "billing_autorenew_service_type_ENTERPRISE_CLOUD_DATABASE": "Enterprise Cloud Databases", @@ -153,5 +153,6 @@ "billing_autorenew_service_activate_alert_renew2016": "Esta mensagem não diz respeito aos serviços Bare Metal e VPS.", "billing_autorenew_service_type_DEDICATED_CLUSTER": "Região 3-AZ", "billing_autorenew_service_type_OKMS_RESOURCE": "OVHcloud KMS", - "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services" + "billing_autorenew_service_type_VRACK_SERVICES_RESOURCE": "vRack Services", + "billing_autorenew_service_type_VMWARE_CLOUD_DIRECTOR_ORGANIZATION": "Managed VCD" } diff --git a/packages/manager/modules/order/src/order.constant.ts b/packages/manager/modules/order/src/order.constant.ts index aedc717e73cb..e70c8a5f7d9a 100644 --- a/packages/manager/modules/order/src/order.constant.ts +++ b/packages/manager/modules/order/src/order.constant.ts @@ -33,6 +33,29 @@ export const getKMSProductSettings = ({ region }: { region: string }) => configuration: [{ label: 'region', value: region }].filter(Boolean), }); +export const getVcdProductSettings = ({ + serviceName, + planCode, + quantity = 1, + vdcOrgId, +}: { + serviceName: string; + planCode: string; + quantity?: number; + vdcOrgId?: string; +}) => + JSURL.stringify({ + serviceName, + planCode, + quantity, + productId: 'vmwareCloudDirector', + duration: 'P1M', + pricingMode: 'default', + configuration: vdcOrgId + ? [{ label: 'vdc-org-id', value: vdcOrgId }] + : undefined, + }); + export const ORDER_URLS = { EU: { DEDICATED: { diff --git a/yarn.lock b/yarn.lock index 1667eebe6083..45fbf0febeb2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8364,7 +8364,7 @@ dependencies: "@tanstack/query-devtools" "5.28.10" -"@tanstack/react-query-devtools@^5.51.21": +"@tanstack/react-query-devtools@5.51.21", "@tanstack/react-query-devtools@^5.51.21": version "5.51.21" resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.51.21.tgz#8ccfcfdb07e64de9220c34f7a969691dfb12a9ae" integrity sha512-mi5ef8dvsS48GsG6/8M60O2EgrzPK1kNPngOcHBTlIUrB5dGkxP9fuHf05GQRxtSp5W5GlyeUpzOmtkKNpf9dQ== @@ -8378,7 +8378,7 @@ dependencies: "@tanstack/query-core" "5.51.9" -"@tanstack/react-query@^5.51.21": +"@tanstack/react-query@5.51.21", "@tanstack/react-query@^5.51.21": version "5.51.21" resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.51.21.tgz#cdd14677bcc809a83e01b6c38842c841ce7420af" integrity sha512-Q/V81x3sAYgCsxjwOkfLXfrmoG+FmDhLeHH5okC/Bp8Aaw2c33lbEo/mMcMnkxUPVtB2FLpzHT0tq3c+OlZEbw== @@ -17637,9 +17637,9 @@ i18next-http-backend@^2.5.2: cross-fetch "4.0.0" i18next-http-backend@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.6.1.tgz#186c3a1359e10245c9119a13129f9b5bf328c9a7" - integrity sha512-rCilMAnlEQNeKOZY1+x8wLM5IpYOj10guGvEpeC59tNjj6MMreLIjIW8D1RclhD3ifLwn6d/Y9HEM1RUE6DSog== + version "2.6.2" + resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.6.2.tgz#b25516446ae6f251ce8231e70e6ffbca833d46a5" + integrity sha512-Hp/kd8/VuoxIHmxsknJXjkTYYHzivAyAF15pzliKzk2TiXC25rZCEerb1pUFoxz4IVrG3fCvQSY51/Lu4ECV4A== dependencies: cross-fetch "4.0.0" @@ -27054,7 +27054,7 @@ tailwindcss-animate@^1.0.7: resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz#318b692c4c42676cc9e67b19b78775742388bef4" integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== -tailwindcss@^3.4.10, tailwindcss@^3.4.3, tailwindcss@^3.4.6: +tailwindcss@^3.3.3: version "3.4.13" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.13.tgz#3d11e5510660f99df4f1bfb2d78434666cb8f831" integrity sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw== @@ -27082,6 +27082,62 @@ tailwindcss@^3.4.10, tailwindcss@^3.4.3, tailwindcss@^3.4.6: resolve "^1.22.2" sucrase "^3.32.0" +tailwindcss@^3.4.10, tailwindcss@^3.4.6: + version "3.4.14" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.14.tgz#6dd23a7f54ec197b19159e91e3bb1e55e7aa73ac" + integrity sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +tailwindcss@^3.4.3: + version "3.4.9" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.9.tgz#9e04cddce1924d530df62af37d3520f0e2a9d85e" + integrity sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + tailwindcss@^3.4.4: version "3.4.4" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.4.tgz#351d932273e6abfa75ce7d226b5bf3a6cb257c05"