Skip to content

Commit

Permalink
feat(key-management-service): add kms termination
Browse files Browse the repository at this point in the history
ref: MANAGER-13980

Signed-off-by: David Arsène <david.arsene.ext@ovhcloud.com>
  • Loading branch information
darsene committed May 27, 2024
1 parent f37f681 commit 4024c23
Show file tree
Hide file tree
Showing 16 changed files with 279 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import React from 'react';
import { terminateOKmsQueryKey, terminateOKms } from '../services/post';
import { getOkmsServiceId, getOkmsServiceIdQueryKey } from '../services/get';
import { getOkmsServicesResourceListQueryKey } from '../GET/apiv2/services';

export const useTerminateOKms = ({
kmsId,
onSuccess,
onError,
}: {
kmsId: string;
onSuccess?: () => void;
onError?: (result: ApiError) => void;
}) => {
const [isErrorVisible, setIsErrorVisible] = React.useState(false);
const queryClient = useQueryClient();

const {
mutate: terminateKms,
isPending,
error: terminateKmsError,
} = useMutation({
mutationKey: terminateOKmsQueryKey(kmsId),
mutationFn: async () => {
const { data: servicesId } = await queryClient.fetchQuery<
ApiResponse<number[]>
>({
queryKey: getOkmsServiceIdQueryKey({ okms: kmsId }),
queryFn: () => getOkmsServiceId({ okms: kmsId }),
});
return terminateOKms({ serviceId: servicesId[0] });
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: getOkmsServicesResourceListQueryKey,
});
onSuccess?.();
},
onError: (result: ApiError) => {
setIsErrorVisible(true);
onError?.(result);
},
});

return {
terminateKms,
isPending,
isErrorVisible: terminateKmsError && isErrorVisible,
error: terminateKmsError,
hideError: () => setIsErrorVisible(false),
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { apiClient } from '@ovh-ux/manager-core-api';

export type TerminateKmsParams = {
serviceId: number;
};

export const terminateOKmsQueryKey = (kms: string) => [`terminateKms-${kms}`];

/**
* Terminiate a kms
*/
export const terminateOKms = async ({ serviceId }: TerminateKmsParams) =>
apiClient.v6.post<{ message: string }>(`/services/${serviceId}/terminate`);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import {
useBreadcrumb,
BreadcrumbProps,
useBreadcrumb,
} from '@ovh-ux/manager-react-shell-client';
import { OsdsBreadcrumb } from '@ovhcloud/ods-components/react';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ODS_TEXT_COLOR_INTENT } from '@ovhcloud/ods-components';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { OKMS } from '@/interface';
import KmsActionMenu from '../menu/KmsActionMenu.component';

export const DatagridCellName = (props: OKMS) => {
const navigate = useNavigate();
Expand Down Expand Up @@ -41,3 +42,7 @@ export const DatagridCellRegion = (props: OKMS) => {
export const DatagridCellRestApiEndpoint = (props: OKMS) => {
return <OsdsLink href={props?.restEndpoint}>{props?.restEndpoint}</OsdsLink>;
};

export const DatagridActionMenu = (props: OKMS) => {
return <KmsActionMenu {...props} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { ApiError } from '@ovh-ux/manager-core-api';
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import {
ODS_BUTTON_TYPE,
ODS_BUTTON_VARIANT,
ODS_INPUT_TYPE,
ODS_MESSAGE_TYPE,
ODS_SPINNER_SIZE,
ODS_TEXT_LEVEL,
ODS_TEXT_SIZE,
OdsInputValueChangeEvent,
} from '@ovhcloud/ods-components';
import {
OsdsButton,
OsdsInput,
OsdsMessage,
OsdsModal,
OsdsSpinner,
OsdsText,
} from '@ovhcloud/ods-components/react';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { terminateValue } from './TerminateModal.constants';

export type TerminateModalProps = {
headline: string;
description?: string;
terminateInputButton: string;
closeModal: () => void;
isLoading?: boolean;
onConfirmTerminate: () => void;
error?: ApiError;
};

export const TerminateModal: React.FC<TerminateModalProps> = ({
headline,
description,
terminateInputButton,
closeModal,
isLoading,
onConfirmTerminate,
error,
}) => {
const { t } = useTranslation('key-management-service/terminate');
const [terminateInput, setTerminateInput] = useState('');

const close = () => {
setTerminateInput('');
closeModal();
};

return (
<OsdsModal
dismissible
color={ODS_THEME_COLOR_INTENT.warning}
headline={headline}
onOdsModalClose={close}
>
{!!error && (
<OsdsMessage type={ODS_MESSAGE_TYPE.error}>
<OsdsText
level={ODS_TEXT_LEVEL.body}
size={ODS_TEXT_SIZE._400}
color={ODS_THEME_COLOR_INTENT.text}
>
{t('key_management_service_terminate_error', {
error: error.response?.data?.message,
})}
</OsdsText>
</OsdsMessage>
)}
<OsdsText
color={ODS_THEME_COLOR_INTENT.text}
level={ODS_TEXT_LEVEL.body}
className="block mb-3"
>
{description}
</OsdsText>
<OsdsInput
disabled={isLoading || undefined}
type={ODS_INPUT_TYPE.text}
value={terminateInput}
onOdsValueChange={(e: OdsInputValueChangeEvent) =>
setTerminateInput(e.detail.value)
}
/>
{isLoading && <OsdsSpinner inline size={ODS_SPINNER_SIZE.md} />}
<OsdsButton
disabled={isLoading || undefined}
slot="actions"
type={ODS_BUTTON_TYPE.button}
variant={ODS_BUTTON_VARIANT.ghost}
color={ODS_THEME_COLOR_INTENT.primary}
onClick={close}
>
{t('key_management_service_terminate_cancel')}
</OsdsButton>
<OsdsButton
disabled={isLoading || terminateInput !== terminateValue || undefined}
slot="actions"
type={ODS_BUTTON_TYPE.button}
variant={ODS_BUTTON_VARIANT.flat}
color={ODS_THEME_COLOR_INTENT.primary}
onClick={() => {
setTerminateInput('');
onConfirmTerminate();
}}
>
{terminateInputButton}
</OsdsButton>
</OsdsModal>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const terminateValue = 'TERMINATE';
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ActionMenu, ActionMenuItem } from '@ovhcloud/manager-components';
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import React from 'react';
import { ODS_ICON_NAME } from '@ovhcloud/ods-components';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { OKMS } from '@/interface';
import { ROUTES_URLS } from '@/routes/routes.constants';

const KmsActionMenu: React.FC<OKMS> = ({ id }) => {
const { t } = useTranslation('key-management-service/listing');
const navigate = useNavigate();

const items: ActionMenuItem[] = [
{
id: 1,
label: t('key_management_service_listing_terminate'),
color: ODS_THEME_COLOR_INTENT.error,
onClick: () => {
navigate(`${ROUTES_URLS.terminateOkms}/${id}`);
},
},
];

return (
<ActionMenu
items={items}
isCompact
icon={ODS_ICON_NAME.ELLIPSIS_VERTICAL}
/>
);
};

export default KmsActionMenu;
2 changes: 1 addition & 1 deletion packages/manager/apps/key-management-service/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const init = async (appName: string) => {
context,
reloadOnLocaleChange: true,
defaultNS: appName,
ns: [`${appName}/listing`, `${appName}/dashboard`],
ns: [`${appName}/listing`, `${appName}/dashboard`, `${appName}/terminate`],
});

ReactDOM.createRoot(document.getElementById('root')!).render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default function DashboardPage() {
label: tListing('key_management_service_listing_title'),
},
{
href: ROUTES_URLS.dashboard,
href: `/${okmsId}`,
label: okmsId,
},
]}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate, useParams } from 'react-router-dom';
import { TerminateModal } from '@/components/Modal/terminate/TerminateModal.component';
import { useTerminateOKms } from '@/api/hooks/useTerminateOKms';

export default function TerminateKms() {
const { t } = useTranslation('key-management-service/terminate');
const navigate = useNavigate();
const { kmsId } = useParams();

const closeModal = () => {
navigate('..');
};

const { terminateKms, isErrorVisible, error } = useTerminateOKms({
kmsId,
onSuccess: closeModal,
});

return (
<TerminateModal
headline={t('key_management_service_terminate_heading')}
terminateInputButton={t('key_management_service_terminate_confirm')}
description={t('key_management_service_terminate_description')}
onConfirmTerminate={terminateKms}
closeModal={closeModal}
error={isErrorVisible ? error : null}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Outlet, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
ODS_SPINNER_SIZE,
Expand Down Expand Up @@ -28,6 +28,7 @@ import {
import { useOKMS } from '@/hooks/useOKMS';
import { ROUTES_URLS } from '@/routes/routes.constants';
import {
DatagridActionMenu,
DatagridCellId,
DatagridCellName,
DatagridCellRegion,
Expand Down Expand Up @@ -55,6 +56,12 @@ export default function Listing() {
cell: DatagridCellRegion,
label: t('key_management_service_listing_region_cell'),
},
{
id: 'action',
cell: DatagridActionMenu,
isSortable: false,
label: '',
},
];

const { sorting, setSorting } = useDatagridSearchParams();
Expand Down Expand Up @@ -125,6 +132,7 @@ export default function Listing() {
/>
</div>
)}
<Outlet />
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"key_management_service_listing_clipboard_error_label": "Erreur",
"key_management_service_listing_add_kms_button": "Commander un KMS",
"key_management_service_listing_title": "Mes KMS",
"key_management_service_listing_terminate": "Résilier",
"key_management_service_listing_region_eu_west_par": "Europe (France - Paris)",
"key_management_service_listing_region_eu_west_gra": "Europe (France - Gravelines)",
"key_management_service_listing_region_eu_west_rbx": "Europe (France - Roubaix)",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"key_management_service_terminate_cancel": "Annuler",
"key_management_service_terminate_confirm": "Résilier",
"key_management_service_terminate_error": "Une erreur est survenue. {{error}}",
"key_management_service_terminate_heading": "Résilier mon KMS",
"key_management_service_terminate_description": "Veuillez entrer le mot « TERMINATE » pour confirmer la résiliation de votre KMS"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ export const ROUTES_URLS = {
root: '/',
listing: '/',
onboarding: '/onboarding',
terminateOkms: '/terminate',
createKeyManagementService: '/create',
dashboard: '/:id',
overview: '/:id',
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export default [
{
path: ROUTES_URLS.listing,
...lazyRouteConfig(() => import('@/pages/listing')),
children: [
{
path: `${ROUTES_URLS.terminateOkms}/:okmsId`,
...lazyRouteConfig(() => import('@/pages/listing/TerminateKms')),
},
],
},
{
path: ROUTES_URLS.createKeyManagementService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export const SPECIAL_CONDITIONS_SUBSIDIARIES = ['US'];

export const TERMINATION_FORM_NAME = 'termination';

export const SERVICE_WITH_AGORA_TERMINATION = ['vrack-services'];
export const SERVICE_WITH_AGORA_TERMINATION = ['vrack-services', 'okms'];

export default {
SPECIAL_CONDITIONS_SUBSIDIARIES,
Expand Down

0 comments on commit 4024c23

Please sign in to comment.