From 3d839bc2cf580d510cd5fe052ecff845f71ad377 Mon Sep 17 00:00:00 2001 From: romainvalls Date: Tue, 25 Jun 2024 20:32:55 +0200 Subject: [PATCH] front: adapt power restriction v2 inputs --- .../views/v2/ManageTrainScheduleV2.tsx | 17 ++- .../IntervalsEditor/IntervalsEditor.tsx | 11 +- .../IntervalsEditorCommonForm.tsx | 12 +- .../IntervalsEditorTooltip.tsx | 8 +- .../PowerRestrictionsSelectorV2.tsx | 50 ++++++- .../reducers/osrdconf/osrdConfCommon/index.ts | 140 +++++++++++++++++- .../reducers/osrdconf/osrdConfCommon/utils.ts | 15 ++ front/src/utils/strings.ts | 6 + 8 files changed, 240 insertions(+), 19 deletions(-) create mode 100644 front/src/reducers/osrdconf/osrdConfCommon/utils.ts diff --git a/front/src/applications/operationalStudies/views/v2/ManageTrainScheduleV2.tsx b/front/src/applications/operationalStudies/views/v2/ManageTrainScheduleV2.tsx index 81dff98c3d9..7bee5eeb629 100644 --- a/front/src/applications/operationalStudies/views/v2/ManageTrainScheduleV2.tsx +++ b/front/src/applications/operationalStudies/views/v2/ManageTrainScheduleV2.tsx @@ -1,5 +1,6 @@ -import React, { useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; +import { compact } from 'lodash'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; @@ -16,6 +17,7 @@ import { useOsrdConfSelectors } from 'common/osrdContext'; import { useStoreDataForSpeedLimitByTagSelector } from 'common/SpeedLimitByTagSelector/useStoreDataForSpeedLimitByTagSelector'; import Tabs from 'common/Tabs'; import ItineraryV2 from 'modules/pathfinding/components/Itinerary/ItineraryV2'; +import { upsertViasInOPs } from 'modules/pathfinding/utils'; import PowerRestrictionsSelectorV2 from 'modules/powerRestriction/components/PowerRestrictionsSelectorV2'; import RollingStock2Img from 'modules/rollingStock/components/RollingStock2Img'; import { RollingStockSelector } from 'modules/rollingStock/components/RollingStockSelector'; @@ -56,6 +58,19 @@ const ManageTrainScheduleV2 = () => { value: string; }; + useEffect(() => { + if (pathProperties) { + const allVias = upsertViasInOPs( + pathProperties.suggestedOperationalPoints, + compact(pathSteps) + ); + setPathProperties({ + ...pathProperties, + allVias, + }); + } + }, [pathSteps]); + const pathElectrificationRanges = (): IntervalItem[] => { if (!pathProperties || !pathProperties.electrifications) return []; diff --git a/front/src/common/IntervalsEditor/IntervalsEditor.tsx b/front/src/common/IntervalsEditor/IntervalsEditor.tsx index e42d5eefaba..a73e66de136 100644 --- a/front/src/common/IntervalsEditor/IntervalsEditor.tsx +++ b/front/src/common/IntervalsEditor/IntervalsEditor.tsx @@ -52,6 +52,7 @@ type IntervalsEditorProps = { /** Total length of the path */ totalLength: number; disableDrag?: boolean; + onResizeFromInput?: (intervalIndex: number, newEnd: number, context: 'begin' | 'end') => void; } & ( | { intervalType: INTERVAL_TYPES.NUMBER; @@ -99,6 +100,7 @@ const IntervalsEditor = (props: IntervalsEditorProps) => { mergeTool: true, }, disableDrag = false, + onResizeFromInput, } = props; // Which segment areas are visible @@ -113,13 +115,13 @@ const IntervalsEditor = (props: IntervalsEditorProps) => { // Data to display const [resizingData, setResizingData] = useState(data); - useEffect(() => { - setResizingData(data); - }, [data]); - // Which segment is selected const [selected, setSelected] = useState(null); + useEffect(() => { + setResizingData(data); + }, [data, selected]); + // For mouse click / doubleClick const [clickTimeout, setClickTimeout] = useState(null); const [clickPrevent, setClickPrevent] = useState(false); @@ -333,6 +335,7 @@ const IntervalsEditor = (props: IntervalsEditorProps) => { interval={data[selected]} selectedIntervalIndex={selected} setData={setData} + onInputChange={onResizeFromInput} setSelectedIntervalIndex={setSelected} totalLength={totalLength} defaultValue={defaultValue} diff --git a/front/src/common/IntervalsEditor/IntervalsEditorCommonForm.tsx b/front/src/common/IntervalsEditor/IntervalsEditorCommonForm.tsx index f28d948c804..0c374b4bc60 100644 --- a/front/src/common/IntervalsEditor/IntervalsEditorCommonForm.tsx +++ b/front/src/common/IntervalsEditor/IntervalsEditorCommonForm.tsx @@ -12,7 +12,8 @@ type IntervalsEditorFormProps = { data: IntervalItem[]; interval: IntervalItem; selectedIntervalIndex: number; - setData: (newData: IntervalItem[]) => void; + setData: (newData: IntervalItem[], selectedIntervalIndex?: number) => void; + onInputChange?: (intervalIndex: number, newBegin: number, context: 'begin' | 'end') => void; setSelectedIntervalIndex: (selectedIntervalIndex: number) => void; totalLength: number; defaultValue: string | number; @@ -26,11 +27,12 @@ const IntervalsEditorCommonForm = ({ setSelectedIntervalIndex, totalLength, defaultValue, + onInputChange, }: IntervalsEditorFormProps) => { const { t } = useTranslation('common/common'); const [begin, setBegin] = useState(Math.round(interval.begin)); - const [end, setEnd] = useState(Math.round(interval.end)); + const [end, setEnd] = useState(Math.round(interval.end)); useEffect(() => { setBegin(Math.round(interval.begin)); @@ -53,7 +55,11 @@ const IntervalsEditorCommonForm = ({ fieldName: 'value', defaultValue, }); - setData(fixedResults); + if (onInputChange) { + onInputChange(selectedIntervalIndex, newPosition, context); + } else { + setData(fixedResults, selectedIntervalIndex); + } // update the selected interval if needed // corner case: if we create a new empty first segment diff --git a/front/src/common/IntervalsEditor/IntervalsEditorTooltip.tsx b/front/src/common/IntervalsEditor/IntervalsEditorTooltip.tsx index 705abeb5458..f9ea462b62d 100644 --- a/front/src/common/IntervalsEditor/IntervalsEditorTooltip.tsx +++ b/front/src/common/IntervalsEditor/IntervalsEditorTooltip.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; +import { formatMValue } from 'utils/strings'; + import type { IntervalItem } from './types'; interface IntervalsEditorTooltip { @@ -13,15 +15,15 @@ const IntervalsEditorTooltip = ({ item, point }: IntervalsEditorTooltip) => { const { t } = useTranslation('common/common'); return (
-
{point && {Math.round(point)}}
+
{point && {Math.round(formatMValue(point))}}
{t('begin')} - {Math.round(item.begin)} + {Math.round(formatMValue(item.begin))}
{t('end')} - {Math.round(item.end)} + {Math.round(formatMValue(item.end))}
{t('value')} diff --git a/front/src/modules/powerRestriction/components/PowerRestrictionsSelectorV2.tsx b/front/src/modules/powerRestriction/components/PowerRestrictionsSelectorV2.tsx index 3a1196fbebc..ecb710e7485 100644 --- a/front/src/modules/powerRestriction/components/PowerRestrictionsSelectorV2.tsx +++ b/front/src/modules/powerRestriction/components/PowerRestrictionsSelectorV2.tsx @@ -46,12 +46,12 @@ const PowerRestrictionsSelectorV2 = ({ resetPowerRestrictionRangesV2, cutPowerRestrictionRangesV2, deletePowerRestrictionRangesV2, + resizePowerRestrictionRangeV2, } = useOsrdConfActions(); const powerRestrictionRanges = useSelector(getPowerRestrictionV2); const pathSteps = compact(useSelector(getPathSteps)); // pathSteps + points de coupure d'électricité - // const [updatedPathSteps, setUpdatedPathSteps] = useState([]); const [cutPositions, setCutPositions] = useState([]); const [intervalsEditorData, setIntervalsEditorData] = useState([]); @@ -198,6 +198,53 @@ const PowerRestrictionsSelectorV2 = ({ dispatch(deletePowerRestrictionRangesV2({ from: fromPathStep, to: toPathStep })); } }; + + const resizeSegmentByInput = ( + selectedSegmentIndex: number, + newEnd: number, + context: 'begin' | 'end' + ) => { + const firstIndex = context === 'end' ? selectedSegmentIndex : selectedSegmentIndex - 1; + + let firstRestriction: PowerRestrictionV2 | undefined; + let secondRestriction: PowerRestrictionV2 | undefined; + if (firstIndex >= 0) { + const firstRangeData = intervalsEditorData[firstIndex]; + if (firstRangeData.value !== NO_POWER_RESTRICTION) { + const fromPathStep = pathSteps.find((step) => step.positionOnPath === firstRangeData.begin); + const toPathStep = pathSteps.find((step) => step.positionOnPath === firstRangeData.end); + if (fromPathStep && toPathStep) { + firstRestriction = powerRestrictionRanges.find( + (restriction) => + restriction.from === fromPathStep.id && restriction.to === toPathStep.id + ); + } + } + } + + const secondRangeData = intervalsEditorData[firstIndex + 1]; + if (secondRangeData.value !== NO_POWER_RESTRICTION) { + const fromPathStep = pathSteps.find((step) => step.positionOnPath === secondRangeData.begin); + const toPathStep = pathSteps.find((step) => step.positionOnPath === secondRangeData.end); + if (fromPathStep && toPathStep) { + secondRestriction = powerRestrictionRanges.find( + (restriction) => restriction.from === fromPathStep.id && restriction.to === toPathStep.id + ); + } + } + + let newEndPathStep = pathSteps.find((pathStep) => pathStep.positionOnPath === newEnd); + if (!newEndPathStep) { + newEndPathStep = createPathStep(newEnd, cumulativeSums, pathProperties, pathSteps); + } + + if (firstRestriction && newEndPathStep) { + dispatch( + resizePowerRestrictionRangeV2({ firstRestriction, secondRestriction, newEndPathStep }) + ); + } + }; + const formatElectricalRanges = ( ranges: PowerRestrictionV2[] ): { begin: number; end: number; value: string }[] => { @@ -324,6 +371,7 @@ const PowerRestrictionsSelectorV2 = ({ deleteTool: true, }} disableDrag + onResizeFromInput={resizeSegmentByInput} />