Skip to content

Commit

Permalink
front: refacto of error management with notification
Browse files Browse the repository at this point in the history
Follows the PR on the generation of I18N keys for API errors.
This commit :
- centralized the code where we cast error for notification
- use i18n for name and message
  • Loading branch information
sim51 committed Feb 22, 2024
1 parent 906da79 commit 07c6906
Show file tree
Hide file tree
Showing 33 changed files with 248 additions and 384 deletions.
2 changes: 1 addition & 1 deletion front/public/locales/en/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
},
"objects": {
"DuplicateIdsProvided": "Duplicate object ids provided",
"ObjectIdNotFound": "Object ID not found"
"ObjectIdNotFound": "Object '{{object_id}}' not found"
},
"pathfinding": {
"EndingTrackLocationNotFound": "Ending track location was not found",
Expand Down
2 changes: 1 addition & 1 deletion front/public/locales/fr/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
},
"objects": {
"DuplicateIdsProvided": "Identifiants d'objet fournis en double",
"ObjectIdNotFound": "Objet ID non trouvé"
"ObjectIdNotFound": "Objet '{{object_id}}' non trouvé"
},
"pathfinding": {
"EndingTrackLocationNotFound": "Localisation de la fin de la section non trouvé",
Expand Down
20 changes: 7 additions & 13 deletions front/src/applications/editor/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { SerializedError } from '@reduxjs/toolkit';
import cx from 'classnames';
import { isNil, toInteger } from 'lodash';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
Expand All @@ -7,10 +6,8 @@ import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';

import { ApiError } from 'common/api/baseGeneratedApis';
import type { ObjectType } from 'common/api/osrdEditoastApi';
import { useInfraID, useOsrdActions } from 'common/osrdContext';

import type { EditorSliceActions } from 'reducers/editor';
import { useModal } from 'common/BootstrapSNCF/ModalSNCF';
import MapButtons from 'common/Map/Buttons/MapButtons';
Expand All @@ -23,8 +20,7 @@ import { getEditorState, getInfraLockStatus } from 'reducers/editor/selectors';
import { loadDataModel, updateTotalsIssue } from 'reducers/editor/thunkActions';
import { updateViewport, type Viewport } from 'reducers/map';
import { setFailure } from 'reducers/main';
import { extractMessageFromError } from 'utils/error';

import { castErrorToFailure } from 'utils/error';
import { getEntity, getMixedEntities } from 'applications/editor/data/api';
import { NEW_ENTITY_ID } from 'applications/editor/data/utils';
import { useSwitchTypes } from 'applications/editor/tools/switchEdition/types';
Expand All @@ -37,7 +33,6 @@ import type { switchProps } from 'applications/editor/tools/switchProps';
import { centerMapOnObject, selectEntities } from 'applications/editor/tools/utils';
import TOOLS from 'applications/editor/tools/constsTools';
import TOOL_NAMES from 'applications/editor/tools/constsToolNames';

import type { EditoastType } from './consts';
import type { EditorContextType, ExtendedEditorContextType, FullTool, Reducer } from './types';
import type { EditorEntity } from './typesEditorEntity';
Expand Down Expand Up @@ -244,13 +239,12 @@ const Editor = () => {
if (mapRef.current) centerMapOnObject(+urlInfra, entities, dispatch, mapRef.current);
} catch (e) {
dispatch(
setFailure({
name: t('translation:Editor.tools.select-items.errors.unable-to-select'),
message:
extractMessageFromError(e as ApiError | SerializedError) !== 'undefined'
? extractMessageFromError(e as ApiError | SerializedError)
: t('translation:Editor.tools.select-items.errors.invalid-url'),
})
setFailure(
castErrorToFailure(e, {
name: t('translation:Editor.tools.select-items.errors.unable-to-select'),
message: t('translation:Editor.tools.select-items.errors.invalid-url'),
})
)
);
}
};
Expand Down
5 changes: 2 additions & 3 deletions front/src/applications/editor/components/EditorForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { translateSchema } from 'applications/editor/tools/translationTools';
import { getEditorState } from 'reducers/editor/selectors';
import type { EditorEntity } from 'applications/editor/typesEditorEntity';

import { getErrorMessage } from 'utils/error';
import { FormComponent, FormLineStringLength } from './LinearMetadata';

const fields = {
Expand Down Expand Up @@ -119,8 +119,7 @@ function EditorForm<T extends Omit<EditorEntity, 'objType'> & { objType: string
setError(null);
await onSubmit({ ...data, properties: { ...data.properties, ...formData } });
} catch (e) {
if (e instanceof Error) setError(e.message);
else setError(JSON.stringify(e));
setError(getErrorMessage(e));
} finally {
setSubmited(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ import {
TrainScheduleSummary,
osrdEditoastApi,
} from 'common/api/osrdEditoastApi';
import { extractMessageFromError } from 'utils/error';
import { castErrorToFailure } from 'utils/error';
import { AllowancesSettings, Projection } from 'reducers/osrdsimulation/types';
import { ApiError } from 'common/api/baseGeneratedApis';
import { SerializedError } from '@reduxjs/toolkit';
import { differenceBy } from 'lodash';

export function selectProjection(
Expand Down Expand Up @@ -132,12 +130,12 @@ export default async function getSimulationResults(
store.dispatch(updateAllowancesSettings(newAllowancesSettings));
} catch (e) {
store.dispatch(
setFailure({
name: i18n.t('simulation:errorMessages.unableToRetrieveTrainSchedule'),
message: extractMessageFromError(e as ApiError | SerializedError),
})
setFailure(
castErrorToFailure(e, {
name: i18n.t('simulation:errorMessages.unableToRetrieveTrainSchedule'),
})
)
);
console.error('trainScheduleResults error : ', e);
} finally {
store.dispatch(updateIsUpdating(false));
}
Expand Down
25 changes: 9 additions & 16 deletions front/src/applications/stdcm/views/StdcmRequestModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { Spinner } from 'common/Loaders';
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import type { SimulationReport } from 'common/api/osrdEditoastApi';
import type { StdcmRequestStatus } from 'applications/stdcm/types';
import { extractMessageFromError, extractStatusFromError } from 'utils/error';
import { castErrorToFailure } from 'utils/error';
import { Train } from 'reducers/osrdsimulation/types';
import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext';
import { useAppDispatch } from 'store';
Expand Down Expand Up @@ -104,29 +104,22 @@ export default function StdcmRequestModal(props: StdcmRequestModalProps) {
})
);
})
.catch(() => {
.catch((e) => {
dispatch(
setFailure({
name: t('stdcm:stdcmError'),
message: t('translation:common.error'),
})
setFailure(
castErrorToFailure(e, {
name: t('stdcm:stdcmError'),
message: t('translation:common.error'),
})
)
);
});
});
}
})
.catch((e) => {
const errorMessage = extractMessageFromError(e);
setCurrentStdcmRequestStatus(STDCM_REQUEST_STATUS.rejected);
dispatch(
setFailure({
name: t('stdcm:stdcmError'),
message:
extractStatusFromError(e) === 400 && errorMessage === 'No path could be found'
? t('stdcm:stdcmErrorNoPaths')
: errorMessage,
})
);
dispatch(setFailure(castErrorToFailure(e, { name: t('stdcm:stdcmError') })));
});
}
}, [currentStdcmRequestStatus]);
Expand Down
4 changes: 2 additions & 2 deletions front/src/common/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { Link, useNavigate, useRouteError } from 'react-router-dom';
import { SerializedError } from '@reduxjs/toolkit';
import { useTranslation } from 'react-i18next';
import { extractMessageFromError } from 'utils/error';
import { getErrorMessage } from 'utils/error';
import { ApiError } from 'common/api/baseGeneratedApis';
import NavBarSNCF from 'common/BootstrapSNCF/NavBarSNCF';
import { ModalProvider } from 'common/BootstrapSNCF/ModalSNCF/ModalProvider';
Expand All @@ -21,7 +21,7 @@ export default function ErrorBoundary() {
<h1>
{t(`errors:${(error as ApiError).status ? (error as ApiError).status : 'default'}`)}
</h1>
<p>{extractMessageFromError(error)}</p>
<p>{getErrorMessage(error)}</p>
</>
) : (
<h1>{t('errors:pageNotFound')}</h1>
Expand Down
10 changes: 4 additions & 6 deletions front/src/common/Map/Search/MapSearchSignal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getMap } from 'reducers/map/selectors';
import { setFailure } from 'reducers/main';
import { sortBy } from 'lodash';
import { useDebounce } from 'utils/helpers';
import { castErrorToFailure } from 'utils/error';
import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import InputSNCF from 'common/BootstrapSNCF/InputSNCF';
Expand All @@ -14,7 +15,6 @@ import MultiSelectSNCF from 'common/BootstrapSNCF/MultiSelectSNCF';
import nextId from 'react-id-generator';
import SelectImproved from 'common/BootstrapSNCF/SelectImprovedSNCF';
import SignalCard from 'common/Map/Search/SignalCard';

import type { SearchResultItemSignal, SearchPayload } from 'common/api/osrdEditoastApi';
import { useAppDispatch } from 'store';
import type { Viewport } from 'reducers/map';
Expand Down Expand Up @@ -137,13 +137,11 @@ const MapSearchSignal = ({ updateExtViewport, closeMapSearchPopUp }: MapSearchSi
setSearchResults([...results] as SearchResultItemSignal[]);
})
.catch((e) => {
console.error(e);
setSearchResults([]);
dispatch(
setFailure({
name: t('map-search:errorMessages.unableToSearchSignal'),
message: `${e.message}`,
})
setFailure(
castErrorToFailure(e, { name: t('map-search:errorMessages.unableToSearchSignal') })
)
);
});
};
Expand Down
15 changes: 6 additions & 9 deletions front/src/common/Map/Settings/MapSettingsSpeedLimits.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,24 @@ import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { IoMdSpeedometer } from 'react-icons/io';
import type { IconType } from 'react-icons';
import type { SerializedError } from '@reduxjs/toolkit';

import TIVsSVGFile from 'assets/pictures/layersicons/layer_tivs.svg';

import DotsLoader from 'common/DotsLoader/DotsLoader';
import { useInfraID } from 'common/osrdContext';
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import type { ApiError } from 'common/api/baseGeneratedApis';
import SelectImprovedSNCF from 'common/BootstrapSNCF/SelectImprovedSNCF';
import SwitchSNCF, { SWITCH_TYPES } from 'common/BootstrapSNCF/SwitchSNCF/SwitchSNCF';
import {
FormatSwitch as SimpleFormatSwitch,
Icon2SVG,
} from 'common/Map/Settings/MapSettingsLayers';

import { useAppDispatch } from 'store';
import { setFailure } from 'reducers/main';
import { getMap } from 'reducers/map/selectors';
import { updateLayersSettings } from 'reducers/map';
import type { MapState } from 'reducers/map';
import { castErrorToFailure } from 'utils/error';

type FormatSwitchProps = {
name: keyof MapState['layersSettings'];
Expand Down Expand Up @@ -76,12 +74,11 @@ const FormatSwitch = ({ name, icon: IconComponent, color = '', disabled }: Forma
useEffect(() => {
if (isGetSpeedLimitTagsError && getSpeedLimitTagsError) {
dispatch(
setFailure({
name: t('errorMessages.unableToRetrieveTags'),
message:
`${(getSpeedLimitTagsError as ApiError).data.message}` ||
`${(getSpeedLimitTagsError as SerializedError).message}}`,
})
setFailure(
castErrorToFailure(getSpeedLimitTagsError, {
name: t('errorMessages.unableToRetrieveTags'),
})
)
);
}
}, [isGetSpeedLimitTagsError]);
Expand Down
14 changes: 3 additions & 11 deletions front/src/common/Pathfinding/Pathfinding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,18 @@ import type { Position } from 'geojson';
import bbox from '@turf/bbox';
import { useTranslation } from 'react-i18next';
import { compact, isEqual, omit } from 'lodash';
import { Alert, CheckCircle, Stop } from '@osrd-project/ui-icons';

import { Alert, CheckCircle, Stop } from '@osrd-project/ui-icons';
import type { ArrayElement } from 'utils/types';
import { conditionalStringConcat, formatKmValue } from 'utils/strings';

import { castErrorToFailure } from 'utils/error';
import type { PathResponse, PathfindingRequest, PathfindingStep } from 'common/api/osrdEditoastApi';

import infraLogo from 'assets/pictures/components/tracks.svg';
import type { PointOnMap } from 'applications/operationalStudies/consts';
import InfraLoadingState from 'applications/operationalStudies/components/Scenario/InfraLoadingState';

import { Spinner } from 'common/Loaders';
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext';

import { useAppDispatch } from 'store';
import { setFailure } from 'reducers/main';

Expand Down Expand Up @@ -420,12 +417,7 @@ function Pathfinding({ zoomToFeature, path }: PathfindingProps) {
})
.catch((e) => {
if (e.error) {
dispatch(
setFailure({
name: t('pathfinding'),
message: e.error,
})
);
dispatch(setFailure(castErrorToFailure(e, { name: t('pathfinding') })));
pathfindingDispatch({ type: 'PATHFINDING_ERROR', message: 'failedRequest' });
} else if (e?.data?.message) {
pathfindingDispatch({ type: 'PATHFINDING_ERROR', message: e.data.message });
Expand Down
11 changes: 2 additions & 9 deletions front/src/common/Pathfinding/TypeAndPath.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ import type { Position } from 'geojson';
import cx from 'classnames';

import { useDebounce } from 'utils/helpers';

import { castErrorToFailure } from 'utils/error';
import { loadPathFinding } from 'modules/trainschedule/components/ManageTrainSchedule/helpers/adjustConfWithTrainToModify';

import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import { useInfraID, useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext';

import { useAppDispatch } from 'store';
import { setFailure } from 'reducers/main';

Expand Down Expand Up @@ -134,12 +132,7 @@ export default function TypeAndPath({ zoomToFeature }: PathfindingProps) {
loadPathFinding(itineraryCreated, dispatch, osrdActions);
})
.catch((e) => {
dispatch(
setFailure({
name: e.data.name,
message: e.data.message,
})
);
dispatch(setFailure(castErrorToFailure(e)));
});
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import { useOsrdConfSelectors, useOsrdConfActions, useInfraID } from 'common/osrdContext';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { useAppDispatch } from 'store';

import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import { useOsrdConfSelectors, useOsrdConfActions, useInfraID } from 'common/osrdContext';
import { setFailure } from 'reducers/main';
import { castErrorToFailure } from 'utils/error';

export const useStoreDataForSpeedLimitByTagSelector = () => {
const dispatch = useAppDispatch();
Expand All @@ -32,12 +33,7 @@ export const useStoreDataForSpeedLimitByTagSelector = () => {
// Update the document title using the browser API
if (error) {
dispatch(
setFailure({
name: t('errorMessages.unableToRetrieveTags'),
message: `${(error as FetchBaseQueryError).status} : ${JSON.stringify(
(error as FetchBaseQueryError).data
)}`,
})
setFailure(castErrorToFailure(error, { name: t('errorMessages.unableToRetrieveTags') }))
);
}
}, [error]);
Expand Down
4 changes: 4 additions & 0 deletions front/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ i18n
},
});

// Errors namespace must be initialized so t function
// can be used in plain old function (see utils/error)
i18n.loadNamespaces('errors');

export default i18n;
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { useEffect } from 'react';
import { useTranslation } from 'react-i18next';

import { castErrorToFailure } from 'utils/error';
import { useInfraID } from 'common/osrdContext';
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';

import { useAppDispatch } from 'store';
import { setFailure } from 'reducers/main';

import InfraSelectorModal from './InfraSelectorModal';

type InfraSelectorProps = {
Expand All @@ -24,10 +23,7 @@ const InfraSelector = ({ isInEditor }: InfraSelectorProps) => {
.unwrap()
.catch((e) =>
dispatch(
setFailure({
name: t('errorMessages.unableToRetrieveInfra'),
message: e.message,
})
setFailure(castErrorToFailure(e, { name: t('errorMessages.unableToRetrieveInfra') }))
)
);
};
Expand Down
Loading

0 comments on commit 07c6906

Please sign in to comment.