Skip to content

Commit 3b7dff6

Browse files
committed
front: match PathStep and SuggestedOP with pathStepId
Matching via uic/trigram/ch/etc is unreliable because: - Two OPs can have the same trigram/ch. - The same OP could appear multiple times at different spots in a path. Moreover, we had multiple variants of the matching with slight differences. Some of the matching logic got adjusted to account for specific bugs, while others were left alone. Each path step can be identified with a unique ID stored in PathStep.id. Use that instead. Signed-off-by: Simon Ser <[email protected]>
1 parent d551cab commit 3b7dff6

File tree

7 files changed

+16
-74
lines changed

7 files changed

+16
-74
lines changed

front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from 'common/api/osrdEditoastApi';
1414
import { useOsrdConfActions } from 'common/osrdContext';
1515
import buildOpSearchQuery from 'modules/operationalPoint/helpers/buildOpSearchQuery';
16-
import { formatSuggestedOperationalPoints, matchPathStepAndOp } from 'modules/pathfinding/utils';
16+
import { formatSuggestedOperationalPoints } from 'modules/pathfinding/utils';
1717
import { getSupportedElectrification, isThermal } from 'modules/rollingStock/helpers/electric';
1818
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
1919
import computeBasePathStep from 'modules/trainschedule/helpers/computeBasePathStep';
@@ -39,8 +39,8 @@ export function updatePathStepsFromOperationalPoints(
3939
stepsCoordinates: Position[]
4040
) {
4141
const updatedPathSteps: PathStep[] = pathSteps.map((step, i) => {
42-
const correspondingOp = suggestedOperationalPoints.find((suggestedOp) =>
43-
matchPathStepAndOp(step, suggestedOp)
42+
const correspondingOp = suggestedOperationalPoints.find(
43+
(suggestedOp) => step.id === suggestedOp.pathStepId
4444
);
4545

4646
const { kp, name } = correspondingOp || step;

front/src/modules/pathfinding/components/Itinerary/ModalSuggestedVias.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import ModalBodySNCF from 'common/BootstrapSNCF/ModalSNCF/ModalBodySNCF';
99
import ModalFooterSNCF from 'common/BootstrapSNCF/ModalSNCF/ModalFooterSNCF';
1010
import ModalHeaderSNCF from 'common/BootstrapSNCF/ModalSNCF/ModalHeaderSNCF';
1111
import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext';
12-
import { isVia, matchPathStepAndOp } from 'modules/pathfinding/utils';
1312
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
1413
import type { OperationalStudiesConfSliceActions } from 'reducers/osrdconf/operationalStudiesConf';
1514
import type { PathStep } from 'reducers/osrdconf/types';
@@ -37,12 +36,12 @@ const ModalSuggestedVias = ({ suggestedVias, launchPathfinding }: ModalSuggested
3736
);
3837

3938
const removeViaFromPath = (op: SuggestedOP) => {
40-
const newPathSteps = pathSteps.filter((step) => !matchPathStepAndOp(step!, op));
39+
const newPathSteps = pathSteps.filter((step) => step!.id !== op.pathStepId);
4140
launchPathfinding(newPathSteps);
4241
};
4342

4443
const formatOP = (op: SuggestedOP, idx: number, idxTrueVia: number) => {
45-
const isInVias = isVia(vias, op);
44+
const isInVias = vias.find((step) => step.id === op.pathStepId);
4645
return (
4746
<div
4847
key={`suggested-via-modal-${op.opId}-${idx}`}
@@ -105,7 +104,7 @@ const ModalSuggestedVias = ({ suggestedVias, launchPathfinding }: ModalSuggested
105104
{suggestedVias.map((via, idx) => {
106105
if (!isOriginOrDestination(via)) {
107106
// If name is undefined, we know the op/via has been added by clicking on map
108-
if (isVia(vias, via)) idxTrueVia += 1;
107+
if (vias.find((step) => step.id === via.pathStepId)) idxTrueVia += 1;
109108
return formatOP(via, idx, idxTrueVia);
110109
}
111110
return null;

front/src/modules/pathfinding/hooks/usePathfinding.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ import type {
1414
} from 'common/api/osrdEditoastApi';
1515
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
1616
import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext';
17-
import {
18-
formatSuggestedOperationalPoints,
19-
getPathfindingQuery,
20-
matchPathStepAndOp,
21-
} from 'modules/pathfinding/utils';
17+
import { formatSuggestedOperationalPoints, getPathfindingQuery } from 'modules/pathfinding/utils';
2218
import { useStoreDataForRollingStockSelector } from 'modules/rollingStock/components/RollingStockSelector/useStoreDataForRollingStockSelector';
2319
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
2420
import { setFailure, setWarning } from 'reducers/main';
@@ -126,8 +122,8 @@ const usePathfinding = (
126122
// We update existing pathsteps with coordinates, positionOnPath and kp corresponding to the new pathfinding result
127123
const updatedPathSteps: (PathStep | null)[] = pathStepsInput.map((step, i) => {
128124
if (!step) return step;
129-
const correspondingOp = suggestedOperationalPoints.find((suggestedOp) =>
130-
matchPathStepAndOp(step, suggestedOp)
125+
const correspondingOp = suggestedOperationalPoints.find(
126+
(suggestedOp) => step.id === suggestedOp.pathStepId
131127
);
132128

133129
const theoreticalMargin = i === 0 ? step.theoreticalMargin || '0%' : step.theoreticalMargin;

front/src/modules/pathfinding/utils.ts

+1-35
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { getPointCoordinates } from 'utils/geometry';
1616

1717
import getStepLocation from './helpers/getStepLocation';
1818

19-
export const matchPathStepAndOp = (
19+
const matchPathStepAndOp = (
2020
step: PathStep,
2121
op: Pick<SuggestedOP, 'opId' | 'uic' | 'ch' | 'trigram' | 'track' | 'offsetOnTrack'>
2222
) => {
@@ -143,40 +143,6 @@ export const upsertPathStepsInOPs = (ops: SuggestedOP[], pathSteps: PathStep[]):
143143
return updatedOPs;
144144
};
145145

146-
export const pathStepMatchesOp = (
147-
pathStep: PathStep,
148-
op: Pick<
149-
SuggestedOP,
150-
'pathStepId' | 'opId' | 'uic' | 'ch' | 'trigram' | 'track' | 'offsetOnTrack' | 'name' | 'kp'
151-
>,
152-
withKP = false
153-
) => {
154-
if (!matchPathStepAndOp(pathStep, op)) {
155-
return pathStep.id === op.pathStepId;
156-
}
157-
if ('uic' in pathStep) {
158-
return withKP ? pathStep.kp === op.kp : pathStep.name === op.name;
159-
}
160-
return true;
161-
};
162-
163-
/**
164-
* Check if a suggested operational point is a via.
165-
* Some OPs have same uic so we need to check also the ch (can be still not enough
166-
* probably because of imports problem).
167-
* If the vias has no uic, it has been added via map click and we know it has an id.
168-
* @param withKP - If true, we check the kp compatibility instead of the name.
169-
* It is used in the times and stops table to check if an operational point is a via.
170-
*/
171-
export const isVia = (
172-
vias: PathStep[],
173-
op: Pick<
174-
SuggestedOP,
175-
'pathStepId' | 'opId' | 'uic' | 'ch' | 'trigram' | 'track' | 'offsetOnTrack' | 'name' | 'kp'
176-
>,
177-
{ withKP = false } = {}
178-
) => vias.some((via) => pathStepMatchesOp(via, op, withKP));
179-
180146
export const isStation = (chCode: string): boolean =>
181147
chCode === 'BV' || chCode === '00' || chCode === '';
182148

front/src/modules/timesStops/TimesStopsInput.tsx

+2-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { useTranslation } from 'react-i18next';
77

88
import { useScenarioContext } from 'applications/operationalStudies/hooks/useScenarioContext';
99
import { useOsrdConfActions } from 'common/osrdContext';
10-
import { isVia, matchPathStepAndOp } from 'modules/pathfinding/utils';
1110
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
1211
import type { OperationalStudiesConfSliceActions } from 'reducers/osrdconf/operationalStudiesConf';
1312
import type { PathStep } from 'reducers/osrdconf/types';
@@ -43,7 +42,7 @@ const createClearViaButton = ({
4342
pathStepsAndSuggestedOPs &&
4443
rowIndex > 0 &&
4544
rowIndex < pathStepsAndSuggestedOPs.length - 1 &&
46-
isVia(pathSteps || [], rowData, { withKP: true }) &&
45+
pathSteps.find((step) => step.id === rowData.pathStepId) &&
4746
(!isNil(rowData.stopFor) ||
4847
rowData.theoreticalMargin !== undefined ||
4948
rowData.arrival !== undefined ||
@@ -78,9 +77,7 @@ const TimesStopsInput = ({
7877
const { getTrackSectionsByIds, trackSectionsLoading } = useScenarioContext();
7978

8079
const clearPathStep = (rowData: TimesStopsInputRow) => {
81-
const index = pathSteps.findIndex(
82-
(step) => matchPathStepAndOp(step, rowData) && step.positionOnPath === rowData.positionOnPath
83-
);
80+
const index = pathSteps.findIndex((step) => step.id === rowData.pathStepId);
8481

8582
const updatedPathSteps = pathSteps.map((step, i) => {
8683
if (i === index) {

front/src/modules/timesStops/helpers/utils.ts

+3-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { keyColumn, createTextColumn } from 'react-datasheet-grid';
66

77
import type { ReceptionSignal } from 'common/api/osrdEditoastApi';
88
import type { IsoDurationString, TimeString } from 'common/types';
9-
import { matchPathStepAndOp } from 'modules/pathfinding/utils';
109
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
1110
import type { PathStep } from 'reducers/osrdconf/types';
1211
import { NO_BREAK_SPACE } from 'utils/strings';
@@ -24,18 +23,6 @@ import {
2423
import { marginRegExValidation, MarginUnit } from '../consts';
2524
import { TableType, type TimeExtraDays, type TimesStopsInputRow } from '../types';
2625

27-
const matchPathStepAndOpWithKP = (step: PathStep, op: SuggestedOP) => {
28-
if (!matchPathStepAndOp(step, op)) {
29-
return step.id === op.pathStepId;
30-
}
31-
// We match the kp in case two OPs have the same uic+ch (can happen when the
32-
// infra is imported)
33-
if ('uic' in step || 'trigram' in step) {
34-
return step.kp === op.kp;
35-
}
36-
return true;
37-
};
38-
3926
export const formatSuggestedViasToRowVias = (
4027
operationalPoints: SuggestedOP[],
4128
pathSteps: PathStep[],
@@ -49,7 +36,7 @@ export const formatSuggestedViasToRowVias = (
4936
// to move it to the first position
5037
const origin = pathSteps[0];
5138
const originIndexInOps = origin
52-
? operationalPoints.findIndex((op) => matchPathStepAndOpWithKP(origin, op))
39+
? operationalPoints.findIndex((op) => origin.id === op.pathStepId)
5340
: -1;
5441
if (originIndexInOps !== -1) {
5542
[formattedOps[0], formattedOps[originIndexInOps]] = [
@@ -60,9 +47,7 @@ export const formatSuggestedViasToRowVias = (
6047

6148
// Ditto: destination should be last
6249
const dest = pathSteps[pathSteps.length - 1];
63-
const destIndexInOps = dest
64-
? operationalPoints.findIndex((op) => matchPathStepAndOpWithKP(dest, op))
65-
: -1;
50+
const destIndexInOps = dest ? operationalPoints.findIndex((op) => dest.id === op.pathStepId) : -1;
6651
if (destIndexInOps !== -1) {
6752
const lastOpIndex = formattedOps.length - 1;
6853
[formattedOps[lastOpIndex], formattedOps[destIndexInOps]] = [
@@ -72,7 +57,7 @@ export const formatSuggestedViasToRowVias = (
7257
}
7358

7459
return formattedOps.map((op, i) => {
75-
const pathStep = pathSteps.find((step) => matchPathStepAndOpWithKP(step, op));
60+
const pathStep = pathSteps.find((step) => step.id === op.pathStepId);
7661
const { name } = pathStep || op;
7762
const objectToUse = tableType === TableType.Input ? pathStep : op;
7863

front/src/reducers/osrdconf/helpers.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import nextId from 'react-id-generator';
44

55
import { calculateDistanceAlongTrack } from 'applications/editor/tools/utils';
66
import type { ManageTrainSchedulePathProperties } from 'applications/operationalStudies/types';
7-
import { pathStepMatchesOp } from 'modules/pathfinding/utils';
87
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
98
import { addElementAtIndex } from 'utils/array';
109

@@ -76,7 +75,7 @@ export function upsertPathStep(statePathSteps: (PathStep | null)[], op: Suggeste
7675
}),
7776
};
7877

79-
const stepIndex = cleanPathSteps.findIndex((step) => pathStepMatchesOp(step, op));
78+
const stepIndex = cleanPathSteps.findIndex((step) => step.id === op.pathStepId);
8079
if (stepIndex >= 0) {
8180
// Because of import issues, there can be multiple ops with same position on path
8281
// To avoid updating the wrong one, we need to find the one that matches the payload

0 commit comments

Comments
 (0)