Skip to content

Commit

Permalink
fix(pn-13840): Handle previously unhandled errors on sender dashboard (
Browse files Browse the repository at this point in the history
  • Loading branch information
alessandrogelmi authored Feb 20, 2025
1 parent 81a7208 commit 1f1fe43
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 72 deletions.
10 changes: 9 additions & 1 deletion packages/pn-pa-webapp/public/locales/it/statistics.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,15 @@
"pec_title": "Errore di dominio PEC",
"pec_description": "La notifica non è stata recapitata per dominio PEC non valido",
"rejected_title": "Errore d'invio",
"rejected_description": "La notifica non è stata accettata per problemi tecnici d'invio"
"rejected_description": "La notifica non è stata accettata per problemi tecnici d'invio",
"virus_detected_title": "Rilevato virus",
"virus_detected_description": "La notifica non è stata recapitata a causa della rilevazione di un virus nella comunicazione o nei suoi allegati",
"server_pec_comunication_title": "Errore di comunicazione con il server PEC",
"server_pec_comunication_description": "La notifica non è stata recapitata a causa di un errore nella comunicazione con il server di invio PEC",
"sending_pec_title": "Errore durante l'invio della PEC",
"sending_pec_description": "La notifica non è stata recapitata a causa di un errore tecnico",
"malformed_pec_address_title": "Errore di indirizzo PEC",
"malformed_pec_address_description": "La notifica non è stata recapitata perchè l’indirizzo PEC è malformato"
},
"empty": {
"no_data_found": "Non ci sono dati a disposizione per l'intervallo di tempo selezionato",
Expand Down
24 changes: 24 additions & 0 deletions packages/pn-pa-webapp/src/__mocks__/Statistics.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,10 @@ export const parsedResponseMock: StatisticsParsedResponse = {
[DigitaErrorTypes.INVALID_PEC]: { count: 4, attempts: 7 },
[DigitaErrorTypes.DELIVERY_ERROR]: { count: 4, attempts: 11 },
[DigitaErrorTypes.REJECTED]: { count: 0, attempts: 0 },
[DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: { count: 0, attempts: 0 },
[DigitaErrorTypes.SENDING_PEC]: { count: 0, attempts: 0 },
[DigitaErrorTypes.SERVER_PEC_COMUNICATION]: { count: 0, attempts: 0 },
[DigitaErrorTypes.VIRUS_DETECTED]: { count: 0, attempts: 0 },
[DigitaErrorTypes.UNKNOWN]: { count: 461, attempts: 0 },
},
},
Expand Down Expand Up @@ -348,6 +352,10 @@ export const parsedEmptyResponseMock: StatisticsParsedResponse = {
[DigitaErrorTypes.INVALID_PEC]: { count: 0, attempts: 0 },
[DigitaErrorTypes.DELIVERY_ERROR]: { count: 0, attempts: 0 },
[DigitaErrorTypes.REJECTED]: { count: 0, attempts: 0 },
[DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: { count: 0, attempts: 0 },
[DigitaErrorTypes.SENDING_PEC]: { count: 0, attempts: 0 },
[DigitaErrorTypes.SERVER_PEC_COMUNICATION]: { count: 0, attempts: 0 },
[DigitaErrorTypes.VIRUS_DETECTED]: { count: 0, attempts: 0 },
[DigitaErrorTypes.UNKNOWN]: { count: 0, attempts: 0 },
},
},
Expand Down Expand Up @@ -436,6 +444,22 @@ export const digitalErrorsEmptyDataMock = {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.VIRUS_DETECTED]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.SERVER_PEC_COMUNICATION]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.SENDING_PEC]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: {
count: 0,
attempts: 0,
},
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable functional/immutable-data */
import React from 'react';
import { useTranslation } from 'react-i18next';

Expand Down Expand Up @@ -37,40 +36,61 @@ const DigitalErrorsDetailStatistics: React.FC<Props> = ({ data: sData }) => {
const delivery_errors = sData[DigitaErrorTypes.DELIVERY_ERROR].count;
const pec_errors = sData[DigitaErrorTypes.INVALID_PEC].count;
const rejected_errors = sData[DigitaErrorTypes.REJECTED].count;

const delivery_title = t('digital_errors_detail.delivery_title');
const delivery_description = t('digital_errors_detail.delivery_description');
const pec_title = t('digital_errors_detail.pec_title');
const pec_description = t('digital_errors_detail.pec_description');
const rejected_title = t('digital_errors_detail.rejected_title');
const rejected_description = t('digital_errors_detail.rejected_description');
const virus_detected_errors = sData[DigitaErrorTypes.VIRUS_DETECTED].count;
const server_pec_comunication_errors = sData[DigitaErrorTypes.SERVER_PEC_COMUNICATION].count;
const sending_pec_errors = sData[DigitaErrorTypes.SENDING_PEC].count;
const malformed_pec_address_errors = sData[DigitaErrorTypes.MALFORMED_PEC_ADDRESS].count;

const data: Array<AggregateErrorDetailDataItem> = [
{
title: delivery_title,
description: delivery_description,
title: t('digital_errors_detail.delivery_title'),
description: t('digital_errors_detail.delivery_description'),
value: delivery_errors,
color: GraphColors.lightRed,
},
{
title: pec_title,
description: pec_description,
title: t('digital_errors_detail.pec_title'),
description: t('digital_errors_detail.pec_description'),
value: pec_errors,
color: GraphColors.darkRed,
},
{
title: rejected_title,
description: rejected_description,
title: t('digital_errors_detail.rejected_title'),
description: t('digital_errors_detail.rejected_description'),
value: rejected_errors,
color: GraphColors.pink,
},
{
title: t('digital_errors_detail.virus_detected_title'),
description: t('digital_errors_detail.virus_detected_description'),
value: virus_detected_errors,
color: GraphColors.turquoise,
},
{
title: t('digital_errors_detail.server_pec_comunication_title'),
description: t('digital_errors_detail.server_pec_comunication_description'),
value: server_pec_comunication_errors,
color: GraphColors.blue,
},
{
title: t('digital_errors_detail.sending_pec_title'),
description: t('digital_errors_detail.sending_pec_description'),
value: sending_pec_errors,
color: GraphColors.darkGreen,
},
{
title: t('digital_errors_detail.malformed_pec_address_title'),
description: t('digital_errors_detail.malformed_pec_address_description'),
value: malformed_pec_address_errors,
color: GraphColors.navy,
},
];

const isEmpty = !data.find((item) => item.value > 0);
const isEmpty = data.every((item) => item.value === 0);

const aggregateData = [data[0], data[2], data[1]];
const aggregateData = data.filter((item) => item.value > 0);

const color = [GraphColors.lightRed, GraphColors.pink, GraphColors.darkRed];
const color = aggregateData.map((item) => item.color);

const options: PnEChartsProps['option'] = {
color,
Expand All @@ -79,35 +99,39 @@ const DigitalErrorsDetailStatistics: React.FC<Props> = ({ data: sData }) => {
return (
<Paper sx={{ p: 3, mb: 3 }} elevation={0} data-testid="digitalErrorsDetail">
<Grid container direction={{ lg: 'row', xs: 'column' }} spacing={3}>
<Grid item lg={5} xs={12} sx={{ p: { xs: 0, lg: 3 } }}>
<Grid item lg={isEmpty ? 12 : 5} xs={12} sx={{ p: { xs: 0, lg: 3 } }}>
<Typography variant="h6" component="h3">
{t('digital_errors_detail.title')}
</Typography>
<Typography sx={{ my: 3 }} variant="body1" color="text.primary">
{t('digital_errors_detail.description')}
</Typography>
<List>
{data.map((item) => {
const title = item.title;
const description = item.description;
const color = item.color;
const avatarSx = {
bgcolor: color,
width: 10,
height: 10,
};
return (
<ListItem key={title}>
<ListItemAvatar sx={{ minWidth: 18 }}>
<Avatar sx={avatarSx}>&nbsp;</Avatar>
</ListItemAvatar>
<ListItemText primary={title} secondary={description} />
</ListItem>
);
})}
</List>
{!isEmpty && (
<>
<Typography sx={{ my: 3 }} variant="body1" color="text.primary">
{t('digital_errors_detail.description')}
</Typography>
<List>
{aggregateData.map((item) => {
const title = item.title;
const description = item.description;
const color = item.color;
const avatarSx = {
bgcolor: color,
width: 10,
height: 10,
};
return (
<ListItem key={title}>
<ListItemAvatar sx={{ minWidth: 18 }}>
<Avatar sx={avatarSx}>&nbsp;</Avatar>
</ListItemAvatar>
<ListItemText primary={title} secondary={description} />
</ListItem>
);
})}
</List>
</>
)}
</Grid>
<Grid item lg={7} xs={12} sx={{ p: { xs: 0, lg: 3 } }}>
<Grid item lg={isEmpty ? 12 : 7} xs={12} sx={{ p: { xs: 0, lg: 3 } }}>
{isEmpty ? (
<EmptyStatistics />
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ describe('DeliveryModeStatistics component tests', () => {
expect(container).toHaveTextContent('digital_errors_detail.delivery_description');
expect(container).toHaveTextContent('digital_errors_detail.pec_title');
expect(container).toHaveTextContent('digital_errors_detail.pec_description');
expect(container).toHaveTextContent('digital_errors_detail.rejected_title');
expect(container).toHaveTextContent('digital_errors_detail.rejected_description');

const graph = getByTestId('Aggregate');
expect(graph).toBeInTheDocument();
Expand All @@ -86,20 +84,14 @@ describe('DeliveryModeStatistics component tests', () => {
value: digitalErrorsDataMock.data[DigitaErrorTypes.DELIVERY_ERROR].count,
color: GraphColors.lightRed,
},
{
title: 'digital_errors_detail.rejected_title',
description: 'digital_errors_detail.rejected_description',
value: digitalErrorsDataMock.data[DigitaErrorTypes.REJECTED].count,
color: GraphColors.pink,
},
{
title: 'digital_errors_detail.pec_title',
description: 'digital_errors_detail.pec_description',
value: digitalErrorsDataMock.data[DigitaErrorTypes.INVALID_PEC].count,
color: GraphColors.darkRed,
},
],
options: { color: [GraphColors.lightRed, GraphColors.pink, GraphColors.darkRed] },
options: { color: [GraphColors.lightRed, GraphColors.darkRed] },
startAngle: 180,
endAngle: -180,
radius: ['30%', '90%'],
Expand All @@ -112,13 +104,6 @@ describe('DeliveryModeStatistics component tests', () => {
<DigitalErrorsDetailStatistics {...digitalErrorsEmptyDataMock} />
);
expect(container).toHaveTextContent('digital_errors_detail.title');
expect(container).toHaveTextContent('digital_errors_detail.description');
expect(container).toHaveTextContent('digital_errors_detail.delivery_title');
expect(container).toHaveTextContent('digital_errors_detail.delivery_description');
expect(container).toHaveTextContent('digital_errors_detail.pec_title');
expect(container).toHaveTextContent('digital_errors_detail.pec_description');
expect(container).toHaveTextContent('digital_errors_detail.rejected_title');
expect(container).toHaveTextContent('digital_errors_detail.rejected_description');
expect(container).toHaveTextContent('empty.no_data_found');

const emptyImg = getByTestId('empty-image');
Expand Down
20 changes: 14 additions & 6 deletions packages/pn-pa-webapp/src/models/Statistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ export enum ResponseStatus { // EXPORT FROM pn-commons/../NotificationDetail.ts?
}

export enum DigitaErrorTypes {
INVALID_PEC = 'ERRORE DOMINIO PEC NON VALIDO',
DELIVERY_ERROR = 'ERRORE CONSEGNA',
REJECTED = 'NON ACCETTAZIONE',
UNKNOWN = '-',
DELIVERY_ERROR = 'ERRORE CONSEGNA',
VIRUS_DETECTED = 'RILEVAZIONE VIRUS',
SERVER_PEC_COMUNICATION = 'ERRORE COMUNICAZIONE SERVER PEC',
SENDING_PEC = 'ERRORE INVIO PEC',
INVALID_PEC = 'ERRORE DOMINIO PEC NON VALIDO',
MALFORMED_PEC_ADDRESS = 'ERRORE INDIRIZZO PEC MALFORMATO',
UNKNOWN = 'NON DEFINITO',
}

export enum StatisticsDataTypes {
Expand Down Expand Up @@ -161,9 +165,13 @@ export interface IAttemptsCount {
}

export interface IDigitalErrorsDetailStatistics {
[DigitaErrorTypes.INVALID_PEC]: IAttemptsCount;
[DigitaErrorTypes.DELIVERY_ERROR]: IAttemptsCount;
[DigitaErrorTypes.REJECTED]: IAttemptsCount;
[DigitaErrorTypes.DELIVERY_ERROR]: IAttemptsCount;
[DigitaErrorTypes.VIRUS_DETECTED]: IAttemptsCount;
[DigitaErrorTypes.SERVER_PEC_COMUNICATION]: IAttemptsCount;
[DigitaErrorTypes.SENDING_PEC]: IAttemptsCount;
[DigitaErrorTypes.INVALID_PEC]: IAttemptsCount;
[DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: IAttemptsCount;
[DigitaErrorTypes.UNKNOWN]: IAttemptsCount;
}

Expand Down Expand Up @@ -209,7 +217,7 @@ export const SelectedStatisticsFilter = {
} as const;

export type SelectedStatisticsFilterKeys =
typeof SelectedStatisticsFilter[keyof typeof SelectedStatisticsFilter];
(typeof SelectedStatisticsFilter)[keyof typeof SelectedStatisticsFilter];

export type StatisticsFilter = {
selected: SelectedStatisticsFilterKeys | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,31 @@ import StatisticsData from './StatisticsData';
*/
export class DigitalErrorsDetailStatisticsData extends StatisticsData {
data: IDigitalErrorsDetailStatistics = {
[DigitaErrorTypes.INVALID_PEC]: {
[DigitaErrorTypes.REJECTED]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.DELIVERY_ERROR]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.REJECTED]: {
[DigitaErrorTypes.VIRUS_DETECTED]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.SERVER_PEC_COMUNICATION]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.SENDING_PEC]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.INVALID_PEC]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: {
count: 0,
attempts: 0,
},
Expand All @@ -50,28 +66,52 @@ export class DigitalErrorsDetailStatisticsData extends StatisticsData {
return this;
}

isDigitalErrorsDetailStatistics(type: string): type is DigitaErrorTypes {
return (Object.values(DigitaErrorTypes) as Array<string>).includes(type);
}

parseChunk(chunk: NotificationOverview | DigitalNotificationFocus): void {
// parse only if chunk is a DigitalNotificationFocus
if ('error_type' in chunk) {
const type = chunk.error_type;

this.data[type as keyof IDigitalErrorsDetailStatistics].attempts +=
+chunk.failed_attempts_count;
this.data[type as keyof IDigitalErrorsDetailStatistics].count += +chunk.notifications_count;
if (this.isDigitalErrorsDetailStatistics(type)) {
this.data[type].attempts += +chunk.failed_attempts_count;
this.data[type].count += +chunk.notifications_count;
} else {
this.data[DigitaErrorTypes.UNKNOWN].attempts += +chunk.failed_attempts_count;
this.data[DigitaErrorTypes.UNKNOWN].count += +chunk.notifications_count;
}
}
}

resetData(): void {
this.data = {
[DigitaErrorTypes.INVALID_PEC]: {
[DigitaErrorTypes.REJECTED]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.DELIVERY_ERROR]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.REJECTED]: {
[DigitaErrorTypes.VIRUS_DETECTED]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.SERVER_PEC_COMUNICATION]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.SENDING_PEC]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.INVALID_PEC]: {
count: 0,
attempts: 0,
},
[DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: {
count: 0,
attempts: 0,
},
Expand Down

0 comments on commit 1f1fe43

Please sign in to comment.