Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"description": "Définissez vos règles de diffusion pour choisir quels contacts recevront les communications, en fonction des catégories et priorités que vous sélectionnez.",
"table_column_name": "Nom",
"table_column_status": "Statut",
"add_routing_button": "Créer une règle",
"status_enabled": "Activé",
"status_disabled": "Désactivé",
"actions_menu_label": "Actions",
"table_action_deactivate": "Désactiver",
"add_routing_error_message": "Une erreur est survenue lors de la création de la règle.",
"add_routing_success_message": "La règle a été créée avec succès.",
"edit_routing_error_message": "Une erreur est survenue lors de la modification de la règle.",
"edit_routing_success_message": "La règle a été modifiée avec succès.",
"delete_routing_error_message": "Une erreur est survenue lors de la suppression de la règle.",
"delete_routing_success_message": "La règle a été supprimée avec succès.",
"add_routing_modal_title": "Créer une règle",
"edit_routing_modal_title": "Modifier la règle",
"delete_routing_modal_title": "Supprimer la règle",
"delete_routing_modal_info": "Êtes-vous sûr de vouloir supprimer la règle <strong>{{ routingName }}</strong> ?"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { NAMESPACES } from '@ovh-ux/manager-common-translations';
import { ODS_BADGE_COLOR } from '@ovhcloud/ods-components';
import { OdsBadge } from '@ovhcloud/ods-components/react';
import { useTranslation } from 'react-i18next';

export default function RoutingStatusChip({ active }: { active: boolean }) {
const { t } = useTranslation(NAMESPACES.STATUS);
return (
<OdsBadge
color={active ? ODS_BADGE_COLOR.success : ODS_BADGE_COLOR.critical}
label={t(active ? 'ok' : 'disabled')}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import apiClient from '@ovh-ux/manager-core-api';
import { NotificationReference } from '../types/reference.type';
import { Notification } from '../types/notification.type';

export const getNotificationReference = async (): Promise<NotificationReference> => {
const { data } = await apiClient.v2.get('/notification/reference');
Expand Down
8 changes: 8 additions & 0 deletions packages/manager/apps/communication/src/data/api/routing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import apiClient from '@ovh-ux/manager-core-api';
import { NotificationRouting } from '../types/routing.type';

export const getNotificationRoutingQueryKey = () => ['/notification/routing'];
export const getNotificationRouting = async (): Promise<NotificationRouting[]> => {
const { data } = await apiClient.v2.get('/notification/routing');
return data;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useQuery, UseQueryResult } from '@tanstack/react-query';
import { ApiError } from '@ovh-ux/manager-core-api';
import { NotificationRouting } from '@/data/types/routing.type';
import {
getNotificationRouting,
getNotificationRoutingQueryKey,
} from '@/data/api/routing';

export const useNotificationRouting = (): UseQueryResult<
NotificationRouting[],
ApiError
> =>
useQuery({
queryKey: getNotificationRoutingQueryKey(),
queryFn: () => getNotificationRouting(),
});
2 changes: 2 additions & 0 deletions packages/manager/apps/communication/src/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import {
useNotificationReference,
useNotificationHistory,
} from './hooks/useNotification/useNotification';
import { useNotificationRouting } from './hooks/useNotificationRouting/useNotificationRouting';
import { useAccountUrn } from './hooks/useAccountUrn/useAccountUrn';

export {
useNotification,
useNotificationReference,
useNotificationHistory,
useNotificationRouting,
useAccountUrn,
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './notification.type';
export * from './reference.type';
export * from './routing.type';
export * from './iam-resource.type';
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ContactMeanType } from './contact-mean.type';

export type NotificationRoutingContactMean = {
id: string;
email: string;
type: ContactMeanType;
};

export type NotificationRoutingCondition = {
category: string[];
priority: string[];
};

export type NotificationRoutingRule = {
continue: boolean;
condition: NotificationRoutingCondition;
contactMeans: NotificationRoutingContactMean[];
};

export type NotificationRouting = {
active: boolean;
createdAt: string;
id: string;
name: string;
rules: NotificationRoutingRule[];
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import ContactMeanStatusChip from '@/components/contactMeanStatus/contactMeanSta
import { useAccountUrn } from '@/data';
import { urls } from '@/routes/routes.constant';
import {
useDeleteContactMean,
useChangeContactMeanStatus,
useRestartValidationContactMean,
} from '@/data/hooks/useContactMean/useContactMean';
Expand All @@ -35,17 +34,6 @@ function ContactMeanActionMenu({ contactMean }: { contactMean: ContactMean }) {
const { t } = useTranslation(['contacts', NAMESPACES.ACTIONS, 'common']);
const { addSuccess, addError, clearNotifications } = useNotifications();
const { data: accountUrn } = useAccountUrn();
const { mutate: deleteContactMean } = useDeleteContactMean({
id: contactMean.id,
onSuccess: () => {
clearNotifications();
addSuccess(t('delete_contact_success_message'));
},
onError: () => {
clearNotifications();
addError(t('delete_contact_error_message'));
},
});
const { mutate: disableContactMean } = useChangeContactMeanStatus({
contactMeanId: contactMean.id,
onSuccess: () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { useTranslation } from 'react-i18next';
import { OdsMessage, OdsText } from '@ovhcloud/ods-components/react';
import {
ActionMenu,
ActionMenuItem,
Datagrid,
DatagridColumn,
DataGridTextCell,
ManagerButton,
Notifications,
useResourcesIcebergV2,
} from '@ovh-ux/manager-react-components';
import { ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components';
import { useMemo } from 'react';
import { Outlet } from 'react-router-dom';
import { NAMESPACES } from '@ovh-ux/manager-common-translations';
import { useAuthorization } from '@/hooks';
import { NotificationRouting } from '@/data/types/routing.type';
import { useAccountUrn } from '@/data';
import { getNotificationRoutingQueryKey } from '@/data/api/routing';
import {
NotificationRoutingActions,
displayActionMenuItem,
} from './settings.constants';
import RoutingStatusChip from '@/components/routingStatus/RoutingStatus.component';

function RoutingActionMenu({ routing }: { routing: NotificationRouting }) {
const { t } = useTranslation(['settings', NAMESPACES.ACTIONS, 'common']);
// const { addSuccess, addError, clearNotifications } = useNotifications();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we need this line soon?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, with the next ticket that's coming :)

const { data: accountUrn } = useAccountUrn();

const items = useMemo(
() =>
[
displayActionMenuItem(routing, NotificationRoutingActions.ENABLE) && {
id: 1,
label: t('activate', { ns: NAMESPACES.ACTIONS }),
onClick: () => {},
iamActions: ['account:apiovh:notification/routing/edit'],
urn: accountUrn,
},
displayActionMenuItem(routing, NotificationRoutingActions.DISABLE) && {
id: 2,
label: t('table_action_deactivate'),
onClick: () => {},
iamActions: ['account:apiovh:notification/routing/edit'],
urn: accountUrn,
},
displayActionMenuItem(routing, NotificationRoutingActions.EDIT) && {
id: 3,
label: t('modify', { ns: NAMESPACES.ACTIONS }),
onClick: () => {},
iamActions: ['account:apiovh:notification/routing/edit'],
urn: accountUrn,
},
displayActionMenuItem(routing, NotificationRoutingActions.DELETE) && {
id: 4,
label: t('delete', { ns: NAMESPACES.ACTIONS }),
onClick: () => {},
iamActions: ['account:apiovh:notification/routing/delete'],
urn: accountUrn,
},
].filter(Boolean) as ActionMenuItem[],
[t, routing],
);

return (
<ActionMenu
id={routing.id}
items={items}
isCompact
variant={ODS_BUTTON_VARIANT.ghost}
aria-label={t('actions_menu_label')}
/>
);
}

function SettingsPage() {
const { t } = useTranslation(['settings', 'common']);
const { data: accountUrn } = useAccountUrn();
const { isAuthorized, isLoading: isLoadingAuthorization } = useAuthorization([
'account:apiovh:notification/routing/get',
]);

const columns: DatagridColumn<NotificationRouting>[] = useMemo(
() => [
{
id: 'name',
label: t('table_column_name'),
isSortable: false,
cell: ({ name }) => (
<DataGridTextCell className="truncate">{name}</DataGridTextCell>
),
},
{
id: 'status',
label: t('table_column_status'),
isSortable: false,
size: 50,
cell: ({ active }) => (
<DataGridTextCell>
<RoutingStatusChip active={active} />
</DataGridTextCell>
),
},
{
id: 'actions',
label: '',
size: 50,
isSortable: false,
cell: (routing) => (
<div className="flex flex-row justify-center">
<RoutingActionMenu routing={routing} />
</div>
),
}
],
[t],
);

const {
flattenData,
isLoading: isLoadingRouting,
hasNextPage,
fetchNextPage,
} = useResourcesIcebergV2<NotificationRouting>({
columns,
route: '/notification/routing',
queryKey: getNotificationRoutingQueryKey(),
enabled: isAuthorized,
});

const isLoading = isLoadingRouting || isLoadingAuthorization;

return (
<div className="flex flex-col gap-4">
<OdsText preset="paragraph" className="mb-6">
{t('description')}
</OdsText>

{!isLoading && !isAuthorized && (
<OdsMessage color="warning" isDismissible={false} className="w-full">
{t('common:iam_display_content_message', { ns: 'common' })}
</OdsMessage>
)}

<Notifications clearAfterRead />

<Datagrid
items={flattenData}
columns={columns}
isLoading={isLoading}
tableLayoutFixed={true}
topbar={
<ManagerButton
id="add-routing-button"
iamActions={['account:apiovh:notification/routing/create']}
urn={accountUrn}
icon="plus"
label={t('add_routing_button')}
aria-label={t('add_routing_button')}
size="sm"
onClick={() => {}}
/>
}
totalItems={flattenData?.length || 0}
hasNextPage={hasNextPage}
onFetchNextPage={fetchNextPage}
manualSorting={true}
/>

<Outlet />
</div>
);
}

export default SettingsPage;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { NotificationRouting } from '@/data/types/routing.type';

export enum NotificationRoutingActions {
EDIT = 'EDIT',
DELETE = 'DELETE',
ENABLE = 'ENABLE',
DISABLE = 'DISABLE',
}

export const displayActionMenuItem = (
routing: NotificationRouting,
action: NotificationRoutingActions,
): boolean => {
switch (action) {
case NotificationRoutingActions.EDIT:
case NotificationRoutingActions.DISABLE:
return routing.active;
case NotificationRoutingActions.ENABLE:
return !routing.active;
case NotificationRoutingActions.DELETE:
return true;
default:
return false;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const CommunicationsPage = lazy(() =>
const CommunicationsDetailPage = lazy(() =>
import('@/pages/communications/detail/CommunicationsDetail.page'),
);
const SettingsPage = lazy(() => import('@/pages/settings'));
const SettingsPage = lazy(() => import('@/pages/settings/Settings.page'));

export default (
<Route
Expand Down
Loading