diff --git a/front/public/locales/en/translation.json b/front/public/locales/en/translation.json index cf31a2b37c7..08564436f9d 100644 --- a/front/public/locales/en/translation.json +++ b/front/public/locales/en/translation.json @@ -429,6 +429,7 @@ "pick-track-cancel": "Undo line selection", "save-switch": "Save the switch" }, + "duplicate-errors": "The track {{track}} is already used by the port {{port}}", "endpoint": "Endpoint:", "help": { "no-move": "Switches cannot be moved, and are automatically placed on their first port.", diff --git a/front/public/locales/fr/translation.json b/front/public/locales/fr/translation.json index 084ad229e9a..e4daeef8823 100644 --- a/front/public/locales/fr/translation.json +++ b/front/public/locales/fr/translation.json @@ -429,6 +429,7 @@ "pick-track-cancel": "Annuler la sélection d'une ligne", "save-switch": "Sauvegarder l'aiguillage" }, + "duplicate-errors": "La voie {{track}} est déjà utilisée par le port {{port}}", "endpoint": "Extrémité :", "help": { "no-move": "Les aiguillages ne peuvent pas être déplacés, et sont automatiquement placés sur leur premier port.", diff --git a/front/src/applications/editor/tools/switchEdition/components.tsx b/front/src/applications/editor/tools/switchEdition/components.tsx index 4f3000d24aa..0a473ab59a6 100644 --- a/front/src/applications/editor/tools/switchEdition/components.tsx +++ b/front/src/applications/editor/tools/switchEdition/components.tsx @@ -94,6 +94,7 @@ export const SwitchEditionLeftPanel = () => { }} onSubmit={async (flatSwitch) => { const entityToSave = flatSwitchToSwitch(switchType, flatSwitch as FlatSwitchEntity); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const res: any = await dispatch( save( diff --git a/front/src/applications/editor/tools/switchEdition/components/TrackSectionEndpointSelector.tsx b/front/src/applications/editor/tools/switchEdition/components/TrackSectionEndpointSelector.tsx index 72cfffaf64d..b734a880019 100644 --- a/front/src/applications/editor/tools/switchEdition/components/TrackSectionEndpointSelector.tsx +++ b/front/src/applications/editor/tools/switchEdition/components/TrackSectionEndpointSelector.tsx @@ -1,10 +1,10 @@ -import React, { useCallback, useContext, useEffect, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import Select from 'react-select'; import { useTranslation } from 'react-i18next'; import { FaMapMarkedAlt, FaTimesCircle } from 'react-icons/fa'; import type { FieldProps } from '@rjsf/core'; -import { keyBy } from 'lodash'; +import { isEmpty, isNil, keyBy } from 'lodash'; import EditorContext from 'applications/editor/context'; import { getEntity } from 'applications/editor/data/api'; @@ -29,6 +29,22 @@ const TrackSectionEndpointSelector = ({ schema, formData, onChange, name }: Fiel const { state, setState } = useContext( EditorContext ) as ExtendedEditorContextType; + + const duplicateWith = useMemo(() => { + const allPorts = Object.entries(state.entity.properties?.ports ?? {}); + const ports = allPorts + .filter(([_, v]) => !isNil(v) && !isEmpty(v)) + .map(([k, v]) => ({ + ...v, + port: k, + name: `port::${k}`, + })); + + if (!ports.length) return []; + const currentPort = ports.find((p) => p.name === name); + return ports.filter((p) => p.name !== name && p.track === currentPort?.track); + }, [state.entity.properties]); + const { t } = useTranslation(); const infraID = useInfraID(); @@ -89,6 +105,14 @@ const TrackSectionEndpointSelector = ({ schema, formData, onChange, name }: Fiel
{schema.title &&
{schema.title}
} {schema.description &&

{schema.description}

} + {duplicateWith.map(({ track, port }, i) => ( +
+ {t('Editor.tools.switch-edition.duplicate-errors', { + track, + port, + })} +
+ ))}
{trackSection ? ( diff --git a/front/src/applications/editor/tools/switchEdition/tool.tsx b/front/src/applications/editor/tools/switchEdition/tool.tsx index afb8e79ea7d..6c54f31f51b 100644 --- a/front/src/applications/editor/tools/switchEdition/tool.tsx +++ b/front/src/applications/editor/tools/switchEdition/tool.tsx @@ -7,6 +7,7 @@ import { save } from 'reducers/editor'; import { SwitchEntity, SwitchType } from 'types'; import { ConfirmModal } from 'common/BootstrapSNCF/ModalSNCF'; +import { filter, groupBy } from 'lodash'; import { NEW_ENTITY_ID } from '../../data/utils'; import { Tool } from '../editorContextTypes'; import { DEFAULT_COMMON_TOOL_STATE } from '../commonToolState'; @@ -49,7 +50,19 @@ const SwitchEditionTool: Tool = { icon: AiFillSave, labelTranslationKey: 'Editor.tools.switch-edition.actions.save-switch', isDisabled({ isLoading, state }) { - return state.portEditionState.type !== 'idle' || isLoading || false; + const portWithTracks = filter(state.entity?.properties?.ports ?? {}, (p) => !!p?.track); + const portsKeys = Object.keys(state.entity?.properties?.ports ?? {}); + const detectedDuplicates = filter( + groupBy(portWithTracks, 'track'), + (v, _) => v.length > 1 + ); + return ( + state.portEditionState.type !== 'idle' || + portWithTracks.length !== portsKeys.length || + !!detectedDuplicates.length || + isLoading || + false + ); }, async onClick({ setIsFormSubmited }) { if (setIsFormSubmited) {