Skip to content

Commit

Permalink
feat(key-management-service): add kms dashboard (#11664)
Browse files Browse the repository at this point in the history
ref: MANAGER-13567

Signed-off-by: Vincent BONMARCHAND <vincent.bonmarchand.ext@corp.ovh.com>
  • Loading branch information
vovh committed May 23, 2024
1 parent d5108ca commit 21a156f
Show file tree
Hide file tree
Showing 25 changed files with 676 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ export const getListingIceberg = async () => {
}
};

export const getOkmsResourceQueryKey = (okmsId: string) => [
`get/okms/resource/${okmsId}`,
];

export const getOkmsServicesResourceListQueryKey = ['get/okms/resource'];

export const sortOKMS = (okms: OKMS[], sorting: ColumnSort): OKMS[] => {
const data = [...okms];

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import apiClient from '@ovh-ux/manager-core-api';
import { OKMS } from '@/interface';

export const getOKMSResource = async (
okmsId: string,
): Promise<{ data: OKMS }> => {
return apiClient.v2.get(`okms/resource/${okmsId}`);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import React from 'react';
import { updateOkmsName, updateOkmsNameQueryKey } from '../services/put';
import { getOkmsServiceId, getOkmsServiceIdQueryKey } from '../services/get';
import { getOkmsServicesResourceListQueryKey } from '../GET/apiv2/services';

export type UpdateOkmsNameMutationParams = {
/** Okms service id */
okms: string;
/** Okms service new display name */
displayName: string;
};

/**
* Get the function to mutate a okms Services
*/
export const useUpdateOkmsName = ({
onSuccess,
onError,
}: {
onSuccess?: () => void;
onError?: (result: ApiError) => void;
}) => {
const [isErrorVisible, setIsErrorVisible] = React.useState(false);
const queryClient = useQueryClient();

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

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

export type GetOkmsServiceIdParams = {
/** Filter on a specific service family */
okms: string;
};

export const getOkmsServiceIdQueryKey = ({
okms = '',
}: GetOkmsServiceIdParams) => [`get/services${okms}`];
/**
* allowedServices operations : List all services allowed in this kms
*/
export const getOkmsServiceId = async ({ okms }: GetOkmsServiceIdParams) => {
const resourceName = okms ? `?resourceName=${okms}` : '';
return apiClient.v6.get<number[]>(`/services${resourceName}`);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './get';
export * from './put';
export * from '../hooks/useUpdateOkmsName';
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { apiClient } from '@ovh-ux/manager-core-api';

export type UpdateOkmsNameParams = {
serviceId: number;
displayName: string;
};

export const updateOkmsNameQueryKey = () => [`put/services/displayName`];

export const updateOkmsName = async ({
serviceId,
displayName,
}: UpdateOkmsNameParams) =>
apiClient.v6.put(`/services/${serviceId}`, {
displayName,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import {
useBreadcrumb,
BreadcrumbProps,
} from '@ovh-ux/manager-react-shell-client';
import { OsdsBreadcrumb } from '@ovhcloud/ods-components/react';

function Breadcrumb({ rootLabel }: BreadcrumbProps): JSX.Element {
const breadcrumbItems = useBreadcrumb({
rootLabel,
appName: 'key-management-service',
});

return <OsdsBreadcrumb items={breadcrumbItems} />;
}

export default Breadcrumb;
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,26 @@ import {
DataGridClipboardCell,
DataGridTextCell,
} from '@ovhcloud/manager-components';
import { OsdsLink } from '@ovhcloud/ods-components/react';
import { ODS_TEXT_COLOR_INTENT } from '@ovhcloud/ods-components';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { OKMS } from '@/interface';

export const DatagridCellName = (props: OKMS) => {
return <DataGridTextCell>{props.iam.displayName}</DataGridTextCell>;
const navigate = useNavigate();
return (
<div>
<OsdsLink
onClick={() => {
navigate(`/${props?.id}`);
}}
color={ODS_TEXT_COLOR_INTENT.primary}
>
{props?.iam.displayName}
</OsdsLink>
</div>
);
};

export const DatagridCellId = (props: OKMS) => {
Expand All @@ -22,3 +37,7 @@ export const DatagridCellRegion = (props: OKMS) => {
</DataGridTextCell>
);
};

export const DatagridCellRestApiEndpoint = (props: OKMS) => {
return <OsdsLink href={props?.restEndpoint}>{props?.restEndpoint}</OsdsLink>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
OsdsButton,
OsdsInput,
OsdsText,
} from '@ovhcloud/ods-components/react';
import {
ODS_INPUT_TYPE,
ODS_TEXT_LEVEL,
ODS_TEXT_SIZE,
OsdsInputCustomEvent,
OdsInputValueChangeEventDetail,
ODS_BUTTON_VARIANT,
} from '@ovhcloud/ods-components';

import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import React, { useState } from 'react';

import { useTranslation } from 'react-i18next';
import { isValidOkmsName } from '@/utils';
import Modal from './Modal';
import { OKMS } from '@/interface';

interface DeleteModalProps {
okms: OKMS;
toggleModal: (showModal: boolean) => void;
onEditName: (okms: OKMS) => void;
}

const EditNameModal = ({ okms, toggleModal, onEditName }: DeleteModalProps) => {
const { t } = useTranslation('key-management-service/dashboard');
const [newName, setNewName] = useState(okms.iam?.displayName || '');
const isValidName = isValidOkmsName(newName);
const isButtonValid = okms.iam?.displayName !== newName && isValidName;

const onEdit = () => {
if (isButtonValid) {
onEditName({
...okms,
iam: {
...okms.iam,
displayName: newName,
},
} as OKMS);
toggleModal(false);
}
};
return (
<Modal
color={ODS_THEME_COLOR_INTENT.info}
onClose={() => toggleModal(false)}
>
<OsdsText
color={ODS_THEME_COLOR_INTENT.text}
level={ODS_TEXT_LEVEL.heading}
size={ODS_TEXT_SIZE._400}
className="my-4"
>
{t('key_management_service_dashboard_modal_title')}
</OsdsText>
<OsdsInput
aria-label="edit-input"
type={ODS_INPUT_TYPE.text}
color={
isValidName
? ODS_THEME_COLOR_INTENT.info
: ODS_THEME_COLOR_INTENT.error
}
className="p-3"
value={newName}
onOdsValueChange={(
e: OsdsInputCustomEvent<OdsInputValueChangeEventDetail>,
) => setNewName(e.target.value as string)}
/>
<OsdsButton
slot="actions"
variant={ODS_BUTTON_VARIANT.stroked}
color={ODS_THEME_COLOR_INTENT.primary}
onClick={() => {
toggleModal(false);
}}
>
{t('key_management_service_dashboard_modal_cta_cancel')}
</OsdsButton>
<OsdsButton
disabled={!isButtonValid || undefined}
slot="actions"
color={ODS_THEME_COLOR_INTENT.primary}
onClick={onEdit}
aria-label="edit-name-okms"
>
{t('key_management_service_dashboard_modal_cta_edit')}
</OsdsButton>
</Modal>
);
};

export default EditNameModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import { OsdsModal } from '@ovhcloud/ods-components/react';
import React, { useRef } from 'react';

const Modal: React.FC<React.PropsWithChildren & {
onClose: () => void;
color: ODS_THEME_COLOR_INTENT;
}> = ({ color, onClose, children }) => {
const modal = useRef<HTMLOsdsModalElement>(null);

const onOdsModalClose = () => {
onClose();
modal.current?.close();
};

return (
<OsdsModal
color={color}
dismissible
onOdsModalClose={onOdsModalClose}
ref={modal}
>
{children}
</OsdsModal>
);
};

export default Modal;
Loading

0 comments on commit 21a156f

Please sign in to comment.