Skip to content

Commit

Permalink
feat(veeam-backup): add new product veeam-backup (#12611)
Browse files Browse the repository at this point in the history
ref: MANAGER-14740

Signed-off-by: Nicolas Pierre-charles <[email protected]>
Co-authored-by: David Arsène <[email protected]>
  • Loading branch information
chipp972 and darsene authored Oct 18, 2024
1 parent ea79dad commit fdcf66a
Show file tree
Hide file tree
Showing 145 changed files with 4,159 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { OsdsText } from '@ovhcloud/ods-components/react';

export interface DescriptionProps {
children?: string;
children?: React.ReactNode;
className?: string;
}
export const Description: React.FC<DescriptionProps> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { IcebergFetchParamsV2, fetchIcebergV2 } from '@ovh-ux/manager-core-api';
import { useInfiniteQuery } from '@tanstack/react-query';
import { ColumnSort } from '../../components';

interface IcebergV2Hook {
interface IcebergV2Hook<T> {
queryKey: string[];
defaultSorting?: ColumnSort;
sort?: (sorting: ColumnSort, data: T[]) => T[];
}

export const defaultPageSize = 10;
Expand All @@ -20,7 +21,7 @@ export function useResourcesIcebergV2<T = unknown>({
pageSize = defaultPageSize,
queryKey,
defaultSorting = undefined,
}: IcebergFetchParamsV2 & IcebergV2Hook) {
}: IcebergFetchParamsV2 & IcebergV2Hook<T>) {
const [flattenData, setFlattenData] = useState<T[]>([]);
const [sorting, setSorting] = useState<ColumnSort>(defaultSorting);
const {
Expand All @@ -42,7 +43,7 @@ export function useResourcesIcebergV2<T = unknown>({
});

useEffect(() => {
const flatten = data?.pages.map((page) => page.data).flat();
const flatten = data?.pages.map((page) => page.data).flat() as T[];
setFlattenData(flatten);
}, [data]);

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import { useFeatureAvailability } from '@ovh-ux/manager-react-components';
import infinityCLoud from '@/assets/images/sidebar/infinity-cloud.png';
import hycuLogo from '@/assets/images/sidebar/hycu-logo.svg';
import veeamBackupLogo from '@/assets/images/sidebar/veeam-backup-logo.png';

const features = [
'dedicated-cloud',
Expand All @@ -33,6 +34,7 @@ const features = [
'dedicated-cloud:order',
'cloud-disk-array',
'dedicated-nasha',
'veeam-backup',
'veeam-cloud-connect:order',
'veeam-enterprise:order',
'hycu',
Expand Down Expand Up @@ -239,14 +241,35 @@ export default function HostedPrivateCloudSidebar() {
],
});
}
if (feature['hycu']) {

if (feature['hycu'] || feature['veeam-backup']) {
menu.push({
id: 'hpc-storage-backup',
label: t('sidebar_storage_backup'),
icon: <img className="mb-1 mr-1 w-6 aspect-square" alt="" src={infinityCLoud} />,
pathMatcher: new RegExp('^/hycu'),
pathMatcher: new RegExp('^/hycu|/veeam-backup'),
badge: 'new',
subItems: [
(feature['veeam-backup']) && {
id: 'hpc-veeam-backup',
label: t('sidebar_veeam_backup'),
icon: <img alt="" src={veeamBackupLogo} />,
pathMatcher: new RegExp('^/veeam-backup'),
async loader() {
const appId = 'veeam-backup';
const items = await loadServices('/vmwareCloudDirector/backup', null, appId);

return [
{
id: 'veeam-backup-all',
label: t('sidebar_all_veeam_backup'),
href: navigation.getURL(appId, '#/'),
ignoreSearch: true,
},
...items
];
},
},
(feature['hycu']) && {
id: 'hpc-hycu',
label: t('sidebar_hycu'),
Expand All @@ -272,7 +295,7 @@ export default function HostedPrivateCloudSidebar() {
},
}
]
})
});
}

if (feature['key-management-service']) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ hostedPrivateCloudUniverse.children = [
},
features: ['hycu'],
},
{
id: 'veeam-backup',
translation: 'sidebar_veeam_backup',
serviceType: 'VEEAMBACKUP',
tag: NodeTag.NEW,
routing: {
application: 'veeam-backup',
hash: '#/',
},
features: ['veeam-backup'],
},
],
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,7 @@
"sidebar_zimbra": "Zimbra Mail",
"sidebar_pci_savings_plan": "Savings Plans",
"sidebar_hycu": "HYCU",
"sidebar_all_hycu": "Alle meine Lizenzen"
"sidebar_all_hycu": "Alle meine Lizenzen",
"sidebar_veeam_backup": "Managed Veeam für VCD",
"sidebar_all_veeam_backup": "Alle Dienstleistungen"
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,7 @@
"sidebar_reduce": "Minimise",
"sidebar_pci_savings_plan": "Savings Plan",
"sidebar_hycu": "HYCU",
"sidebar_all_hycu": "All my licenses"
"sidebar_all_hycu": "All my licenses",
"sidebar_veeam_backup": "Managed Veeam for VCD",
"sidebar_all_veeam_backup": "All services"
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,7 @@
"sidebar_reduce": "Minimizar",
"sidebar_pci_savings_plan": "Savings Plans",
"sidebar_hycu": "HYCU",
"sidebar_all_hycu": "Todas mis licencias"
"sidebar_all_hycu": "Todas mis licencias",
"sidebar_veeam_backup": "Managed Veeam for VCD",
"sidebar_all_veeam_backup": "Todos los servicios"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"sidebar_telecom_operations": "Opérations",
"sidebar_vps": "Serveurs Privés Virtuels",
"sidebar_storage_backup": "Stockage et sauvegarde",
"sidebar_veeam_backup": "Managed Veeam for VCD",
"sidebar_all_veeam_backup": "Tous les services",
"sidebar_dedicated_cloud": "Managed Bare Metal",
"sidebar_licences": "Licences",
"sidebar_hpc": "Hosted Private Cloud",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"sidebar_telecom_operations": "Opérations",
"sidebar_vps": "Serveurs Privés Virtuels",
"sidebar_storage_backup": "Stockage et sauvegarde",
"sidebar_veeam_backup": "Managed Veeam for VCD",
"sidebar_all_veeam_backup": "Tous les services",
"sidebar_dedicated_cloud": "Managed Bare Metal",
"sidebar_licences": "Licences",
"sidebar_hpc": "Hosted Private Cloud",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,7 @@
"sidebar_reduce": "Riduci",
"sidebar_pci_savings_plan": "Savings Plan",
"sidebar_hycu": "HYCU",
"sidebar_all_hycu": "Tutte le mie licenze"
"sidebar_all_hycu": "Tutte le mie licenze",
"sidebar_veeam_backup": "Managed Veeam for VCD",
"sidebar_all_veeam_backup": "Tutti i servizi"
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,7 @@
"sidebar_reduce": "Zmniejsz",
"sidebar_pci_savings_plan": "Savings Plans",
"sidebar_hycu": "HYCU",
"sidebar_all_hycu": "Wszystkie moje licencje"
"sidebar_all_hycu": "Wszystkie moje licencje",
"sidebar_veeam_backup": "Managed Veeam for VCD",
"sidebar_all_veeam_backup": "Wszystkie usługi"
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,7 @@
"sidebar_reduce": "Reduzir",
"sidebar_pci_savings_plan": "Savings Plans",
"sidebar_hycu": "HYCU",
"sidebar_all_hycu": "Todas as minhas licenças"
"sidebar_all_hycu": "Todas as minhas licenças",
"sidebar_veeam_backup": "Managed Veeam for VCD",
"sidebar_all_veeam_backup": "Todos os serviços"
}
2 changes: 2 additions & 0 deletions packages/manager/apps/veeam-backup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
e2e/reports
coverage
3 changes: 3 additions & 0 deletions packages/manager/apps/veeam-backup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @ovh-ux/manager-veeam-backup-app

> veeam backup app
20 changes: 20 additions & 0 deletions packages/manager/apps/veeam-backup/cucumber.js
Original file line number Diff line number Diff line change
@@ -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,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Feature: Onboarding page

Scenario: User wants to find informations related to veeam-backup
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
Original file line number Diff line number Diff line change
@@ -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<ConfigParams>,
nb: number,
) {
this.handlersConfig.nbBackup = nb;
});

When('User navigates to Listing page', async function(
this: ICustomWorld<ConfigParams>,
) {
await setupNetwork(this);
await this.page.goto(getUrl('listing'), { waitUntil: 'load' });
});

Then('User gets redirected to Onboarding page', async function(
this: ICustomWorld<ConfigParams>,
) {
await expect(this.page).toHaveURL(getUrl('onboarding'));
});

Then('User sees {int} guides', async function(
this: ICustomWorld<ConfigParams>,
nbGuides: number,
) {
const guides = await this.page.locator('osds-tile');
await expect(guides).toHaveCount(nbGuides);
});
7 changes: 7 additions & 0 deletions packages/manager/apps/veeam-backup/e2e/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -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]}`;
2 changes: 2 additions & 0 deletions packages/manager/apps/veeam-backup/e2e/utils/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './network';
export * from './constants';
45 changes: 45 additions & 0 deletions packages/manager/apps/veeam-backup/e2e/utils/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BrowserContext } from '@playwright/test';
import {
getServicesMocks,
GetServicesMocksParams,
} from '@ovh-ux/manager-react-components/src/hooks/services/mocks/services.mock';
import {
ICustomWorld,
toPlaywrightMockHandler,
Handler,
} from '../../../../../../playwright-helpers';
import {
GetAuthenticationMocks,
getAuthenticationMocks,
} from '../../../../../../playwright-helpers/mocks/auth';
import {
getIamMocks,
getOrganizationMocks,
GetOrganizationMocksParams,
getVeeamBackupMocks,
GetVeeamBackupMocksParams,
} from '../../mocks';

export type ConfigParams = GetAuthenticationMocks &
GetVeeamBackupMocksParams &
GetOrganizationMocksParams &
GetServicesMocksParams;

export const getConfig = (params: ConfigParams): Handler[] =>
[
getAuthenticationMocks,
getIamMocks,
getOrganizationMocks,
getVeeamBackupMocks,
getServicesMocks,
].flatMap((getMocks) => getMocks(params));

export const setupNetwork = async (world: ICustomWorld) =>
Promise.all(
getConfig({
...((world?.handlersConfig as ConfigParams) || ({} as ConfigParams)),
isAuthMocked: true,
})
.reverse()
.map(toPlaywrightMockHandler(world.context as BrowserContext)),
);
22 changes: 22 additions & 0 deletions packages/manager/apps/veeam-backup/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="mobile-web-app-capable" content="yes" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>OVHcloud</title>
<link rel="shortcut icon" href="images/favicon.png" />
<link rel="apple-touch-icon" href="images/touchicon-180.png" />
</head>
<body>
<noscript>
<strong>
We're sorry but this application doesn't work properly without
JavaScript enabled. Please enable it to continue.
</strong>
</noscript>
<div id="root"></div>
<script type="module" src="./src/index.tsx"></script>
</body>
</html>
22 changes: 22 additions & 0 deletions packages/manager/apps/veeam-backup/mocks/iam.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"resourceURN": "urn:v1:resource:vmwareCloudDirectorBackup:BackupA",
"authorizedActions": [
"vmwareCloudDirectorBackup:apiovh:get",
"vmwareCloudDirector:apiovh:organization/get",
"account:apiovh:iam/resource/edit",
"account:apiovh:service/terminate"
],
"unauthorizedActions": []
},
{
"resourceURN": "urn:v1:resource:vmwareCloudDirectorBackup:BackupB",
"authorizedActions": [],
"unauthorizedActions": [
"vmwareCloudDirectorBackup:apiovh:get",
"vmwareCloudDirector:apiovh:organization/get",
"account:apiovh:iam/resource/edit",
"account:apiovh:service/terminate"
]
}
]
15 changes: 15 additions & 0 deletions packages/manager/apps/veeam-backup/mocks/iam.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { PathParams } from 'msw';
import { Handler } from '../../../../../playwright-helpers';
import resourceList from './iam.json';

const findResourceByUrn = (params: PathParams) =>
resourceList.find(({ resourceURN }) => resourceURN === params.urn);

export const getIamMocks = (): Handler[] => [
{
url: '/iam/resource/:urn/authorization/check',
response: (_: unknown, params: PathParams) => findResourceByUrn(params),
api: 'v2',
method: 'post',
},
];
3 changes: 3 additions & 0 deletions packages/manager/apps/veeam-backup/mocks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './vcd-organization.mock';
export * from './veeam-backup.mock';
export * from './iam.mock';
Loading

0 comments on commit fdcf66a

Please sign in to comment.