Skip to content

Commit

Permalink
feat(vcd): add reset password setup
Browse files Browse the repository at this point in the history
  ref: MANAGER-15191

Signed-off-by: Paul Dickerson <[email protected]>
  • Loading branch information
Paul Dickerson authored and Nicolas Pierre-charles committed Nov 15, 2024
1 parent 2fd1dab commit bbce325
Show file tree
Hide file tree
Showing 24 changed files with 424 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type OdsNotificationProps = {
notification: Notification;
};

const getOdsMessageColor = (type: NotificationType) => {
export const getOdsNotificationMessageColor = (type: NotificationType) => {
switch (type) {
case NotificationType.Success:
return ODS_MESSAGE_COLOR.success;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './iam/iam.handler';
export * from './vcd-organization/vcd-organization.handler';
export * from './vcd-organization/vcd-datacentre.handler';
export * from './vcd-organization/vcd-datacentre-order.handler';
export * from './veeam-backup/veeam-backup.handler';
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { PathParams } from 'msw';
import { Handler } from '../../../../../../playwright-helpers';
import { datacentreList } from './vcd-datacentre.mock';
import { computeList } from './vdc-compute.mock';
import { storageList } from './vdc-storage.mock';

export type GetDatacentresMocksParams = {
isDatacentresKo?: boolean;
isDatacentreUpdateKo?: boolean;
nbDatacentres?: number;
isComputeKO?: boolean;
nbCompute?: number;
isStorageKO?: boolean;
nbStorage?: number;
};

const findDatacentreById = (params: PathParams) =>
datacentreList.find(({ id }) => id === params.id);

export const getDatacentresMocks = ({
isDatacentresKo,
isDatacentreUpdateKo,
nbDatacentres = Number.POSITIVE_INFINITY,
isComputeKO,
nbCompute = Number.POSITIVE_INFINITY,
isStorageKO,
nbStorage = Number.POSITIVE_INFINITY,
}: GetDatacentresMocksParams): Handler[] => [
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter/:id/storage',
response: isStorageKO
? { message: 'Storage error' }
: storageList.slice(0, nbStorage),
api: 'v2',
status: isStorageKO ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter/:id/compute',
response: isComputeKO
? { message: 'Compute error' }
: computeList.slice(0, nbCompute),
api: 'v2',
status: isComputeKO ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter',
response: isDatacentresKo
? { message: 'Datacentres error' }
: datacentreList.slice(0, nbDatacentres),
api: 'v2',
status: isDatacentresKo ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter/:id',
response: (_: unknown, params: PathParams) =>
isDatacentresKo
? { message: 'Datacentre error' }
: findDatacentreById(params),
api: 'v2',
status: isDatacentresKo ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter/:id',
response: isDatacentreUpdateKo
? { message: 'Datacentre update error' }
: {},
method: 'put',
api: 'v2',
status: isDatacentreUpdateKo ? 500 : 200,
},
];
Original file line number Diff line number Diff line change
@@ -1,89 +1,27 @@
import { PathParams } from 'msw';
import { Handler } from '../../../../../../playwright-helpers';
import { organizationList } from './vcd-organization.mock';
import { datacentreList } from './vcd-datacentre.mock';
import { computeList } from './vdc-compute.mock';
import { storageList } from './vdc-storage.mock';

export type GetOrganizationMocksParams = {
isOrganizationKo?: boolean;
isOrganizationUpdateKo?: boolean;
isOrganizationResetPasswordKo?: boolean;
nbOrganization?: number;
allOrgsBackedUp?: boolean;
isDatacentresKo?: boolean;
isDatacentreUpdateKo?: boolean;
nbDatacentres?: number;
isComputeKO?: boolean;
nbCompute?: number;
isStorageKO?: boolean;
nbStorage?: number;
};

const findOrganizationById = (params: PathParams) =>
organizationList.find(({ id }) => id === params.id);

const findDatacentreById = (params: PathParams) =>
datacentreList.find(({ id }) => id === params.id);

export const getOrganizationMocks = ({
isOrganizationKo,
isOrganizationUpdateKo,
isOrganizationResetPasswordKo,
nbOrganization = Number.POSITIVE_INFINITY,
allOrgsBackedUp,
isDatacentresKo,
isDatacentreUpdateKo,
nbDatacentres = Number.POSITIVE_INFINITY,
isComputeKO,
nbCompute = Number.POSITIVE_INFINITY,
isStorageKO,
nbStorage = Number.POSITIVE_INFINITY,
}: GetOrganizationMocksParams): Handler[] => {
const nb = allOrgsBackedUp ? 1 : nbOrganization;
return [
{
url:
'/vmwareCloudDirector/organization/:id/virtualDataCenter/:id/storage',
response: isStorageKO
? { message: 'Storage error' }
: storageList.slice(0, nbStorage),
api: 'v2',
status: isStorageKO ? 500 : 200,
},
{
url:
'/vmwareCloudDirector/organization/:id/virtualDataCenter/:id/compute',
response: isComputeKO
? { message: 'Compute error' }
: computeList.slice(0, nbCompute),
api: 'v2',
status: isComputeKO ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter',
response: isDatacentresKo
? { message: 'Datacentres error' }
: datacentreList.slice(0, nbDatacentres),
api: 'v2',
status: isDatacentresKo ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter/:id',
response: (_: unknown, params: PathParams) =>
isDatacentresKo
? { message: 'Datacentre error' }
: findDatacentreById(params),
api: 'v2',
status: isDatacentresKo ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/virtualDataCenter/:id',
response: isDatacentreUpdateKo
? { message: 'Datacentre update error' }
: {},
method: 'put',
api: 'v2',
status: isDatacentreUpdateKo ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id',
response: isOrganizationUpdateKo
Expand All @@ -93,6 +31,15 @@ export const getOrganizationMocks = ({
api: 'v2',
status: isOrganizationUpdateKo ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id/password',
response: isOrganizationResetPasswordKo
? { message: 'Organization reset password error' }
: {},
method: 'post',
api: 'v2',
status: isOrganizationResetPasswordKo ? 500 : 200,
},
{
url: '/vmwareCloudDirector/organization/:id',
response: (_: unknown, params: PathParams) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
"managed_vcd_dashboard_service_cancellation": "Résilier le service",
"managed_vcd_dashboard_password": "Mot de passe",
"managed_vcd_dashboard_password_renew": "Renouveler le mot de passe admin",
"managed_vcd_dashboard_password_tooltip": "Si vous souhaitez changer votre mot de passe administrateur, merci de contacter le support",
"managed_vcd_dashboard_password_modal_title": "Changer le mot de passe",
"managed_vcd_dashboard_password_modal_subtitle": "Êtes-vous certain de changer de mot de passe ?",
"managed_vcd_dashboard_password_renew_success": "Vous allez recevoir un email pour visualiser votre mot de passe",
"managed_vcd_dashboard_password_renew_error": "Une erreur est survenue. Veuillez réessayer plus tard ou contacter le support pour changer votre mot de passe administrateur",
"managed_vcd_dashboard_back_link": "Retour à la liste",
"managed_vcd_dashboard_coming_soon": "Bientôt disponible",
"managed_vcd_dashboard_data_protection": "Protection de Données",
Expand All @@ -38,6 +41,7 @@
"managed_vcd_dashboard_edit_modal_error": "Une erreur est survenue: {{error}}.",
"managed_vcd_dashboard_edit_modal_cta_cancel": "Annuler",
"managed_vcd_dashboard_edit_modal_cta_edit": "Modifier",
"managed_vcd_dashboard_edit_modal_cta_validate": "Valider",
"managed_vcd_dashboard_edit_name_modal_title": "Modifier le nom",
"managed_vcd_dashboard_edit_name_modal_label": "Nom",
"managed_vcd_dashboard_edit_name_modal_success": "Le nom a été modifié avec succès.",
Expand Down
5 changes: 4 additions & 1 deletion packages/manager/apps/hpc-vmware-managed-vcd/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { odsSetup } from '@ovhcloud/ods-common-core';
import { RouterProvider, createHashRouter } from 'react-router-dom';
import { Routes } from './routes/routes';
import { MessageContextProvider } from './context/Message.context';

odsSetup();

Expand All @@ -20,7 +21,9 @@ function App() {

return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
<MessageContextProvider>
<RouterProvider router={router} />
</MessageContextProvider>
<ReactQueryDevtools />
</QueryClientProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import React, { useEffect, useState } from 'react';
import {
HeadersProps,
BaseLayout,
Notifications,
} from '@ovh-ux/manager-react-components';
import { HeadersProps, BaseLayout } from '@ovh-ux/manager-react-components';
import {
OsdsTabBar,
OsdsTabBarItem,
Expand All @@ -12,6 +8,7 @@ import {
import { NavLink, Outlet, useLocation, useNavigate } from 'react-router-dom';
import Breadcrumb from '@/components/breadcrumb/Breadcrumb.component';
import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb';
import { MessageList } from '@/components/message/MessageList.component';

export type DashboardTabItemProps = {
name: string;
Expand Down Expand Up @@ -74,7 +71,7 @@ export default function VcdDashboardLayout({
</OsdsTabs>
}
breadcrumb={<Breadcrumb items={breadcrumbItems} />}
message={<Notifications />}
message={<MessageList />}
backLinkLabel={backLinkLabel}
onClickReturn={onClickReturn}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { OsdsMessage, OsdsText } from '@ovhcloud/ods-components/react';
import { ODS_THEME_TYPOGRAPHY_SIZE } from '@ovhcloud/ods-common-theming';
import {
getOdsNotificationMessageColor,
getOdsNotificationTextColor,
} from '@ovh-ux/manager-react-components/src/components/notifications/ods-notification';
import { MessageType, useMessageContext } from '@/context/Message.context';

type MessageProps = {
message: MessageType;
};

export const Message: React.FC<MessageProps> = ({ message }) => {
const { pathname } = useLocation();
const { clearMessage } = useMessageContext();
const {
content,
uid,
type,
persistent,
includedSubRoutes,
excludedSubRoutes,
duration,
} = message;

useEffect(() => {
if (
!includedSubRoutes.every((route) => pathname.includes(route)) ||
excludedSubRoutes.some((route) => pathname.includes(route))
) {
clearMessage(uid);
}
}, [uid, includedSubRoutes, excludedSubRoutes, pathname]);

useEffect(() => {
if (!duration) return;
const durationTimeout = setTimeout(() => clearMessage(uid), duration);

// eslint-disable-next-line consistent-return
return () => clearTimeout(durationTimeout);
}, [duration]);

return (
<OsdsMessage
className="mb-2"
type={getOdsNotificationMessageColor(type)}
{...(persistent
? {}
: {
removable: true,
onOdsRemoveClick: () => clearMessage(uid),
})}
>
<OsdsText
color={getOdsNotificationTextColor(type)}
size={ODS_THEME_TYPOGRAPHY_SIZE._400}
>
{content}
</OsdsText>
</OsdsMessage>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { useMessageContext } from '@/context/Message.context';
import { Message } from './Message.component';

export const MessageList: React.FC = () => {
const { messages } = useMessageContext();

return (
<>
{messages.map((message) => (
<Message key={message.uid} message={message} />
))}
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useNotifications } from '@ovh-ux/manager-react-components';
import useManagedVcdOrganization from '@/data/hooks/useManagedVcdOrganization';
import { useUpdateVcdOrganizationDetails } from '@/data/hooks/useUpdateVcdOrganization';
import { IVcdOrganizationState } from '@/types/vcd-organization.interface';
Expand All @@ -10,6 +9,8 @@ import {
validateOrganizationName,
} from '@/utils/formValidation';
import { EditDetailModal } from './EditDetailModal';
import { useMessageContext } from '@/context/Message.context';
import { subRoutes } from '@/routes/routes.constant';

type OrganizationDetailName = 'name' | 'description';
type TValidationFunctions = {
Expand All @@ -27,16 +28,17 @@ export const UpdateDetailModalHandler = ({
const { t } = useTranslation('dashboard');
const navigate = useNavigate();
const closeModal = () => navigate('..');
const { addSuccess } = useNotifications();
const { addSuccess } = useMessageContext();
const { id } = useParams();
const { data: vcdOrganization } = useManagedVcdOrganization({ id });
const { updateDetails, error, isError } = useUpdateVcdOrganizationDetails({
id,
onSuccess: () => {
addSuccess(
t(`managed_vcd_dashboard_edit_${detailName}_modal_success`),
true,
);
addSuccess({
content: t(`managed_vcd_dashboard_edit_${detailName}_modal_success`),
includedSubRoutes: [id],
excludedSubRoutes: [subRoutes.datacentres],
});
closeModal();
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import {
} from '@ovh-ux/manager-react-shell-client';
import OrganizationServiceManagementTile from './OrganizationServiceManagementTile.component';

vi.mock('react-router-dom', () => ({
useNavigate: () => ({ navigate: vi.fn() }),
useParams: () => ({ id: 'id' }),
}));

const shellContext = {
environment: {
getUser: vi.fn(),
Expand Down
Loading

0 comments on commit bbce325

Please sign in to comment.