-
+
setEditModalDisplayed(true)}
+ onClick={() => navigate('update-name')}
>
setEditModalDisplayed(true)}
name={ODS_ICON_NAME.PEN}
size={ODS_ICON_SIZE.xs}
color={ODS_THEME_COLOR_INTENT.primary}
@@ -113,6 +106,7 @@ const InformationsTile = ({ okmsData }: InformationTileProps) => {
{okmsData?.swaggerEndpoint}
+
);
};
diff --git a/packages/manager/apps/key-management-service/src/components/serviceKey/serviceKeyStateActions/ServiceKeyStateActions.component.tsx b/packages/manager/apps/key-management-service/src/components/serviceKey/serviceKeyStateActions/ServiceKeyStateActions.component.tsx
index f12ca98cb561..8fd659428096 100644
--- a/packages/manager/apps/key-management-service/src/components/serviceKey/serviceKeyStateActions/ServiceKeyStateActions.component.tsx
+++ b/packages/manager/apps/key-management-service/src/components/serviceKey/serviceKeyStateActions/ServiceKeyStateActions.component.tsx
@@ -1,5 +1,6 @@
-import { OsdsIcon, OsdsButton } from '@ovhcloud/ods-components/react';
import React from 'react';
+import { OsdsIcon, OsdsButton } from '@ovhcloud/ods-components/react';
+import { ManagerButton } from '@ovh-ux/manager-react-components';
import {
ODS_BUTTON_SIZE,
ODS_BUTTON_TEXT_ALIGN,
@@ -9,9 +10,10 @@ import {
} from '@ovhcloud/ods-components';
import { OkmsAllServiceKeys } from '@/types/okmsServiceKey.type';
import useServiceKeyActionsList from '@/hooks/serviceKey/useServiceKeyActionsList';
+import { OKMS } from '@/types/okms.type';
type ServiceKeyStateActionsProps = {
- okmsId: string;
+ okms: OKMS;
okmsKey: OkmsAllServiceKeys;
};
@@ -23,38 +25,62 @@ const ActionsIcons = [
];
const ServiceKeyStateActions = ({
- okmsId,
+ okms,
okmsKey,
}: ServiceKeyStateActionsProps) => {
- const actionList = useServiceKeyActionsList(okmsId, okmsKey);
+ const actionList = useServiceKeyActionsList(okms, okmsKey);
const getActionIcon = (id: number) => {
return ActionsIcons.find((actionIcon) => actionIcon.id === id)?.icon;
};
return (
<>
- {actionList.map((action) => (
-
- {action.label}
-
-
-
-
- ))}
+ {actionList.map((action) => {
+ return action.iamActions ? (
+
+ {action.label}
+
+
+
+
+ ) : (
+
+ {action.label}
+
+
+
+
+ );
+ })}
>
);
};
diff --git a/packages/manager/apps/key-management-service/src/data/api/okms.ts b/packages/manager/apps/key-management-service/src/data/api/okms.ts
index caa5e0f830f9..f5f9865186f8 100644
--- a/packages/manager/apps/key-management-service/src/data/api/okms.ts
+++ b/packages/manager/apps/key-management-service/src/data/api/okms.ts
@@ -92,20 +92,6 @@ export const getListingIcebergV2 = async ({
}
};
-/**
- * Get okms listing with iceberg V2
- */
-export const getListingIceberg = async () => {
- try {
- const List = await fetchIcebergV2({
- route: '/okms/resource',
- });
- return List.data as OKMS[];
- } catch (error) {
- return null;
- }
-};
-
export const getOkmsResourceQueryKey = (okmsId: string) => [
`get/okms/resource/${okmsId}`,
];
diff --git a/packages/manager/apps/key-management-service/src/data/api/okmsService.ts b/packages/manager/apps/key-management-service/src/data/api/okmsService.ts
index 8f60cff29731..de066437a23e 100644
--- a/packages/manager/apps/key-management-service/src/data/api/okmsService.ts
+++ b/packages/manager/apps/key-management-service/src/data/api/okmsService.ts
@@ -16,24 +16,20 @@ export const updateOkmsName = async ({
displayName,
});
-export type GetOkmsServiceIdParams = {
- /** Filter on a specific service family */
- okms: string;
-};
-
-export const getOkmsServiceIdQueryKey = ({
- okms = '',
-}: GetOkmsServiceIdParams) => [`get/services${okms}`];
+export const getOkmsServiceIdQueryKey = (okmsId: string) => [
+ `get/okms/services`,
+ okmsId,
+];
/**
* allowedServices operations : List all services allowed in this kms
*/
-export const getOkmsServiceId = async ({ okms }: GetOkmsServiceIdParams) => {
- const resourceName = okms ? `?resourceName=${okms}` : '';
+export const getOkmsServiceId = async (okmsId: string) => {
+ const resourceName = okmsId ? `?resourceName=${okmsId}` : '';
return apiClient.v6.get(`/services${resourceName}`);
};
-export const getServiceInfos = async ({ okms }: GetOkmsServiceIdParams) => {
- const serviceId = await getOkmsServiceId({ okms });
+export const getServiceInfos = async (okmsId: string) => {
+ const serviceId = await getOkmsServiceId(okmsId);
return apiClient.v6.get(`/services/${serviceId.data[0]}`);
};
diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useKMSServiceInfos.ts b/packages/manager/apps/key-management-service/src/data/hooks/useKMSServiceInfos.ts
index acc26a7515bf..c637da680dd6 100644
--- a/packages/manager/apps/key-management-service/src/data/hooks/useKMSServiceInfos.ts
+++ b/packages/manager/apps/key-management-service/src/data/hooks/useKMSServiceInfos.ts
@@ -1,16 +1,16 @@
import { useQuery } from '@tanstack/react-query';
-import { OKMS } from '@/types/okms.type';
import { ErrorResponse } from '@/types/api.type';
import { KMSServiceInfos } from '@/types/okmsService.type';
import { getServiceInfos } from '../api/okmsService';
-export const useKMSServiceInfos = (okms?: OKMS) => {
+export const getKMSServiceInfosQueryKey = (okmsId: string) => [
+ 'okms/service/infos',
+ okmsId,
+];
+export const useKMSServiceInfos = (okmId?: string) => {
return useQuery<{ data: KMSServiceInfos }, ErrorResponse>({
- queryKey: ['okms/service/infos', okms?.id],
- queryFn: () => getServiceInfos({ okms: okms?.id }),
+ queryKey: getKMSServiceInfosQueryKey(okmId),
+ queryFn: () => getServiceInfos(okmId),
retry: false,
- ...{
- keepPreviousData: true,
- },
});
};
diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useOKMS.ts b/packages/manager/apps/key-management-service/src/data/hooks/useOKMS.ts
index 2a326e9bf6de..6e254e0ed428 100644
--- a/packages/manager/apps/key-management-service/src/data/hooks/useOKMS.ts
+++ b/packages/manager/apps/key-management-service/src/data/hooks/useOKMS.ts
@@ -1,13 +1,12 @@
import { useQuery } from '@tanstack/react-query';
import apiClient from '@ovh-ux/manager-core-api';
+import { useResourcesIcebergV2 } from '@ovh-ux/manager-react-components';
-import { OKMS, OKMSOptions } from '@/types/okms.type';
+import { OKMS } from '@/types/okms.type';
import { ErrorResponse } from '@/types/api.type';
import {
- getListingIceberg,
getOkmsResourceQueryKey,
getOkmsServicesResourceListQueryKey,
- sortOKMS,
} from '../api/okms';
export const getOKMSResource = async (
@@ -16,18 +15,6 @@ export const getOKMSResource = async (
return apiClient.v2.get(`okms/resource/${okmsId}`);
};
-export const useAllOKMS = () => {
- return useQuery({
- queryKey: getOkmsServicesResourceListQueryKey,
- queryFn: () => getListingIceberg(),
- retry: false,
- ...{
- keepPreviousData: true,
- },
- refetchInterval: 5000,
- });
-};
-
export const useOKMSById = (okmsId: string) => {
return useQuery<{ data: OKMS }, ErrorResponse>({
queryKey: getOkmsResourceQueryKey(okmsId),
@@ -36,21 +23,12 @@ export const useOKMSById = (okmsId: string) => {
...{
keepPreviousData: true,
},
- refetchInterval: 5000,
});
};
-export const useOKMS = ({ sorting }: OKMSOptions) => {
- // retrieve All OKMS from API
- const {
- data: okms,
- error: allOKMSError,
- isLoading: allOKMSLoading,
- } = useAllOKMS();
-
- return {
- isLoading: allOKMSLoading,
- error: allOKMSError,
- data: sortOKMS(okms || [], sorting),
- };
-};
+export const useOKMSList = ({ pageSize }: { pageSize?: number }) =>
+ useResourcesIcebergV2({
+ route: '/okms/resource',
+ queryKey: getOkmsServicesResourceListQueryKey,
+ pageSize,
+ });
diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useOkmsServiceKeys.ts b/packages/manager/apps/key-management-service/src/data/hooks/useOkmsServiceKeys.ts
index b4f06145fce3..814af9dba6fd 100644
--- a/packages/manager/apps/key-management-service/src/data/hooks/useOkmsServiceKeys.ts
+++ b/packages/manager/apps/key-management-service/src/data/hooks/useOkmsServiceKeys.ts
@@ -1,5 +1,6 @@
import { useQuery } from '@tanstack/react-query';
+import { ApiError } from '@ovh-ux/manager-core-api';
import { ErrorResponse } from '@/types/api.type';
import {
getOkmsServiceKeyResource,
@@ -16,7 +17,7 @@ import {
/* Service Key List */
export const useAllOkmsServiceKeys = (okmsId: string) => {
- return useQuery({
+ return useQuery<{ data: OkmsAllServiceKeys[] }, ApiError>({
queryKey: getOkmsServiceKeyResourceListQueryKey(okmsId),
queryFn: () => getListingOkmsServiceKey(okmsId),
retry: false,
diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useTerminateOKms.ts b/packages/manager/apps/key-management-service/src/data/hooks/useTerminateOKms.ts
index d45109ddbc96..a862377f09d9 100644
--- a/packages/manager/apps/key-management-service/src/data/hooks/useTerminateOKms.ts
+++ b/packages/manager/apps/key-management-service/src/data/hooks/useTerminateOKms.ts
@@ -29,8 +29,8 @@ export const useTerminateOKms = ({
const { data: servicesId } = await queryClient.fetchQuery<
ApiResponse
>({
- queryKey: getOkmsServiceIdQueryKey({ okms: okmsId }),
- queryFn: () => getOkmsServiceId({ okms: okmsId }),
+ queryKey: getOkmsServiceIdQueryKey(okmsId),
+ queryFn: () => getOkmsServiceId(okmsId),
});
return terminateOKms({ serviceId: servicesId[0] });
},
diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useUpdateOkmsName.ts b/packages/manager/apps/key-management-service/src/data/hooks/useUpdateOkmsName.ts
index e153e4996f2c..8a7471075431 100644
--- a/packages/manager/apps/key-management-service/src/data/hooks/useUpdateOkmsName.ts
+++ b/packages/manager/apps/key-management-service/src/data/hooks/useUpdateOkmsName.ts
@@ -1,14 +1,24 @@
import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api';
import { useMutation, useQueryClient } from '@tanstack/react-query';
-import React from 'react';
-import { getOkmsServicesResourceListQueryKey } from '../api/okms';
+import { useTranslation } from 'react-i18next';
+import { useNotifications } from '@ovh-ux/manager-react-components';
+import {
+ getOkmsResourceQueryKey,
+ getOkmsServicesResourceListQueryKey,
+} from '../api/okms';
import {
updateOkmsNameQueryKey,
getOkmsServiceIdQueryKey,
getOkmsServiceId,
updateOkmsName,
} from '../api/okmsService';
+import { getKMSServiceInfosQueryKey } from './useKMSServiceInfos';
+export type UpdateOkmsParams = {
+ okmsId: string;
+ onSuccess: () => void;
+ onError?: (result: ApiError) => void;
+};
export type UpdateOkmsNameMutationParams = {
/** Okms service id */
okms: string;
@@ -20,14 +30,13 @@ export type UpdateOkmsNameMutationParams = {
* Get the function to mutate a okms Services
*/
export const useUpdateOkmsName = ({
+ okmsId,
onSuccess,
onError,
-}: {
- onSuccess?: () => void;
- onError?: (result: ApiError) => void;
-}) => {
- const [isErrorVisible, setIsErrorVisible] = React.useState(false);
+}: UpdateOkmsParams) => {
const queryClient = useQueryClient();
+ const { t } = useTranslation('key-management-service/serviceKeys');
+ const { addError, addSuccess, clearNotifications } = useNotifications();
const {
mutate: updateKmsName,
@@ -39,19 +48,36 @@ export const useUpdateOkmsName = ({
const { data: servicesId } = await queryClient.fetchQuery<
ApiResponse
>({
- queryKey: getOkmsServiceIdQueryKey({ okms }),
- queryFn: () => getOkmsServiceId({ okms }),
+ queryKey: getOkmsServiceIdQueryKey(okms),
+ queryFn: () => getOkmsServiceId(okms),
});
return updateOkmsName({ serviceId: servicesId[0], displayName });
},
- onSuccess: () => {
- queryClient.invalidateQueries({
+ onSuccess: async () => {
+ await queryClient.invalidateQueries({
queryKey: getOkmsServicesResourceListQueryKey,
});
+ await queryClient.invalidateQueries({
+ queryKey: getKMSServiceInfosQueryKey(okmsId),
+ });
+ await queryClient.invalidateQueries({
+ queryKey: getOkmsResourceQueryKey(okmsId),
+ });
+ clearNotifications();
+ addSuccess(
+ t('key_management_service_service-keys_update_name_success'),
+ true,
+ );
onSuccess?.();
},
onError: (result: ApiError) => {
- setIsErrorVisible(true);
+ clearNotifications();
+ addError(
+ t('key_management_service_service-keys_update_error', {
+ error: result.message,
+ }),
+ true,
+ );
onError?.(result);
},
});
@@ -59,8 +85,6 @@ export const useUpdateOkmsName = ({
return {
updateKmsName,
isPending,
- isErrorVisible: updateNameError && isErrorVisible,
error: updateNameError,
- hideError: () => setIsErrorVisible(false),
};
};
diff --git a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActions.spec.tsx b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActions.spec.tsx
index 2664b2ab4b64..ad674f1fcf08 100644
--- a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActions.spec.tsx
+++ b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActions.spec.tsx
@@ -1,8 +1,13 @@
import { describe, expect, it, vi } from 'vitest';
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import { renderHook } from '@testing-library/react';
-import { OkmsKeyTypes, OkmsServiceKeyState } from '@/types/okmsServiceKey.type';
+import {
+ OkmsAllServiceKeys,
+ OkmsKeyTypes,
+ OkmsServiceKeyState,
+} from '@/types/okmsServiceKey.type';
import useServiceKeyActionsList from './useServiceKeyActionsList';
+import { OKMS } from '@/types/okms.type';
vi.mock('react-i18next', () => ({
useTranslation: vi.fn(() => ({ t: vi.fn((key) => key) })),
@@ -31,13 +36,25 @@ vi.mock('@/data/hooks/useUpdateOkmsServiceKey', () => ({
}));
describe('useServiceKeyActionsList', () => {
- const okmsId = 'testOkmsId';
- const commonKeyProps = {
+ const okms: OKMS = {
+ iam: {
+ displayName: 'kms-1',
+ id: '1b4e7c8e-d1b8-4b46-a584-52c8b4b0225c',
+ urn: `urn:v1:eu:resource:okms:1b4e7c8e-d1b8-4b46-a584-52c8b4b0225c`,
+ },
+ id: '7f3a82ac-a8d8-4c2a-ab0c-f6e86ddf6a7c',
+ kmipEndpoint: 'eu-west-rbx.okms.ovh.net:1234',
+ region: 'EU_WEST_RBX',
+ restEndpoint: 'https://eu-west-rbx.okms.ovh.net',
+ swaggerEndpoint: '"https://swagger-eu-west-rbx.okms.ovh.net',
+ };
+
+ const commonKeyProps: Omit = {
id: 'testKeyId',
name: 'testKeyName',
- keys: [] as any[],
+ keys: [],
createdAt: '2023-01-01T00:00:00Z',
- operations: [] as any[],
+ operations: [],
};
const useCases = [
@@ -171,7 +188,7 @@ describe('useServiceKeyActionsList', () => {
useCases.forEach(({ description, okmsKey, expectedActions }) => {
it(description, () => {
const { result } = renderHook(() =>
- useServiceKeyActionsList(okmsId, okmsKey),
+ useServiceKeyActionsList(okms, okmsKey),
);
expect(result.current).toEqual(
expect.arrayContaining(
diff --git a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActionsList.tsx b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActionsList.tsx
index 2f696ab258ee..03b7d9cd568e 100644
--- a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActionsList.tsx
+++ b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyActionsList.tsx
@@ -13,9 +13,10 @@ import {
OkmsKeyTypes,
OkmsServiceKeyState,
} from '@/types/okmsServiceKey.type';
+import { OKMS } from '@/types/okms.type';
const useServiceKeyActionsList = (
- okmsId: string,
+ okms: OKMS,
okmsKey?: OkmsAllServiceKeys,
isListMode?: boolean,
) => {
@@ -26,10 +27,10 @@ const useServiceKeyActionsList = (
deleteKmsServiceKey,
isPending: deleteIsPending,
} = useDeleteOkmsServiceKey({
- okmsId,
+ okmsId: okms.id,
keyId: okmsKey?.id,
onSuccess: () => {
- navigate(`/${okmsId}/${ROUTES_URLS.keys}`);
+ navigate(`/${okms.id}/${ROUTES_URLS.keys}`);
},
onError: () => {},
});
@@ -38,7 +39,7 @@ const useServiceKeyActionsList = (
updateKmsServiceKey,
isPending: updateIsPending,
} = useUpdateOkmsServiceKey({
- okmsId,
+ okmsId: okms.id,
keyId: okmsKey?.id,
onSuccess: () => {
addSuccess(
@@ -72,9 +73,11 @@ const useServiceKeyActionsList = (
return isListMode
? navigate(`${ROUTES_URLS.serviceKeyDeactivate}/${okmsKey?.id}`)
: navigate(
- `/${okmsId}/${ROUTES_URLS.keys}/${okmsKey?.id}/${ROUTES_URLS.serviceKeyDeactivate}`,
+ `/${okms.id}/${ROUTES_URLS.keys}/${okmsKey?.id}/${ROUTES_URLS.serviceKeyDeactivate}`,
);
},
+ iamActions: ['okms:apiovh:resource/serviceKey/deactivate'],
+ urn: okms.iam.urn,
});
}
if (
@@ -87,6 +90,8 @@ const useServiceKeyActionsList = (
color: ODS_THEME_COLOR_INTENT.primary,
disabled: updateIsPending,
onClick: () => updateKmsServiceKey({ state: OkmsServiceKeyState.active }),
+ iamActions: ['okms:apiovh:resource/serviceKey/activate'],
+ urn: okms.iam.urn,
});
}
if (
@@ -100,6 +105,8 @@ const useServiceKeyActionsList = (
disabled:
okmsKey?.state === OkmsServiceKeyState.active || deleteIsPending,
onClick: () => deleteKmsServiceKey(),
+ iamActions: ['okms:apiovh:resource/serviceKey/delete'],
+ urn: okms.iam.urn,
});
}
return items;
diff --git a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyOperationsTranslations.spec.tsx b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyOperationsTranslations.spec.tsx
index c5a30fe9462c..13b98ec1e7d9 100644
--- a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyOperationsTranslations.spec.tsx
+++ b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyOperationsTranslations.spec.tsx
@@ -1,7 +1,16 @@
-import { describe, expect, it, test } from 'vitest';
+import { describe, expect, it, test, vi } from 'vitest';
import { OkmsServiceKeyOperations } from '@/types/okmsServiceKey.type';
import { useServiceKeyOperationsTranslations } from './useServiceKeyOperationsTranslations';
+vi.mock('react-i18next', () => ({
+ useTranslation: () => ({
+ t: (translationKey: string) => translationKey,
+ i18n: {
+ changeLanguage: () => new Promise(() => {}),
+ },
+ }),
+}));
+
describe('get service key operations translation ', () => {
const useCases: {
operation: OkmsServiceKeyOperations;
diff --git a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyTypeTranslations.spec.tsx b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyTypeTranslations.spec.tsx
index 1c08795cd6b4..a916f9533012 100644
--- a/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyTypeTranslations.spec.tsx
+++ b/packages/manager/apps/key-management-service/src/hooks/serviceKey/useServiceKeyTypeTranslations.spec.tsx
@@ -1,7 +1,16 @@
-import { describe, expect, it, test } from 'vitest';
+import { describe, expect, it, test, vi } from 'vitest';
import { OkmsKeyTypes } from '@/types/okmsServiceKey.type';
import { useServiceKeyTypeTranslations } from './useServiceKeyTypeTranslations';
+vi.mock('react-i18next', () => ({
+ useTranslation: () => ({
+ t: (translationKey: string) => translationKey,
+ i18n: {
+ changeLanguage: () => new Promise(() => {}),
+ },
+ }),
+}));
+
describe('get service key type translation ', () => {
const useCases: {
type: OkmsKeyTypes;
diff --git a/packages/manager/apps/key-management-service/src/mocks/okms.mock.ts b/packages/manager/apps/key-management-service/src/mocks/okms.mock.ts
new file mode 100644
index 000000000000..c7a1103b4b51
--- /dev/null
+++ b/packages/manager/apps/key-management-service/src/mocks/okms.mock.ts
@@ -0,0 +1,42 @@
+import { PathParams } from 'msw';
+import { Handler } from '../../../../../../playwright-helpers';
+import { OKMS } from '@/types/okms.type';
+
+export const okmsList: OKMS[] = [
+ {
+ iam: {
+ displayName: 'kms-1',
+ id: '1b4e7c8e-d1b8-4b46-a584-52c8b4b0225c',
+ urn: `urn:v1:eu:resource:okms:1b4e7c8e-d1b8-4b46-a584-52c8b4b0225c`,
+ },
+ id: '7f3a82ac-a8d8-4c2a-ab0c-f6e86ddf6a7c',
+ kmipEndpoint: 'eu-west-rbx.okms.ovh.net:1234',
+ region: 'EU_WEST_RBX',
+ restEndpoint: 'https://eu-west-rbx.okms.ovh.net',
+ swaggerEndpoint: '"https://swagger-eu-west-rbx.okms.ovh.net',
+ },
+];
+
+export type GetOkmsMocksParams = {
+ nbOkms?: number;
+};
+
+const findOkmsById = (params: PathParams) =>
+ okmsList.find(({ id }) => id === params.id);
+
+export const getOkmsMocks = ({
+ nbOkms = okmsList.length,
+}: GetOkmsMocksParams): Handler[] => [
+ {
+ url: '/okms/resource/:id',
+ response: (_: unknown, params: PathParams) => findOkmsById(params),
+ status: 200,
+ api: 'v2',
+ },
+ {
+ url: '/okms/resource',
+ response: okmsList.slice(0, nbOkms),
+ status: 200,
+ api: 'v2',
+ },
+];
diff --git a/packages/manager/apps/key-management-service/src/mocks/services.mock.ts b/packages/manager/apps/key-management-service/src/mocks/services.mock.ts
new file mode 100644
index 000000000000..19fe0b3e8db6
--- /dev/null
+++ b/packages/manager/apps/key-management-service/src/mocks/services.mock.ts
@@ -0,0 +1,36 @@
+import { KMSServiceInfos, OkmsState } from '@/types/okmsService.type';
+import { Handler } from '../../../../../../playwright-helpers';
+
+const serviceList: KMSServiceInfos[] = [
+ {
+ billing: {
+ lifecycle: { current: { creationDate: '2024-04-12T18:00:00.000Z' } },
+ nextBillingDate: '2024-05-12T18:00:00.000Z',
+ },
+ customer: { contacts: [{ customerCode: 'code', type: 'type' }] },
+ resource: {
+ displayName: 'name',
+ name: 'name',
+ product: { name: 'name', description: 'descripton' },
+ resellingProvider: 'test',
+ state: OkmsState.Active,
+ },
+ },
+];
+
+export const getServicesMocks = (): Handler[] => [
+ {
+ url: '/services/:id',
+ response: serviceList[0],
+ status: 200,
+ method: 'get',
+ api: 'v6',
+ },
+ {
+ url: '/services',
+ response: () => [1234567890],
+ status: 200,
+ method: 'get',
+ api: 'v6',
+ },
+];
diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/CreateAddIdentities.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateAddIdentities.component.tsx
index 820c776c97b0..4de995d7eb00 100644
--- a/packages/manager/apps/key-management-service/src/pages/credential/create/CreateAddIdentities.component.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateAddIdentities.component.tsx
@@ -83,9 +83,9 @@ const CreateAddIdentities = ({
)}
-
-
-
+
+
+
>
)}
diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedBase.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedBase.component.tsx
index 762edddd6777..9b7041ca026d 100644
--- a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedBase.component.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedBase.component.tsx
@@ -11,6 +11,7 @@ import { useTranslation } from 'react-i18next';
type IdentitiesSelectedBaseProps = {
title: string;
+ identityURNs: string[];
addCallback: () => void;
addButtonLabel: string;
deleteCallback: () => void;
@@ -20,6 +21,7 @@ type IdentitiesSelectedBaseProps = {
const IdentitiesSelectedBase = ({
title,
+ identityURNs,
addCallback,
addButtonLabel,
deleteCallback,
@@ -36,6 +38,7 @@ const IdentitiesSelectedBase = ({
variant={ODS_BUTTON_VARIANT.stroked}
size={ODS_BUTTON_SIZE.sm}
color={ODS_THEME_COLOR_INTENT.primary}
+ disabled={identityURNs.length > 25 || undefined}
onClick={addCallback}
>
{addButtonLabel}
diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedGroups.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedGroups.component.tsx
index 0d6180275fae..a46f7054dce2 100644
--- a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedGroups.component.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedGroups.component.tsx
@@ -10,7 +10,13 @@ import IdentityGroupNameCell from './cell/group/IdentityGroupNameCell.component'
import IdentityGroupDescriptionCell from './cell/group/IdentityGroupDescriptionCell.component';
import IdentityGroupDeleteActionCell from './cell/group/IdentityGroupDeleteActionCell';
-const IdentitiesSelectedGroups = () => {
+type IdentitiesSelectedGroupsProps = {
+ identityURNs: string[];
+};
+
+const IdentitiesSelectedGroups = ({
+ identityURNs,
+}: IdentitiesSelectedGroupsProps) => {
const { t } = useTranslation('key-management-service/credential');
const navigate = useNavigate();
const { groupList, setGroupList } = useIdentityData();
@@ -49,6 +55,7 @@ const IdentitiesSelectedGroups = () => {
deleteCallback={() => setGroupList([])}
datagridColumns={columns}
items={groupList}
+ identityURNs={identityURNs}
>
);
};
diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedServiceAccounts.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedServiceAccounts.component.tsx
index ace116814196..95f49d40c3f1 100644
--- a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedServiceAccounts.component.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedServiceAccounts.component.tsx
@@ -6,11 +6,17 @@ import { ROUTES_URLS } from '@/routes/routes.constants';
import { useIdentityData } from '@/hooks/credential/useIdentityData';
import { IdentityOauthClient } from '@/types/identity.type';
import IdentitiesSelectedBase from './IdentitiesSelectedBase.component';
-import IdentityServiceAccountDescriptionCell from './cell/service-account/IdentityServiceAccountDescriptionCell.component';
+import IdentityServiceAccountIdentityCell from './cell/service-account/IdentityServiceAccountIdentityCell.component';
import IdentityServiceAccountNameCell from './cell/service-account/IdentityServiceAccountNameCell.component';
import IdentityServiceAccountDeleteActionCell from './cell/service-account/IdentityServiceAccountDeleteActionCell';
-const IdentitiesSelectedServiceAccounts = () => {
+type IdentitiesSelectedServiceAccountsProps = {
+ identityURNs: string[];
+};
+
+const IdentitiesSelectedServiceAccounts = ({
+ identityURNs,
+}: IdentitiesSelectedServiceAccountsProps) => {
const { t } = useTranslation('key-management-service/credential');
const navigate = useNavigate();
const { serviceAccountList, setServiceAccountList } = useIdentityData();
@@ -23,10 +29,10 @@ const IdentitiesSelectedServiceAccounts = () => {
isSortable: false,
},
{
- id: 'description',
- cell: IdentityServiceAccountDescriptionCell,
+ id: 'identity',
+ cell: IdentityServiceAccountIdentityCell,
label: t(
- 'key_management_service_credential_user_list_column_description',
+ 'key_management_service_credential_create_identities_service-account_tile_identity_label',
),
isSortable: false,
},
@@ -51,6 +57,7 @@ const IdentitiesSelectedServiceAccounts = () => {
deleteCallback={() => setServiceAccountList([])}
datagridColumns={columns}
items={serviceAccountList}
+ identityURNs={identityURNs}
>
);
};
diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedUsersList.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedUsersList.component.tsx
index 79e1b2a89943..17e532a3ec9a 100644
--- a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedUsersList.component.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedUsersList.component.tsx
@@ -11,7 +11,12 @@ import IdentityUserGroupCell from './cell/user/IdentityUserGroupCell.component';
import IdentityUserStatusCell from './cell/user/IdentityUserStatusCell.component';
import IdentityUserDeleteActionCell from './cell/user/IdentityUserDeleteActionCell';
-const IdentitiesSelectedUsersList = () => {
+type IdentitiesSelectedUsersListProps = {
+ identityURNs: string[];
+};
+const IdentitiesSelectedUsersList = ({
+ identityURNs,
+}: IdentitiesSelectedUsersListProps) => {
const { t } = useTranslation('key-management-service/credential');
const navigate = useNavigate();
const { userList, setUserList } = useIdentityData();
@@ -59,6 +64,7 @@ const IdentitiesSelectedUsersList = () => {
}}
datagridColumns={columns}
items={userList}
+ identityURNs={identityURNs}
>
);
};
diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDescriptionCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountIdentityCell.component.tsx
similarity index 53%
rename from packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDescriptionCell.component.tsx
rename to packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountIdentityCell.component.tsx
index 14ccda07496b..9a4bb3401142 100644
--- a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDescriptionCell.component.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountIdentityCell.component.tsx
@@ -2,10 +2,10 @@ import React from 'react';
import { DataGridTextCell } from '@ovh-ux/manager-react-components';
import { IdentityOauthClient } from '@/types/identity.type';
-const IdentityServiceAccountDescriptionCell = (
+const IdentityServiceAccountIdentityCell = (
serviceAccount: IdentityOauthClient,
) => {
- return {serviceAccount.description};
+ return {serviceAccount.identity};
};
-export default IdentityServiceAccountDescriptionCell;
+export default IdentityServiceAccountIdentityCell;
diff --git a/packages/manager/apps/key-management-service/src/pages/dashboard/generalInformations/GeneralInformations.tsx b/packages/manager/apps/key-management-service/src/pages/dashboard/generalInformations/GeneralInformations.tsx
index 5e545b4ea5a8..f1f37b1b86e7 100644
--- a/packages/manager/apps/key-management-service/src/pages/dashboard/generalInformations/GeneralInformations.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/dashboard/generalInformations/GeneralInformations.tsx
@@ -14,7 +14,7 @@ function GeneralInformationsTab() {
const {
data: okmsService,
isLoading: isOkmsServiceLoading,
- } = useKMSServiceInfos(okms?.data);
+ } = useKMSServiceInfos(okms?.data.id);
const navigate = useNavigate();
@@ -32,7 +32,10 @@ function GeneralInformationsTab() {
return (
-
+
{
+ const { t: tDashboard } = useTranslation('key-management-service/dashboard');
+ const { t: tCredential } = useTranslation(
+ 'key-management-service/credential',
+ );
+ const { okmsId } = useParams();
+ const { data: okmsServiceInfos, isLoading } = useKMSServiceInfos(okmsId);
+ const navigate = useNavigate();
+ const { updateKmsName, isPending, error } = useUpdateOkmsName({
+ okmsId,
+ onSuccess: () => {
+ navigate('..');
+ },
+ });
+
+ return (
+ {
+ navigate('..');
+ }}
+ updateDisplayName={(newDisplayName: string) => {
+ updateKmsName({ okms: okmsId, displayName: newDisplayName });
+ }}
+ >
+ );
+};
+
+export default OkmsNameUpdateModal;
diff --git a/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx b/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx
index 862b081ac235..18a66a1155d4 100644
--- a/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx
@@ -4,8 +4,8 @@ import { Outlet, useNavigate, useParams } from 'react-router-dom';
import {
Notifications,
BaseLayout,
- ErrorBanner,
HeadersProps,
+ ErrorBanner,
} from '@ovh-ux/manager-react-components';
import { queryClient } from '@ovh-ux/manager-react-core-application';
import KmsGuidesHeader from '@/components/Guide/KmsGuidesHeader';
@@ -13,12 +13,13 @@ import Dashboard, {
DashboardTabItemProps,
} from '@/components/layout-helpers/Dashboard/Dashboard';
import Loading from '@/components/Loading/Loading';
-import { useOKMSById } from '@/data/hooks/useOKMS';
import Breadcrumb from '@/components/Breadcrumb/Breadcrumb';
import { ROUTES_URLS } from '@/routes/routes.constants';
import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb';
import { getOkmsResourceQueryKey } from '@/data/api/okms';
import { OKMS } from '@/types/okms.type';
+import { useKMSServiceInfos } from '@/data/hooks/useKMSServiceInfos';
+import { useOKMSById } from '@/data/hooks/useOKMS';
export const OkmsContext = createContext(null);
@@ -32,14 +33,27 @@ export default function DashboardPage() {
'key-management-service/credential',
);
const { okmsId } = useParams();
- const { data: okms, isLoading, error } = useOKMSById(okmsId);
+ const {
+ data: okms,
+ isLoading: isOkmsLoading,
+ isError: isOkmsError,
+ error: okmsError,
+ } = useOKMSById(okmsId);
- if (isLoading) return ;
+ const {
+ data: okmsServiceInfos,
+ isLoading: isOkmsServiceInfosLoading,
+ isError: isOkmsServiceInfosError,
+ error: okmsServiceInfoError,
+ } = useKMSServiceInfos(okmsId);
+ const displayName = okmsServiceInfos?.data?.resource.displayName;
- if (error)
+ if (isOkmsServiceInfosLoading || isOkmsLoading) return ;
+
+ if (isOkmsServiceInfosError || isOkmsError)
return (
navigate(ROUTES_URLS.listing)}
onReloadPage={() =>
queryClient.refetchQueries({
@@ -67,7 +81,7 @@ export default function DashboardPage() {
const breadcrumbItems: BreadcrumbItem[] = [
{
id: okmsId,
- label: okms.data.iam.displayName,
+ label: displayName,
navigateTo: `/${okmsId}`,
},
{
@@ -80,10 +94,15 @@ export default function DashboardPage() {
label: tCredentials('key_management_service_credential'),
navigateTo: `/${okmsId}/${ROUTES_URLS.credentials}`,
},
+ {
+ id: ROUTES_URLS.okmsUpdateName,
+ label: tDashboard('key_management_service_update_name'),
+ navigateTo: `/${okmsId}/${ROUTES_URLS.okmsUpdateName}`,
+ },
];
const headerProps: HeadersProps = {
- title: okms.data.iam.displayName,
+ title: displayName,
headerButton: ,
};
diff --git a/packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/ServiceKeyList.page.tsx b/packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/ServiceKeyList.page.tsx
index 5a660992a85b..ff69268c48c6 100644
--- a/packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/ServiceKeyList.page.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/ServiceKeyList.page.tsx
@@ -1,30 +1,23 @@
-import React from 'react';
+import React, { useContext } from 'react';
import { Outlet, useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
+import { queryClient } from '@ovh-ux/manager-react-core-application';
import {
- ODS_SPINNER_SIZE,
ODS_MESSAGE_TYPE,
ODS_BUTTON_SIZE,
ODS_ICON_NAME,
ODS_ICON_SIZE,
ODS_BUTTON_VARIANT,
} from '@ovhcloud/ods-components';
-import {
- OsdsText,
- OsdsMessage,
- OsdsSpinner,
- OsdsButton,
- OsdsIcon,
-} from '@ovhcloud/ods-components/react';
+import { OsdsMessage, OsdsIcon } from '@ovhcloud/ods-components/react';
import {
Datagrid,
+ Description,
+ ErrorBanner,
+ ManagerButton,
useDatagridSearchParams,
} from '@ovh-ux/manager-react-components';
-import {
- ODS_THEME_COLOR_INTENT,
- ODS_THEME_TYPOGRAPHY_LEVEL,
- ODS_THEME_TYPOGRAPHY_SIZE,
-} from '@ovhcloud/ods-common-theming';
+import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import {
DatagridCellType,
DatagridCreationDate,
@@ -35,6 +28,9 @@ import {
} from '@/components/Listing/ListingCells';
import { useOkmsServiceKeys } from '@/data/hooks/useOkmsServiceKeys';
import { ROUTES_URLS } from '@/routes/routes.constants';
+import { OkmsContext } from '..';
+import Loading from '@/components/Loading/Loading';
+import { getOkmsServiceKeyResourceListQueryKey } from '@/data/api/okmsServiceKey';
export default function Keys() {
const { t } = useTranslation('key-management-service/serviceKeys');
@@ -75,66 +71,70 @@ export default function Keys() {
];
const { sorting, setSorting } = useDatagridSearchParams();
+ const okms = useContext(OkmsContext);
const { okmsId } = useParams();
const { error, data: okmsServiceKey, isLoading } = useOkmsServiceKeys({
sorting,
okmsId,
});
+ if (isLoading) return ;
+
+ if (error)
+ return (
+ navigate(ROUTES_URLS.listing)}
+ onReloadPage={() =>
+ queryClient.refetchQueries({
+ queryKey: getOkmsServiceKeyResourceListQueryKey(okmsId),
+ })
+ }
+ />
+ );
+
return (
- <>
-
-
- {t('key_management_service_service-keys_headline')}
-
-
+
+
+ {t('key_management_service_service-keys_headline')}
+
{error && (
{tError('manager_error_page_default')}
)}
+
+
{
+ navigate(ROUTES_URLS.createKmsServiceKey);
+ }}
+ urn={okms.iam.urn}
+ iamActions={['okms:apiovh:resource/serviceKey/create']}
+ >
+
+
+
- {isLoading && !error && (
-
-
-
- )}
- {
- navigate(ROUTES_URLS.createKmsServiceKey);
- }}
- >
-
-
-
-
- {t('key_management_service_service-keys_cta_create')}
-
- {!isLoading && !error && (
-
-
-
- )}
+ {t('key_management_service_service-keys_cta_create')}
+
+
+
- >
+
);
}
diff --git a/packages/manager/apps/key-management-service/src/pages/listing/KmsListing.page.spec.tsx b/packages/manager/apps/key-management-service/src/pages/listing/KmsListing.page.spec.tsx
new file mode 100644
index 000000000000..861f4a46d699
--- /dev/null
+++ b/packages/manager/apps/key-management-service/src/pages/listing/KmsListing.page.spec.tsx
@@ -0,0 +1,102 @@
+import { act, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { renderTestApp } from '@/utils/tests/renderTestApp';
+import '@testing-library/jest-dom';
+import { labels } from '@/utils/tests/init.i18n';
+import { okmsList } from '@/mocks/okms.mock';
+
+describe('KMS listing test suite', () => {
+ it('should redirect to the onboarding page when the kms list is empty', async () => {
+ await renderTestApp({ nbOkms: 0 });
+
+ expect(screen.getByText(labels.onboarding.title)).toBeVisible();
+
+ expect(
+ screen.queryByText(labels.listing.key_management_service_listing_title),
+ ).not.toBeInTheDocument();
+ });
+
+ it('should display the kms listing page', async () => {
+ await renderTestApp();
+
+ expect(
+ screen.getByText(labels.listing.key_management_service_listing_title),
+ ).toBeVisible();
+
+ expect(
+ screen.queryByText(labels.onboarding.description),
+ ).not.toBeInTheDocument();
+ });
+
+ it(`should navigate to the kms creation form on click on "${labels.listing.key_management_service_listing_add_kms_button}" button`, async () => {
+ await renderTestApp();
+
+ await waitFor(
+ () =>
+ expect(
+ screen.getByText(
+ labels.listing.key_management_service_listing_add_kms_button,
+ ),
+ ).toBeEnabled(),
+ {
+ timeout: 30_000,
+ },
+ );
+
+ await act(() =>
+ userEvent.click(
+ screen.getByText(
+ labels.listing.key_management_service_listing_add_kms_button,
+ ),
+ ),
+ );
+
+ await waitFor(
+ () =>
+ expect(
+ screen.getByText(
+ labels.create.key_management_service_create_subtitle,
+ ),
+ ).toBeVisible(),
+ { timeout: 30_000 },
+ );
+ });
+
+ it('should navigate to a kms dashboard on click on kms name', async () => {
+ await renderTestApp();
+
+ await act(() =>
+ userEvent.click(screen.getByText(okmsList[0].iam.displayName)),
+ );
+
+ await waitFor(
+ () =>
+ expect(
+ screen.getByText(labels.dashboard.billing_informations),
+ ).toBeVisible(),
+ { timeout: 30_000 },
+ );
+ });
+
+ it(`should navigate to the kms delete modal on click on "${labels.listing.key_management_service_listing_terminate}" list action button`, async () => {
+ await renderTestApp();
+
+ await act(() =>
+ userEvent.click(
+ screen.getByText(
+ labels.listing.key_management_service_listing_terminate,
+ ),
+ ),
+ );
+
+ await waitFor(
+ () =>
+ expect(
+ screen.getByText(
+ labels.terminate.key_management_service_terminate_cancel,
+ ),
+ ).toBeVisible(),
+ { timeout: 30_000 },
+ );
+ });
+});
diff --git a/packages/manager/apps/key-management-service/src/pages/listing/index.tsx b/packages/manager/apps/key-management-service/src/pages/listing/index.tsx
index 2a33977bfaf3..1962ace06416 100644
--- a/packages/manager/apps/key-management-service/src/pages/listing/index.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/listing/index.tsx
@@ -1,24 +1,19 @@
-import React, { Suspense, useEffect } from 'react';
+import React from 'react';
import { Outlet, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
- ODS_SPINNER_SIZE,
ODS_MESSAGE_TYPE,
ODS_BUTTON_SIZE,
ODS_BUTTON_VARIANT,
} from '@ovhcloud/ods-components';
-import {
- OsdsButton,
- OsdsMessage,
- OsdsSpinner,
-} from '@ovhcloud/ods-components/react';
+import { OsdsButton, OsdsMessage } from '@ovhcloud/ods-components/react';
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import {
BaseLayout,
Datagrid,
HeadersProps,
Notifications,
- useDatagridSearchParams,
+ RedirectionGuard,
useNotifications,
} from '@ovh-ux/manager-react-components';
import {
@@ -26,7 +21,7 @@ import {
PageLocation,
useOvhTracking,
} from '@ovh-ux/manager-react-shell-client';
-import { useOKMS } from '@/data/hooks/useOKMS';
+import { useOKMSList } from '@/data/hooks/useOKMS';
import { ROUTES_URLS } from '@/routes/routes.constants';
import {
DatagridActionMenu,
@@ -36,7 +31,6 @@ import {
DatagridCellStatus,
} from '@/components/Listing/ListingCells';
import KmsGuidesHeader from '@/components/Guide/KmsGuidesHeader';
-import Loading from '@/components/Loading/Loading';
export default function Listing() {
const { t } = useTranslation('key-management-service/listing');
@@ -74,24 +68,35 @@ export default function Listing() {
},
];
- const { sorting, setSorting } = useDatagridSearchParams();
-
- const { error, data: okms, isLoading } = useOKMS({
- sorting,
+ const {
+ data,
+ flattenData,
+ fetchNextPage,
+ hasNextPage,
+ isError,
+ isLoading,
+ status,
+ } = useOKMSList({
+ pageSize: 10,
});
- useEffect(() => {
- if (okms.length === 0 && !isLoading) {
- navigate(ROUTES_URLS.onboarding);
- }
- }, [okms.length, isLoading]);
-
const headerProps: HeadersProps = {
title: t('key_management_service_listing_title'),
headerButton: ,
};
+
return (
- }>
+
+ {tError('manager_error_page_default')}
+
+ }
+ >
}>
- {error && (
-
- {tError('manager_error_page_default')}
-
- )}
-
- {isLoading && !error && (
-
-
-
- )}
- {!isLoading && !error && (
+ {flattenData && (
fetchNextPage()}
contentAlignLeft
/>
)}
-
+
);
}
diff --git a/packages/manager/apps/key-management-service/src/pages/serviceKey/ServiceKey.page.tsx b/packages/manager/apps/key-management-service/src/pages/serviceKey/ServiceKey.page.tsx
index b07ec4555243..a99f0f2b22eb 100644
--- a/packages/manager/apps/key-management-service/src/pages/serviceKey/ServiceKey.page.tsx
+++ b/packages/manager/apps/key-management-service/src/pages/serviceKey/ServiceKey.page.tsx
@@ -3,13 +3,13 @@ import { useTranslation } from 'react-i18next';
import { useQueryClient } from '@tanstack/react-query';
import {
BaseLayout,
+ Clipboard,
ErrorBanner,
+ ManagerButton,
Notifications,
- Clipboard,
} from '@ovh-ux/manager-react-components';
import { Outlet, useNavigate, useParams } from 'react-router-dom';
import {
- OsdsButton,
OsdsIcon,
OsdsTabBar,
OsdsTabBarItem,
@@ -38,37 +38,49 @@ import { getOkmsServiceKeyResourceQueryKey } from '@/data/api/okmsServiceKey';
import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb';
import { useOKMSById } from '@/data/hooks/useOKMS';
import ServiceKeyStateActions from '@/components/serviceKey/serviceKeyStateActions/ServiceKeyStateActions.component';
+import { getOkmsResourceQueryKey } from '@/data/api/okms';
export default function Key() {
const { okmsId, keyId } = useParams();
- const { data: okms } = useOKMSById(okmsId);
- const { data: serviceKey, error, isLoading } = useOkmsServiceKeyById({
- okmsId,
- keyId,
- });
const { t } = useTranslation('key-management-service/serviceKeys');
const queryClient = useQueryClient();
-
const navigate = useNavigate();
- const kms = okms?.data;
- const kmsKey = serviceKey?.data;
+ const {
+ data: okms,
+ isLoading: isLoadingOkms,
+ error: okmsError,
+ } = useOKMSById(okmsId);
- if (isLoading) return ;
+ const {
+ data: serviceKey,
+ error: serviceKeyError,
+ isLoading: isLoadingServiceKey,
+ } = useOkmsServiceKeyById({
+ okmsId,
+ keyId,
+ });
- if (error)
+ if (isLoadingServiceKey || isLoadingOkms) return ;
+
+ if (okmsError || serviceKeyError)
return (
navigate(ROUTES_URLS.listing)}
onReloadPage={() =>
queryClient.refetchQueries({
- queryKey: getOkmsServiceKeyResourceQueryKey({ okmsId, keyId }),
+ queryKey: okmsError
+ ? getOkmsResourceQueryKey(okmsId)
+ : getOkmsServiceKeyResourceQueryKey({ okmsId, keyId }),
})
}
/>
);
+ const kms = okms.data;
+ const kmsKey = serviceKey.data;
+
const breadcrumbItems: BreadcrumbItem[] = [
{
id: okmsId,
@@ -131,18 +143,20 @@ export default function Key() {
>
- navigate(ROUTES_URLS.serviceKeyEditName)}
+ urn={kms.iam.urn}
+ iamActions={['okms:apiovh:resource/serviceKey/update']}
>
-
+
@@ -161,7 +175,7 @@ export default function Key() {
titleStatus={}
>
-
+
diff --git a/packages/manager/apps/key-management-service/src/routes/routes.constants.ts b/packages/manager/apps/key-management-service/src/routes/routes.constants.ts
index c7c47288b056..0041c5ff8b1e 100644
--- a/packages/manager/apps/key-management-service/src/routes/routes.constants.ts
+++ b/packages/manager/apps/key-management-service/src/routes/routes.constants.ts
@@ -5,6 +5,7 @@ export const ROUTES_URLS = {
terminateOkms: '/terminate',
createKeyManagementService: 'create',
okmsId: ':okmsId',
+ okmsUpdateName: 'update-name',
keys: 'keys',
keyId: ':keyId',
createKmsServiceKey: 'create',
diff --git a/packages/manager/apps/key-management-service/src/routes/routes.tsx b/packages/manager/apps/key-management-service/src/routes/routes.tsx
index a37274924b0e..beee6cca23a4 100644
--- a/packages/manager/apps/key-management-service/src/routes/routes.tsx
+++ b/packages/manager/apps/key-management-service/src/routes/routes.tsx
@@ -84,6 +84,16 @@ export default [
pageType: PageType.dashboard,
},
},
+ children: [
+ {
+ path: ROUTES_URLS.okmsUpdateName,
+ ...lazyRouteConfig(() =>
+ import(
+ '@/pages/dashboard/generalInformations/updateName/OkmsNameUpdateModal'
+ ),
+ ),
+ },
+ ],
},
{
path: ROUTES_URLS.keys,
diff --git a/packages/manager/apps/key-management-service/src/setupTests.ts b/packages/manager/apps/key-management-service/src/setupTests.ts
deleted file mode 100644
index 39d524c2e0e0..000000000000
--- a/packages/manager/apps/key-management-service/src/setupTests.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import '@testing-library/jest-dom';
-import { vi } from 'vitest';
-
-vi.mock('react-i18next', () => ({
- useTranslation: () => ({
- t: (translationKey: string) => translationKey,
- i18n: {
- changeLanguage: () => new Promise(() => {}),
- },
- }),
-}));
diff --git a/packages/manager/apps/key-management-service/src/setupTests.tsx b/packages/manager/apps/key-management-service/src/setupTests.tsx
new file mode 100644
index 000000000000..141b5063ffb0
--- /dev/null
+++ b/packages/manager/apps/key-management-service/src/setupTests.tsx
@@ -0,0 +1,39 @@
+import { odsSetup } from '@ovhcloud/ods-common-core';
+import { SetupServer, setupServer } from 'msw/node';
+import { toMswHandlers } from '../../../../../playwright-helpers';
+import { getAuthenticationMocks } from '../../../../../playwright-helpers/mocks/auth';
+import '@testing-library/jest-dom';
+import 'element-internals-polyfill';
+
+odsSetup();
+
+declare global {
+ // eslint-disable-next-line vars-on-top, no-var
+ var server: SetupServer;
+ // eslint-disable-next-line vars-on-top, no-var, @typescript-eslint/naming-convention
+ var __VERSION__: string;
+}
+
+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__;
+});
+
+afterEach(() => {
+ server.resetHandlers();
+});
diff --git a/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.ts b/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.ts
index d85895eb1717..821674362799 100644
--- a/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.ts
+++ b/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.ts
@@ -19,7 +19,7 @@ export const getDownloadCredentialParameters = (credential: OkmsCredential) => {
credential.certificatePEM.replace(/\n/g, '\r\n'),
)}`
: undefined,
- filename: `${credential.name}.pem`,
+ filename: `${credential.id}_certificate.pem`,
isDisabled: isDownloadCredentialDisabled(credential.status),
};
};
diff --git a/packages/manager/apps/key-management-service/src/utils/tests/TestApp.tsx b/packages/manager/apps/key-management-service/src/utils/tests/TestApp.tsx
new file mode 100644
index 000000000000..c61879281812
--- /dev/null
+++ b/packages/manager/apps/key-management-service/src/utils/tests/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() {
+ const router = createMemoryRouter(routes, {
+ initialEntries: ['/'],
+ initialIndex: 0,
+ });
+
+ const queryClient = new QueryClient({
+ defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
+ });
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/manager/apps/key-management-service/src/utils/tests/init.i18n.ts b/packages/manager/apps/key-management-service/src/utils/tests/init.i18n.ts
new file mode 100644
index 000000000000..d43dbd8afec9
--- /dev/null
+++ b/packages/manager/apps/key-management-service/src/utils/tests/init.i18n.ts
@@ -0,0 +1,75 @@
+import i18next, { i18n } from 'i18next';
+import common from '../../../public/translations/key-management-service/common/Messages_fr_FR.json';
+import create from '../../../public/translations/key-management-service/create/Messages_fr_FR.json';
+import dashboard from '../../../public/translations/key-management-service/dashboard/Messages_fr_FR.json';
+import error from '../../../public/translations/key-management-service/error/Messages_fr_FR.json';
+import guide from '../../../public/translations/key-management-service/guide/Messages_fr_FR.json';
+import listing from '../../../public/translations/key-management-service/listing/Messages_fr_FR.json';
+import onboarding from '../../../public/translations/key-management-service/onboarding/Messages_fr_FR.json';
+import serviceKeys from '../../../public/translations/key-management-service/serviceKeys/Messages_fr_FR.json';
+import terminate from '../../../public/translations/key-management-service/terminate/Messages_fr_FR.json';
+
+export const defaultLocale = 'fr_FR';
+export const defaultAvailableLocales = [defaultLocale];
+
+function addTranslations() {
+ i18next
+ .addResources(defaultLocale, 'key-management-service/common', common)
+ .addResources(defaultLocale, 'key-management-service/create', create)
+ .addResources(defaultLocale, 'key-management-service/dashboard', dashboard)
+ .addResources(defaultLocale, 'key-management-service/error', error)
+ .addResources(defaultLocale, 'key-management-service/guide', guide)
+ .addResources(defaultLocale, 'key-management-service/listing', listing)
+ .addResources(defaultLocale, 'key-management-service/terminate', terminate)
+ .addResources(
+ defaultLocale,
+ 'key-management-service/onboarding',
+ onboarding,
+ )
+ .addResources(
+ defaultLocale,
+ 'key-management-service/serviceKeys',
+ serviceKeys,
+ )
+ .use({
+ type: 'postProcessor',
+ name: 'normalize',
+ process: (value: string) =>
+ value ? value.replace(/&/g, '&') : value,
+ });
+}
+
+export const initTestI18n = () =>
+ new Promise((resolve) => {
+ i18next.init({
+ lng: defaultLocale,
+ defaultNS: 'key-management-service',
+ ns: [],
+ supportedLngs: defaultAvailableLocales,
+ postProcess: 'normalize',
+ interpolation: {
+ escapeValue: false,
+ },
+ });
+
+ if (i18next.isInitialized) {
+ addTranslations();
+ } else {
+ i18next.on('initialized', () => {
+ addTranslations();
+ resolve(i18next);
+ });
+ }
+ });
+
+export const labels = {
+ common,
+ create,
+ dashboard,
+ error,
+ guide,
+ listing,
+ onboarding,
+ serviceKeys,
+ terminate,
+};
diff --git a/packages/manager/apps/key-management-service/src/utils/tests/renderTestApp.tsx b/packages/manager/apps/key-management-service/src/utils/tests/renderTestApp.tsx
new file mode 100644
index 000000000000..8849615ba54a
--- /dev/null
+++ b/packages/manager/apps/key-management-service/src/utils/tests/renderTestApp.tsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import {
+ initShellContext,
+ ShellContext,
+ ShellContextType,
+} from '@ovh-ux/manager-react-shell-client';
+import { i18n } from 'i18next';
+import { I18nextProvider } from 'react-i18next';
+import { render, waitFor, screen } from '@testing-library/react';
+import { TestApp } from './TestApp';
+import { initTestI18n } from './init.i18n';
+import { toMswHandlers } from '../../../../../../../playwright-helpers';
+import { getAuthenticationMocks } from '../../../../../../../playwright-helpers/mocks/auth';
+import { getOkmsMocks, GetOkmsMocksParams } from '@/mocks/okms.mock';
+import { getServicesMocks } from '@/mocks/services.mock';
+
+let context: ShellContextType;
+let i18nValue: i18n;
+
+export const renderTestApp = async (mockParams: GetOkmsMocksParams = {}) => {
+ global.server?.resetHandlers(
+ ...toMswHandlers([
+ ...getAuthenticationMocks({ isAuthMocked: true }),
+ ...getOkmsMocks(mockParams),
+ ...getServicesMocks(),
+ ]),
+ );
+
+ if (!context) {
+ context = await initShellContext('key-management-service');
+ }
+
+ if (!i18nValue) {
+ i18nValue = await initTestI18n();
+ }
+
+ const result = render(
+
+
+
+
+ ,
+ );
+
+ await waitFor(
+ () =>
+ expect(
+ screen.getAllByText('Key Management Service', { exact: false }).length,
+ ).toBeGreaterThan(0),
+ { timeout: 30000 },
+ );
+
+ return result;
+};
diff --git a/packages/manager/apps/key-management-service/vitest.config.js b/packages/manager/apps/key-management-service/vitest.config.js
index 156daa6627e5..51634113d665 100644
--- a/packages/manager/apps/key-management-service/vitest.config.js
+++ b/packages/manager/apps/key-management-service/vitest.config.js
@@ -8,7 +8,7 @@ export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
- setupFiles: './src/setupTests.ts',
+ setupFiles: './src/setupTests.tsx',
coverage: {
include: ['src'],
exclude: [
@@ -25,6 +25,17 @@ export default defineConfig({
'src/queryClient.ts',
],
},
+ testTimeout: 60_000,
+ fileParallelism: false,
+ maxWorkers: 1,
+ pollOptions: {
+ forks: {
+ singleFork: true,
+ },
+ threads: {
+ singleThread: true,
+ },
+ },
},
resolve: {
alias: {