Skip to content

Commit

Permalink
feat(*): add create kms feature
Browse files Browse the repository at this point in the history
ref: MANAGER-13566

Signed-off-by: Vincent BONMARCHAND <vincent.bonmarchand.ext@corp.ovh.com>
  • Loading branch information
vovh committed May 14, 2024
1 parent 13bb098 commit 9be1360
Show file tree
Hide file tree
Showing 10 changed files with 432 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,34 @@ export const sortOKMS = (okms: OKMS[], sorting: ColumnSort): OKMS[] => {

return data;
};

type OKMSCatalogPlanConfiguration = {
isCustom: boolean;
isMandatory: boolean;
name: string;
values: string[];
};

type OKMSCatalogPlan = {
configurations: OKMSCatalogPlanConfiguration[];
};

export type ErrorResponse = {
response: {
status: number;
data: { message: string };
};
};

export type OKMSCatalog = {
plans: OKMSCatalogPlan[];
};

export const getOrderCatalogOKMS = async (
ovhSubsidiary: string,
): Promise<OKMSCatalog> => {
const { data } = await apiClient.v6.get<OKMSCatalog>(
`/order/catalog/public/okms?ovhSubsidiary=${ovhSubsidiary}`,
);
return data;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React, { useState, useEffect } from 'react';
import { useOrderURL } from '@ovh-ux/manager-module-order';
import {
OsdsText,
OsdsButton,
OsdsLink,
OsdsIcon,
OsdsTile,
} from '@ovhcloud/ods-components/react';
import {
ODS_BUTTON_SIZE,
ODS_BUTTON_VARIANT,
ODS_ICON_SIZE,
ODS_ICON_NAME,
ODS_LINK_REFERRER_POLICY,
} from '@ovhcloud/ods-components';
import {
ODS_THEME_COLOR_INTENT,
ODS_THEME_TYPOGRAPHY_SIZE,
ODS_THEME_TYPOGRAPHY_LEVEL,
} from '@ovhcloud/ods-common-theming';
import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { ROUTES_URLS } from '@/routes/routes.constants';
import { getKMSExpressOrderLink } from './order-utils';

type OrderConfirmationProps = {
region: string;
};

const OrderConfirmation = ({ region }: OrderConfirmationProps) => {
const { t } = useTranslation('key-management-service/create');
const [orderLink, setOrderLink] = useState(null);
const orderBaseUrl = useOrderURL('express_review_base');
const navigate = useNavigate();

const generateExpressOrderLink = () => {
setOrderLink(getKMSExpressOrderLink({ orderBaseUrl, region }));
};

useEffect(() => {
generateExpressOrderLink();
}, [region]);

useEffect(() => {
if (orderLink) {
window.open(orderLink, '_blank', 'noopener,noreferrer');
}
}, [orderLink]);

return (
<>
<OsdsTile className="mb-6">
<span slot="start">
<div className="flex flex-col gap-6 mb-6">
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.heading}
size={ODS_THEME_TYPOGRAPHY_SIZE._600}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_create_order_initiated_title')}
</OsdsText>
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.subheading}
size={ODS_THEME_TYPOGRAPHY_SIZE._800}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_create_order_initiated_subtitle')}
</OsdsText>
<OsdsLink
color={ODS_THEME_COLOR_INTENT.primary}
target={OdsHTMLAnchorElementTarget._blank}
referrerpolicy={
ODS_LINK_REFERRER_POLICY.strictOriginWhenCrossOrigin
}
href={orderLink}
>
{orderLink}
<span slot="end">
<OsdsIcon
className="ml-4 cursor-pointer"
name={ODS_ICON_NAME.EXTERNAL_LINK}
size={ODS_ICON_SIZE.xs}
hoverable
></OsdsIcon>
</span>
</OsdsLink>
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.subheading}
size={ODS_THEME_TYPOGRAPHY_SIZE._800}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_create_order_initiated_info')}
</OsdsText>
</div>
</span>
</OsdsTile>
<OsdsButton
inline
size={ODS_BUTTON_SIZE.md}
variant={ODS_BUTTON_VARIANT.flat}
color={ODS_THEME_COLOR_INTENT.primary}
onClick={() => {
navigate(ROUTES_URLS.root);
}}
>
{t('key_management_service_create_order_initiated_cta_done')}
</OsdsButton>
</>
);
};

export default OrderConfirmation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import React, { useContext, Dispatch, SetStateAction, Suspense } from 'react';
import { useTranslation } from 'react-i18next';
import {
OsdsText,
OsdsSelect,
OsdsSelectOption,
OsdsFormField,
OsdsButton,
OsdsIcon,
OsdsSpinner,
} from '@ovhcloud/ods-components/react';

import {
ODS_SPINNER_SIZE,
ODS_ICON_SIZE,
ODS_ICON_NAME,
ODS_BUTTON_SIZE,
ODS_BUTTON_VARIANT,
ODS_SELECT_SIZE,
} from '@ovhcloud/ods-components';
import {
ODS_THEME_COLOR_INTENT,
ODS_THEME_TYPOGRAPHY_SIZE,
ODS_THEME_TYPOGRAPHY_LEVEL,
} from '@ovhcloud/ods-common-theming';
import { ShellContext } from '@ovh-ux/manager-react-shell-client';
import { useNavigate } from 'react-router-dom';
import { ErrorBanner } from '@ovhcloud/manager-components';
import { useOrderCatalogOKMS } from '@/hooks/useOrderCatalogOKMS';
import { ROUTES_URLS } from '@/routes/routes.constants';

export type RegionSelectorProps = {
setOrderInitiated: () => void;
selectRegion: Dispatch<SetStateAction<string>>;
selectedRegion: string | null;
};

const RegionSelector = ({
setOrderInitiated,
selectRegion,
selectedRegion,
}: RegionSelectorProps) => {
const { t } = useTranslation('key-management-service/create');
const { environment } = useContext(ShellContext);
const {
data: orderCatalogOKMS,
isError,
error,
isLoading,
} = useOrderCatalogOKMS(environment.getUser().ovhSubsidiary);
const navigate = useNavigate();

if (isError && error) {
return (
<Suspense>
<ErrorBanner error={error.response} />
</Suspense>
);
}
return (
<>
<div className="flex flex-col gap-6">
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.heading}
size={ODS_THEME_TYPOGRAPHY_SIZE._600}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_create_region_title')}
</OsdsText>
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.body}
size={ODS_THEME_TYPOGRAPHY_SIZE._400}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_create_region_description')}
</OsdsText>

<OsdsFormField inline className="mb-5">
<div slot="label">
{isLoading && (
<OsdsSpinner className="mr-3" inline size={ODS_SPINNER_SIZE.sm} />
)}
</div>
{orderCatalogOKMS && !isLoading && (
<OsdsSelect
inline
size={ODS_SELECT_SIZE.md}
onOdsValueChange={(v) => {
selectRegion(v.detail.value.toString());
}}
>
<span slot="placeholder">
{t('key_management_service_create_select_placeholder')}
</span>
{orderCatalogOKMS.plans[0].configurations[0].values.map(
(region) => {
return (
<OsdsSelectOption value={region} key={region}>
{t(
`key_management_service_create_region_${region.toLowerCase()}`,
)}
</OsdsSelectOption>
);
},
)}
</OsdsSelect>
)}
</OsdsFormField>
</div>
<div className="flex flex-row mt-6">
<OsdsButton
className="mr-1"
size={ODS_BUTTON_SIZE.sm}
variant={ODS_BUTTON_VARIANT.stroked}
color={ODS_THEME_COLOR_INTENT.primary}
onClick={() => {
navigate(ROUTES_URLS.root);
}}
>
{t('key_management_service_create_cta_cancel')}
</OsdsButton>
<OsdsButton
className="mr-1"
size={ODS_BUTTON_SIZE.sm}
variant={ODS_BUTTON_VARIANT.flat}
color={ODS_THEME_COLOR_INTENT.primary}
disabled={selectedRegion ? undefined : true}
onClick={() => {
setOrderInitiated();
}}
>
<span slot="start">
<OsdsIcon
name={ODS_ICON_NAME.EXTERNAL_LINK}
size={ODS_ICON_SIZE.xs}
contrasted
></OsdsIcon>
</span>
{t('key_management_service_create_cta_order')}
</OsdsButton>
</div>
</>
);
};

export default RegionSelector;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getKMSProductSettings } from '@ovh-ux/manager-module-order';

export const getKMSExpressOrderLink = ({
orderBaseUrl,
region,
}: {
orderBaseUrl: string;
region: string;
}) => {
const KMSOrder = getKMSProductSettings({ region });
return `${orderBaseUrl}?products=~(${KMSOrder})`;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useQuery } from '@tanstack/react-query';
import { ErrorResponse, OKMSCatalog, getOrderCatalogOKMS } from '@/api';

export type OrderCatalogProps = {
ovhSubsidiary: string;
};

export const useOrderCatalogOKMS = (ovhSubsidiary: string) => {
return useQuery<OKMSCatalog, ErrorResponse>({
queryKey: ['order/catalog/public/okms', ovhSubsidiary],
queryFn: () => getOrderCatalogOKMS(ovhSubsidiary),
retry: false,
...{
keepPreviousData: true,
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useState } from 'react';
import {
OsdsText,
OsdsDivider,
OsdsBreadcrumb,
} from '@ovhcloud/ods-components/react';

import { Notifications } from '@ovhcloud/manager-components';
import {
ODS_THEME_COLOR_INTENT,
ODS_THEME_TYPOGRAPHY_SIZE,
ODS_THEME_TYPOGRAPHY_LEVEL,
} from '@ovhcloud/ods-common-theming';
import { useTranslation } from 'react-i18next';
import { ROUTES_URLS } from '@/routes/routes.constants';
import RegionSelector from '@/components/layout-helpers/Create/RegionSelector';
import OrderConfirmation from '@/components/layout-helpers/Create/OrderConfirmation';

export default function Create() {
const { t } = useTranslation('key-management-service/create');
const [isOrderInitiated, setIsOrderInitiated] = useState(false);
const [selectedRegion, setSelectedRegion] = useState(undefined);
return (
<>
<OsdsBreadcrumb
items={[
{
href: ROUTES_URLS.listing,
label: t('key_management_service_create_title'),
},
]}
></OsdsBreadcrumb>
<div className={'flex items-center justify-between mt-4 mb-2'}>
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.heading}
size={ODS_THEME_TYPOGRAPHY_SIZE._600}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_create_title')}
</OsdsText>
</div>
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.subheading}
size={ODS_THEME_TYPOGRAPHY_SIZE._800}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_create_subtitle')}
</OsdsText>
<OsdsDivider></OsdsDivider>
<Notifications />
{!isOrderInitiated ? (
<RegionSelector
setOrderInitiated={() => {
setIsOrderInitiated(true);
}}
selectRegion={setSelectedRegion}
selectedRegion={selectedRegion}
/>
) : (
<OrderConfirmation region={selectedRegion} />
)}
</>
);
}
Loading

0 comments on commit 9be1360

Please sign in to comment.