From 8969f1c2e2d39ea4cec1b60386545172514027ec Mon Sep 17 00:00:00 2001 From: SharglutDev Date: Wed, 29 Nov 2023 11:43:59 +0100 Subject: [PATCH] front: editor: move save button to action bar --- front/public/locales/en/translation.json | 13 ++-- front/public/locales/fr/translation.json | 15 ++-- front/src/applications/editor/Editor.tsx | 7 ++ front/src/applications/editor/Map.tsx | 5 +- .../editor/components/EditorForm.tsx | 56 ++++++++++---- .../editor/tools/editorContextTypes.ts | 3 + .../editor/tools/rangeEdition/components.tsx | 65 +--------------- .../tools/rangeEdition/tool-factory.tsx | 63 ++++++++++++++-- .../editor/tools/rangeEdition/utils.ts | 3 + .../editor/tools/selection/components.tsx | 18 ++--- .../editor/tools/selection/tool.tsx | 4 +- .../editor/tools/trackEdition/components.tsx | 48 +----------- .../editor/tools/trackEdition/tool.tsx | 75 ++++++++++++++++--- 13 files changed, 209 insertions(+), 166 deletions(-) diff --git a/front/public/locales/en/translation.json b/front/public/locales/en/translation.json index 6579ef55945..4935e9901f9 100644 --- a/front/public/locales/en/translation.json +++ b/front/public/locales/en/translation.json @@ -233,9 +233,10 @@ "catenary-edition": { "actions": { "confirm-delete-catenary": "Are you sure you want to remove the catenary?", + "delete-catenary": "Delete the catenary", "new-catenary": "Create a new catenary", "reset-catenary": "Cancel the current modifications", - "delete-catenary": "Delete the catenary" + "save-catenary": "Save the catenary" }, "help": { "init": "Click on a track section to link it to the catenary", @@ -246,8 +247,6 @@ "catenaries": "Electrification", "catenary-default": "Default catenary", "label": "Catenary tool", - "save-existing-catenary": "Save modifications", - "save-new-catenary": "Save the new catenary", "voltage": "{{voltage}}V" }, "detector-edition": { @@ -382,9 +381,10 @@ "speed-edition": { "actions": { "confirm-delete-speed-section": "Are you sure you want to remove the speed limit?", + "delete-speed-section": "Delete the speed limit", "new-speed-section": "Create a new speed limit", "reset-speed-section": "Cancel the current modifications", - "delete-speed-section": "Delete the speed limit" + "save-speed-section": "Save the speed limit" }, "add-new-speed-limit": "Add new speed limit", "add-sign": "Add a sign from {{signType}} type", @@ -408,8 +408,6 @@ "sign-value": "Speed", "signs-section-list": "Section signs list", "remove-track-range": "Click to detatch from:", - "save-existing-speed-section": "Save modifications", - "save-new-speed-section": "Save the new speed limit", "speed-limits": "Speed limits", "toggle-psl": "Permanent speed limit", "toggle-psl-help": "Click on a track section first to be able to activate this option" @@ -442,7 +440,8 @@ "mode-add-point": "Add a point", "mode-delete-point": "Delete points", "mode-move-point": "Move points", - "toggle-anchoring": "Toggle anchoring on/off" + "toggle-anchoring": "Toggle anchoring on/off", + "save-line": "Save the line" }, "help": { "add-anchor-point": "Click to add a point at the end of the track section. Click on the track to add an intermediate point.", diff --git a/front/public/locales/fr/translation.json b/front/public/locales/fr/translation.json index d3b899ae5f1..b2738d41421 100644 --- a/front/public/locales/fr/translation.json +++ b/front/public/locales/fr/translation.json @@ -233,12 +233,13 @@ "catenary-edition": { "actions": { "confirm-delete-catenary": "Êtes-vous sûr(e) de vouloir supprimer l'électrification ?", + "delete-catenary": "Supprimer l'électrification", "new-catenary": "Créer une nouvelle électrification", "reset-catenary": "Annuler les modifications en cours", - "delete-catenary": "Supprimer l'électrification" + "save-catenary": "Sauvegarder l'électrification" }, "help": { - "init":"Cliquez sur un tronçon d'itinéraire pour l'associer à l'électrification", + "init": "Cliquez sur un tronçon d'itinéraire pour l'associer à l'électrification", "add-track": "Ajouter le tronçon '{{track.id}}' à l'électrification {{voltage}}", "remove-range": "Supprimer le tronçon de l'électrification {{voltage}}" }, @@ -246,8 +247,6 @@ "catenaries": "Électrification", "catenary-default": "Électrification par défaut", "label": "Outil \"Électrification\"", - "save-existing-catenary": "Sauvegarder les modifications", - "save-new-catenary": "Sauvegarder la nouvelle électrification", "voltage": "{{voltage}}V" }, "detector-edition": { @@ -382,9 +381,10 @@ "speed-edition": { "actions": { "confirm-delete-speed-section": "Êtes-vous sûr(e) de vouloir supprimer la vitesse limite ?", + "delete-speed-section": "Supprimer la vitesse limite", "new-speed-section": "Créer une nouvelle vitesse limite", "reset-speed-section": "Annuler les modifications en cours", - "delete-speed-section": "Supprimer la vitesse limite" + "save-speed-section": "Sauvegarder la vitesse limite" }, "add-new-speed-limit": "Ajouter une nouvelle limitation", "add-sign": "Ajouter un panneau de type {{signType}}", @@ -408,8 +408,6 @@ "sign-value": "Vitesse", "signs-section-list": "Liste des panneaux de la section", "remove-track-range": "Cliquer pour détacher de :", - "save-existing-speed-section": "Sauvegarder les modifications", - "save-new-speed-section": "Sauvegarder la nouvelle limite de vitesse", "speed-limits": "Limitations de vitesses", "toggle-psl": "Limite permanente de vitesse", "toggle-psl-help": "Cliquez d'abord sur un tronçon d'itinéraire pour pouvoir activer cette option" @@ -442,7 +440,8 @@ "mode-add-point": "Ajouter un point", "mode-delete-point": "Supprimer des points", "mode-move-point": "Déplacer les points", - "toggle-anchoring": "Activer / désactiver l'ancrage automatique" + "toggle-anchoring": "Activer / désactiver l'ancrage automatique", + "save-line": "Sauvegarder la ligne" }, "help": { "add-anchor-point": "Cliquez pour ajouter un point au bout de la section de ligne. Cliquez sur la ligne pour ajouter un point intermédiaire.", diff --git a/front/src/applications/editor/Editor.tsx b/front/src/applications/editor/Editor.tsx index c5ddc1dfbbf..11f65c22d62 100644 --- a/front/src/applications/editor/Editor.tsx +++ b/front/src/applications/editor/Editor.tsx @@ -15,6 +15,7 @@ import { loadDataModel, selectLayers, updateTotalsIssue } from 'reducers/editor' import { updateInfraID } from 'reducers/osrdconf'; import { updateViewport, Viewport } from 'reducers/map'; import { getInfraID } from 'reducers/osrdconf/selectors'; +import { getIsLoading } from 'reducers/main/mainSelector'; import useKeyboardShortcuts from 'utils/hooks/useKeyboardShortcuts'; import MapSearch from 'common/Map/Search/MapSearch'; import Tipped from './components/Tipped'; @@ -44,6 +45,7 @@ const Editor: FC = () => { const mapRef = useRef(null); const { urlInfra } = useParams(); const infraID = useSelector(getInfraID); + const isLoading = useSelector(getIsLoading); const editorState = useSelector((state: { editor: EditorState }) => state.editor); const switchTypes = useSwitchTypes(infraID); const { register } = useKeyboardShortcuts(); @@ -58,6 +60,8 @@ const Editor: FC = () => { setRenderingFingerprint(Date.now()); }, [setRenderingFingerprint]); + const [formError, setFormError] = useState(null); + const switchTool = useCallback( ({ toolType, toolState }: switchProps) => { const tool = TOOLS[toolType]; @@ -128,6 +132,9 @@ const Editor: FC = () => { dispatch, editorState, infraID, + isLoading, + formError, + setFormError, switchTypes, mapState: { viewport, diff --git a/front/src/applications/editor/Map.tsx b/front/src/applications/editor/Map.tsx index 71e0898b82b..7ae6e5ed992 100644 --- a/front/src/applications/editor/Map.tsx +++ b/front/src/applications/editor/Map.tsx @@ -23,9 +23,10 @@ import Hillshade from 'common/Map/Layers/Hillshade'; import PlatformsLayer from 'common/Map/Layers/Platforms'; import { useMapBlankStyle } from 'common/Map/Layers/blankStyle'; import IGN_BD_ORTHO from 'common/Map/Layers/IGN_BD_ORTHO'; +import { Viewport } from 'reducers/map'; import { getInfraID } from 'reducers/osrdconf/selectors'; +import { getIsLoading } from 'reducers/main/mainSelector'; import { getShowOSM, getTerrain3DExaggeration } from 'reducers/map/selectors'; -import { Viewport } from 'reducers/map'; import { getMapMouseEventNearestFeature } from 'utils/mapHelper'; import { InfraError } from './components/InfraErrors/types'; import EditorContext from './context'; @@ -75,6 +76,7 @@ const MapUnplugged: FC> = ({ const editorState = useSelector((state: { editor: EditorState }) => state.editor); const showOSM = useSelector(getShowOSM); const terrain3DExaggeration = useSelector(getTerrain3DExaggeration); + const isLoading = useSelector(getIsLoading); const extendedContext = useMemo>( () => ({ @@ -82,6 +84,7 @@ const MapUnplugged: FC> = ({ dispatch, editorState, infraID, + isLoading, switchTypes, mapState: { viewport, diff --git a/front/src/applications/editor/components/EditorForm.tsx b/front/src/applications/editor/components/EditorForm.tsx index 21325a1a833..9f41f230138 100644 --- a/front/src/applications/editor/components/EditorForm.tsx +++ b/front/src/applications/editor/components/EditorForm.tsx @@ -24,8 +24,10 @@ const fields = { interface EditorFormProps { data: T; - onSubmit: (data: T) => Promise; + onSubmit?: (data: T) => Promise; onChange?: (data: T) => void; + formError?: string | null; + setFormError?: (error: string | null) => void; // Overrides: overrideSchema?: JSONSchema7; @@ -40,12 +42,14 @@ function EditorForm & { objType: string data, onSubmit, onChange, + formError, + setFormError, overrideSchema, overrideUiSchema, overrideFields, children, }: PropsWithChildren>) { - const [error, setError] = useState(null); + // const [error, setError] = useState(null); const [formData, setFormData] = useState(data.properties); const [submited, setSubmited] = useState(false); const { t } = useTranslation('infraEditor'); @@ -77,19 +81,34 @@ function EditorForm & { objType: string /** * When errors are displayed, we scroll to them. */ + // useEffect(() => { + // const container = document.getElementsByClassName('panel-box')[0]; + // if (error && container) { + // container.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); + // } + // }, [error]); + useEffect(() => { + console.log('formerror : ', formError); const container = document.getElementsByClassName('panel-box')[0]; - if (error && container) { + if (formError && container) { container.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); + setSubmited(true); } - }, [error]); + return () => setFormError && setFormError(null); + }, [formError]); return (
- {submited && error !== null && ( + {/* {submited && error !== null && (

{error}

+ )} */} + {submited && formError !== null && ( +
+

{formError}

+
)}
& { objType: string length: { 'ui:widget': FormLineStringLength, }, + 'ui:submitButtonOptions': { + norender: true, + }, ...(overrideUiSchema || {}), }} formData={formData} @@ -111,17 +133,19 @@ function EditorForm & { objType: string isCreation: isNil(formData?.id) || formData?.id === NEW_ENTITY_ID, }} onError={() => setSubmited(true)} - onSubmit={async () => { - try { - setError(null); - await onSubmit({ ...data, properties: { ...data.properties, ...formData } }); - } catch (e) { - if (e instanceof Error) setError(e.message); - else setError(JSON.stringify(e)); - } finally { - setSubmited(true); - } - }} + // onSubmit={async () => { + // if (onSubmit) { + // try { + // setError(null); + // await onSubmit({ ...data, properties: { ...data.properties, ...formData } }); + // } catch (e) { + // if (e instanceof Error) setError(e.message); + // else setError(JSON.stringify(e)); + // } finally { + // setSubmited(true); + // } + // } + // }} onChange={(event) => { setFormData({ ...data.properties, ...event.formData }); onChange?.({ ...data, properties: { ...data.properties, ...event.formData } }); diff --git a/front/src/applications/editor/tools/editorContextTypes.ts b/front/src/applications/editor/tools/editorContextTypes.ts index 719df7c27c6..35584fa076c 100644 --- a/front/src/applications/editor/tools/editorContextTypes.ts +++ b/front/src/applications/editor/tools/editorContextTypes.ts @@ -48,6 +48,9 @@ export interface ExtendedEditorContextType extends EditorContextType { mapState: MapState; infraID: number | undefined; switchTypes: SwitchType[] | undefined; + isLoading: boolean; + formError?: string | null; + setFormError?: (error: string | null) => void; } export type ReadOnlyEditorContextType = Omit< diff --git a/front/src/applications/editor/tools/rangeEdition/components.tsx b/front/src/applications/editor/tools/rangeEdition/components.tsx index c13fb33cd91..57afe6c0dfb 100644 --- a/front/src/applications/editor/tools/rangeEdition/components.tsx +++ b/front/src/applications/editor/tools/rangeEdition/components.tsx @@ -1,9 +1,8 @@ -import { cloneDeep, isEqual } from 'lodash'; -import { useDispatch, useSelector } from 'react-redux'; +import { cloneDeep } from 'lodash'; +import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import React, { FC, useContext, useState } from 'react'; import { BsArrowBarRight } from 'react-icons/bs'; -import { AiFillSave } from 'react-icons/ai'; import { MdShowChart } from 'react-icons/md'; import { FaFlagCheckered, FaTimes } from 'react-icons/fa'; @@ -18,14 +17,11 @@ import { import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; import CheckboxRadioSNCF from 'common/BootstrapSNCF/CheckboxRadioSNCF'; import { LoaderFill } from 'common/Loader'; -import { save } from 'reducers/editor'; -import { getIsLoading } from 'reducers/main/mainSelector'; import { getInfraID } from 'reducers/osrdconf/selectors'; import { APPLICABLE_DIRECTIONS, ApplicableDirection, CatenaryEntity, - EntityObjectOperationResult, SpeedSectionEntity, SpeedSectionPslEntity, } from 'types'; @@ -215,7 +211,6 @@ export const TrackRangesList: FC = () => { }; export const RangeEditionLeftPanel: FC = () => { - const dispatch = useDispatch(); const { t } = useTranslation(); const { setState, @@ -223,7 +218,6 @@ export const RangeEditionLeftPanel: FC = () => { } = useContext(EditorContext) as ExtendedEditorContextType< RangeEditionState >; - const isLoading = useSelector(getIsLoading); const isNew = entity.properties.id === NEW_ENTITY_ID; const isPSL = speedSectionIsPsl(entity as SpeedSectionEntity); @@ -247,64 +241,11 @@ export const RangeEditionLeftPanel: FC = () => { }); }; - let saveMessage; - if (entity.objType === 'SpeedSection') { - saveMessage = isNew - ? t('Editor.tools.speed-edition.save-new-speed-section') - : t('Editor.tools.speed-edition.save-existing-speed-section'); - } else { - saveMessage = isNew - ? t('Editor.tools.catenary-edition.save-new-catenary') - : t('Editor.tools.catenary-edition.save-existing-catenary'); - } - return (
- + {t(`Editor.obj-types.${entity.objType === 'SpeedSection' ? 'SpeedSection' : 'Catenary'}`)} -
- -
{initialEntity.objType === 'SpeedSection' ? ( ) : ( diff --git a/front/src/applications/editor/tools/rangeEdition/tool-factory.tsx b/front/src/applications/editor/tools/rangeEdition/tool-factory.tsx index 44960781278..70219c5b15a 100644 --- a/front/src/applications/editor/tools/rangeEdition/tool-factory.tsx +++ b/front/src/applications/editor/tools/rangeEdition/tool-factory.tsx @@ -1,10 +1,10 @@ import React, { ComponentType } from 'react'; import { Map } from 'maplibre-gl'; import { cloneDeep, isEqual } from 'lodash'; -import { BiReset } from 'react-icons/bi'; -import { GoTrash } from 'react-icons/go'; import { IconType } from 'react-icons'; -import { IoMdAddCircleOutline } from 'react-icons/io'; +import { BiReset } from 'react-icons/bi'; +import { AiFillSave } from 'react-icons/ai'; +import { GoPlusCircle, GoTrash } from 'react-icons/go'; import { save } from 'reducers/editor'; import { ConfirmModal } from 'common/BootstrapSNCF/ModalSNCF'; @@ -15,6 +15,7 @@ import { TrackSectionEntity, } from 'types/editor'; import { getNearestPoint } from 'utils/mapHelper'; +import { EntityObjectOperationResult } from 'types'; import { NEW_ENTITY_ID } from 'applications/editor/data/utils'; import { PartialOrReducer, Tool } from '../editorContextTypes'; import { DEFAULT_COMMON_TOOL_STATE } from '../commonToolState'; @@ -37,6 +38,7 @@ import { selectPslSign, getObjTypeAction, getObjTypeEdition, + isNew, } from './utils'; type EditorRange = SpeedSectionEntity | CatenaryEntity; @@ -87,11 +89,46 @@ function getRangeEditionTool({ actions: [ [ { - id: `new-${objectTypeAction}`, - icon: IoMdAddCircleOutline, - labelTranslationKey: `Editor.tools.${objectTypeEdition}-edition.actions.new-${objectTypeAction}`, - onClick({ setState }) { - setState(getInitialState()); + id: `save-${objectTypeAction}`, + icon: AiFillSave, + labelTranslationKey: `Editor.tools.${objectTypeEdition}-edition.actions.save-${objectTypeAction}`, + isDisabled({ isLoading }) { + return isLoading; + }, + async onClick({ state, setState, dispatch, infraID }) { + const { initialEntity, entity } = state; + if (!isEqual(entity, initialEntity)) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res: any = await dispatch( + save( + infraID, + !isNew(entity) + ? { + update: [ + { + source: initialEntity, + target: entity, + }, + ], + } + : { create: [entity] } + ) + ); + const operation = res[0] as EntityObjectOperationResult; + const { entityId } = operation.railjson; + + const savedEntity = + entityId && entityId !== entity.properties.id + ? { + ...entity, + properties: { ...entity.properties, id: `${entityId}` }, + } + : entity; + setState({ + entity: cloneDeep(savedEntity), + initialEntity: cloneDeep(savedEntity), + }); + } }, }, { @@ -108,6 +145,16 @@ function getRangeEditionTool({ }, }, ], + [ + { + id: `new-${objectTypeAction}`, + icon: GoPlusCircle, + labelTranslationKey: `Editor.tools.${objectTypeEdition}-edition.actions.new-${objectTypeAction}`, + onClick({ setState }) { + setState(getInitialState()); + }, + }, + ], [ { id: 'delete-entity', diff --git a/front/src/applications/editor/tools/rangeEdition/utils.ts b/front/src/applications/editor/tools/rangeEdition/utils.ts index 197998dcf9c..ae359c31fba 100644 --- a/front/src/applications/editor/tools/rangeEdition/utils.ts +++ b/front/src/applications/editor/tools/rangeEdition/utils.ts @@ -382,3 +382,6 @@ export const getObjTypeEdition = (objType: 'SpeedSection' | 'Catenary') => export const getObjTypeAction = (objType: 'SpeedSection' | 'Catenary') => objType === 'SpeedSection' ? 'speed-section' : 'catenary'; + +export const isNew = (entity: SpeedSectionEntity | CatenaryEntity) => + entity.properties.id === NEW_ENTITY_ID; diff --git a/front/src/applications/editor/tools/selection/components.tsx b/front/src/applications/editor/tools/selection/components.tsx index f241a5db544..773cb43e95c 100644 --- a/front/src/applications/editor/tools/selection/components.tsx +++ b/front/src/applications/editor/tools/selection/components.tsx @@ -2,20 +2,20 @@ import React, { FC, useContext } from 'react'; import { Layer, Popup, Source } from 'react-map-gl/maplibre'; import { useSelector } from 'react-redux'; import { groupBy, map } from 'lodash'; -import { IoMdRemoveCircleOutline } from 'react-icons/io'; +import { GoNoEntry } from 'react-icons/go'; import { RiFocus3Line } from 'react-icons/ri'; import { useTranslation } from 'react-i18next'; -import EditorContext from '../../context'; +import { Zone } from 'types'; +import colors from 'common/Map/Consts/colors'; +import { getMap } from 'reducers/map/selectors'; +import { zoneToFeature } from 'utils/mapHelper'; +import GeoJSONs from 'common/Map/Layers/GeoJSONs'; import { SelectionState } from './types'; -import { Zone } from '../../../../types'; -import GeoJSONs from '../../../../common/Map/Layers/GeoJSONs'; -import colors from '../../../../common/Map/Consts/colors'; +import EditorContext from '../../context'; import EntitySumUp from '../../components/EntitySumUp'; import './styles.scss'; -import { zoneToFeature } from '../../../../utils/mapHelper'; -import { getMap } from '../../../../reducers/map/selectors'; import { EditorContextType, ExtendedEditorContextType } from '../editorContextTypes'; export const SelectionMessages = () => { @@ -134,7 +134,7 @@ export const SelectionLeftPanel: FC = () => { setState({ ...state, selection: selection.filter((i) => i.objType !== type) }) } > - {t('Editor.tools.select-items.unselect')} + {t('Editor.tools.select-items.unselect')}
@@ -173,7 +173,7 @@ export const SelectionLeftPanel: FC = () => { }) } > - {t('Editor.tools.select-items.unselect')} + {t('Editor.tools.select-items.unselect')}
diff --git a/front/src/applications/editor/tools/selection/tool.tsx b/front/src/applications/editor/tools/selection/tool.tsx index 3ba3d3f6424..3d564fff52a 100644 --- a/front/src/applications/editor/tools/selection/tool.tsx +++ b/front/src/applications/editor/tools/selection/tool.tsx @@ -1,9 +1,9 @@ import React from 'react'; +import { FiEdit } from 'react-icons/fi'; import { GoTrash } from 'react-icons/go'; -import { BiLoader, BiSelection } from 'react-icons/bi'; import { BsCursor } from 'react-icons/bs'; import { FaDrawPolygon } from 'react-icons/fa'; -import { FiEdit } from 'react-icons/fi'; +import { BiLoader, BiSelection } from 'react-icons/bi'; import { PointLike } from 'maplibre-gl'; import { isEqual, max, min } from 'lodash'; diff --git a/front/src/applications/editor/tools/trackEdition/components.tsx b/front/src/applications/editor/tools/trackEdition/components.tsx index 1971f8781f8..9084e9b434d 100644 --- a/front/src/applications/editor/tools/trackEdition/components.tsx +++ b/front/src/applications/editor/tools/trackEdition/components.tsx @@ -357,7 +357,7 @@ export const TrackEditionLeftPanel: FC = () => { const { t } = useTranslation(); const infraID = useSelector(getInfraID); const isLoading = useSelector(getIsLoading); - const { state, setState } = useContext( + const { state, setState, formError, setFormError } = useContext( EditorContext ) as ExtendedEditorContextType; const { track } = state; @@ -367,52 +367,12 @@ export const TrackEditionLeftPanel: FC = () => { <> { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const res: any = await dispatch( - save( - infraID, - track.properties.id !== NEW_ENTITY_ID - ? { - update: [ - { - source: state.initialTrack, - target: injectGeometry(savedEntity), - }, - ], - } - : { create: [injectGeometry(savedEntity)] } - ) - ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const operation = res[0] as EntityObjectOperationResult; - const savedTrack = { - objType: 'TrackSection', - type: 'Feature', - properties: operation.railjson, - geometry: operation.railjson.geo, - } as TrackSectionEntity; - - setState({ - ...state, - initialTrack: savedTrack, - track: savedTrack, - }); - }} onChange={(newTrack) => { setState({ ...state, track: newTrack as TrackSectionEntity }); }} - > -
- -
-
+ formError={formError} + setFormError={setFormError} + />
{!isNew && ( <> diff --git a/front/src/applications/editor/tools/trackEdition/tool.tsx b/front/src/applications/editor/tools/trackEdition/tool.tsx index 82e64d3b1df..280f5d31bac 100644 --- a/front/src/applications/editor/tools/trackEdition/tool.tsx +++ b/front/src/applications/editor/tools/trackEdition/tool.tsx @@ -1,10 +1,7 @@ import React from 'react'; import { cloneDeep, isEmpty, isEqual } from 'lodash'; -import { GoTrash } from 'react-icons/go'; import { MdShowChart } from 'react-icons/md'; import { RiDragMoveLine } from 'react-icons/ri'; -import { CgAdd, CgRemove } from 'react-icons/cg'; -import { TiDeleteOutline } from 'react-icons/ti'; import { BiAnchor, BiArrowFromLeft, BiArrowToRight } from 'react-icons/bi'; import { Feature, LineString } from 'geojson'; import getNearestPoint from '@turf/nearest-point'; @@ -16,6 +13,9 @@ import { entityDoUpdate, getLineStringDistance } from 'common/IntervalsDataViz/d import { ConfirmModal } from 'common/BootstrapSNCF/ModalSNCF'; import { getMapMouseEventNearestFeature } from 'utils/mapHelper'; import { NEW_ENTITY_ID } from 'applications/editor/data/utils'; +import { GoNoEntry, GoPlusCircle, GoTrash, GoXCircle } from 'react-icons/go'; +import { AiFillSave } from 'react-icons/ai'; +import { EntityObjectOperationResult, TrackSectionEntity } from 'types'; import { Tool } from '../editorContextTypes'; import { DEFAULT_COMMON_TOOL_STATE } from '../commonToolState'; import { @@ -25,7 +25,7 @@ import { TrackEditionLeftPanel, TrackEditionMessages, } from './components'; -import { getNewLine } from './utils'; +import { getNewLine, injectGeometry } from './utils'; import { TrackEditionState } from './types'; function getInitialState(): TrackEditionState { @@ -52,6 +52,63 @@ const TrackEditionTool: Tool = { }, getInitialState, actions: [ + [ + { + id: 'save-line', + icon: AiFillSave, + labelTranslationKey: 'Editor.tools.track-edition.actions.save-line', + isDisabled({ isLoading }) { + return isLoading; + }, + async onClick({ state, setState, dispatch, infraID, setFormError }) { + const { initialTrack, track } = state; + // as it triggers an issue in the issue list, endpoint call is not blocked if the tracksection isn't drawn + // if (!isEqual(track, initialTrack) && !isEmpty(track.properties.extensions?.sncf)) { + if (setFormError) { + try { + setFormError(null); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res: any = await dispatch( + save( + infraID, + track.properties.id !== NEW_ENTITY_ID + ? { + update: [ + { + source: state.initialTrack, + target: injectGeometry(track), + }, + ], + } + : { create: [injectGeometry(track)] } + ) + ); + const operation = res[0] as EntityObjectOperationResult; + const savedTrack = { + objType: 'TrackSection', + type: 'Feature', + properties: operation.railjson, + geometry: operation.railjson.geo, + } as TrackSectionEntity; + + setState({ + ...state, + initialTrack: savedTrack, + track: savedTrack, + }); + } catch (e) { + if (e instanceof Error) { + setFormError(e.message); + console.log('error : ', e.message); + } else { + setFormError(JSON.stringify(e)); + console.log('error sringify: ', JSON.stringify(e)); + } + } + } + }, + }, + ], [ { id: 'mode-move-point', @@ -71,7 +128,7 @@ const TrackEditionTool: Tool = { }, { id: 'mode-add-point', - icon: CgAdd, + icon: GoPlusCircle, labelTranslationKey: 'Editor.tools.track-edition.actions.mode-add-point', onClick({ setState, state }) { setState({ @@ -85,7 +142,7 @@ const TrackEditionTool: Tool = { }, { id: 'mode-delete-point', - icon: TiDeleteOutline, + icon: GoXCircle, labelTranslationKey: 'Editor.tools.track-edition.actions.mode-delete-point', onClick({ setState, state }) { setState({ @@ -99,8 +156,6 @@ const TrackEditionTool: Tool = { return state.editionState.type === 'deletePoint'; }, }, - ], - [ { id: 'toggle-anchoring', icon: BiAnchor, @@ -149,7 +204,7 @@ const TrackEditionTool: Tool = { }, { id: 'cancel-line', - icon: CgRemove, + icon: GoNoEntry, labelTranslationKey: 'Editor.tools.track-edition.actions.cancel-line', onClick({ setState, state }) { if (state.track.geometry.coordinates.length) { @@ -162,6 +217,8 @@ const TrackEditionTool: Tool = { return !state.track.geometry.coordinates.length; }, }, + ], + [ { id: 'delete-line', icon: GoTrash,