From 389143747bdb1f6097fc7b991904f5253bcb4d82 Mon Sep 17 00:00:00 2001 From: Alice Khoudli Date: Thu, 7 Nov 2024 10:01:51 +0100 Subject: [PATCH 1/4] front: add track column to timestops table Signed-off-by: Alice Khoudli --- front/public/locales/en/timesStops.json | 1 + front/public/locales/fr/timesStops.json | 1 + .../hooks/useSetupItineraryForTrainUpdate.ts | 15 +++--- .../pathfinding/hooks/usePathfinding.ts | 15 +++--- front/src/modules/pathfinding/utils.ts | 52 ++++++++++++++++++- .../timesStops/hooks/useTimeStopsColumns.tsx | 13 ++++- front/src/modules/timesStops/types.ts | 1 + .../components/ManageTrainSchedule/types.ts | 1 + .../tests/011-op-times-and-stops-tab.spec.ts | 1 + 9 files changed, 86 insertions(+), 14 deletions(-) diff --git a/front/public/locales/en/timesStops.json b/front/public/locales/en/timesStops.json index e1daaf807a4..2701aa6f2f9 100644 --- a/front/public/locales/en/timesStops.json +++ b/front/public/locales/en/timesStops.json @@ -19,5 +19,6 @@ "theoreticalMargin": "theoretical margin", "theoreticalMarginPlaceholder": "% or min/100km", "theoreticalMarginSeconds": "theoretical margin (s)", + "trackName": "track", "waypoint": "Waypoint {{id}}" } diff --git a/front/public/locales/fr/timesStops.json b/front/public/locales/fr/timesStops.json index fa8b83ea6c4..7e7e3ce33d6 100644 --- a/front/public/locales/fr/timesStops.json +++ b/front/public/locales/fr/timesStops.json @@ -19,5 +19,6 @@ "theoreticalMargin": "marge théorique", "theoreticalMarginPlaceholder": "% ou min/100km", "theoreticalMarginSeconds": "marge théorique (s)", + "trackName": "voie", "waypoint": "Via {{id}}" } diff --git a/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts b/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts index 2280a2b3080..59bc1672f23 100644 --- a/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts +++ b/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts @@ -15,7 +15,7 @@ import { } from 'common/api/osrdEditoastApi'; import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext'; import { - formatSuggestedOperationalPoints, + formatSuggestedOperationalPointsWithTrackName, matchPathStepAndOp, upsertPathStepsInOPs, } from 'modules/pathfinding/utils'; @@ -124,11 +124,14 @@ const useSetupItineraryForTrainUpdate = ( const stepsCoordinates = pathfindingResult.path_item_positions.map((position) => getPointCoordinates(geometry, pathfindingResult.length, position) ); - const suggestedOperationalPoints: SuggestedOP[] = formatSuggestedOperationalPoints( - operational_points, - geometry, - pathfindingResult.length - ); + const suggestedOperationalPoints: SuggestedOP[] = + await formatSuggestedOperationalPointsWithTrackName( + operational_points, + geometry, + pathfindingResult.length, + infraId, + dispatch + ); const computedpathSteps = computeBasePathSteps(trainSchedule); const updatedPathSteps: PathStep[] = updatePathStepsFromOperationalPoints( diff --git a/front/src/modules/pathfinding/hooks/usePathfinding.ts b/front/src/modules/pathfinding/hooks/usePathfinding.ts index fee63419ff0..d1919c3d715 100644 --- a/front/src/modules/pathfinding/hooks/usePathfinding.ts +++ b/front/src/modules/pathfinding/hooks/usePathfinding.ts @@ -16,7 +16,7 @@ import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext'; import { initialState } from 'modules/pathfinding/consts'; import type { PathfindingAction, PathfindingState } from 'modules/pathfinding/types'; import { - formatSuggestedOperationalPoints, + formatSuggestedOperationalPointsWithTrackName, getPathfindingQuery, matchPathStepAndOp, upsertPathStepsInOPs, @@ -294,11 +294,14 @@ export const usePathfinding = ( await postPathProperties(pathPropertiesParams).unwrap(); if (electrifications && geometry && operational_points) { - const suggestedOperationalPoints: SuggestedOP[] = formatSuggestedOperationalPoints( - operational_points, - geometry, - pathResult.length - ); + const suggestedOperationalPoints: SuggestedOP[] = + await formatSuggestedOperationalPointsWithTrackName( + operational_points, + geometry, + pathResult.length, + infraId, + dispatch + ); // We update existing pathsteps with coordinates, positionOnPath and kp corresponding to the new pathfinding result const updatedPathSteps: (PathStep | null)[] = pathSteps.map((step, i) => { diff --git a/front/src/modules/pathfinding/utils.ts b/front/src/modules/pathfinding/utils.ts index 9a7ef0f0049..829362aaade 100644 --- a/front/src/modules/pathfinding/utils.ts +++ b/front/src/modules/pathfinding/utils.ts @@ -1,15 +1,19 @@ -import { compact } from 'lodash'; +import { compact, uniq } from 'lodash'; +import type { TrackSectionEntity } from 'applications/editor/tools/trackEdition/types'; +import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; import type { GeoJsonLineString, PathProperties, PathfindingInput, PostInfraByInfraIdPathfindingBlocksApiArg, RollingStockWithLiveries, + TrackSection, } from 'common/api/osrdEditoastApi'; import { getSupportedElectrification, isThermal } from 'modules/rollingStock/helpers/electric'; import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types'; import type { PathStep } from 'reducers/osrdconf/types'; +import type { AppDispatch } from 'store'; import { addElementAtIndex } from 'utils/array'; import { getPointCoordinates } from 'utils/geometry'; @@ -36,6 +40,52 @@ export const formatSuggestedOperationalPoints = ( coordinates: getPointCoordinates(geometry, pathLength, op.position), })); +export const formatSuggestedOperationalPointsWithTrackName = async ( + operationalPoints: NonNullable>, + geometry: GeoJsonLineString, + pathLength: number, + infraId: number, + dispatch: AppDispatch +): Promise => { + // Extract track IDs to fetch track names + const trackIds = uniq(operationalPoints.map((op) => op.part.track)); + const trackSections = await dispatch( + osrdEditoastApi.endpoints.postInfraByInfraIdObjectsAndObjectType.initiate({ + infraId, + objectType: 'TrackSection', + body: trackIds, + }) + ).unwrap(); + + return operationalPoints.map((op) => { + const associatedTrackSection = trackSections.find( + (trackSection) => (trackSection.railjson as TrackSection).id === op.part.track + ); + + const trackName = associatedTrackSection + ? (associatedTrackSection.railjson as TrackSectionEntity['properties']).extensions?.sncf + ?.track_name + : null; + + return { + opId: op.id, + name: op.extensions?.identifier?.name, + uic: op.extensions?.identifier?.uic, + ch: op.extensions?.sncf?.ch, + kp: op.part.extensions?.sncf?.kp, + chLongLabel: op.extensions?.sncf?.ch_long_label, + chShortLabel: op.extensions?.sncf?.ch_short_label, + ci: op.extensions?.sncf?.ci, + trigram: op.extensions?.sncf?.trigram, + offsetOnTrack: op.part.position, + track: op.part.track, + positionOnPath: op.position, + coordinates: getPointCoordinates(geometry, pathLength, op.position), + trackName: trackName || undefined, + }; + }); +}; + export const matchPathStepAndOp = ( step: PathStep, op: Pick diff --git a/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx b/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx index a1f5d407a81..2fde7f0df75 100644 --- a/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx +++ b/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx @@ -86,7 +86,7 @@ export const useTimeStopsColumns = ( title: t('name'), ...(isOutputTable && { component: ({ rowData }) => ( - + {rowData.name} ), @@ -100,6 +100,17 @@ export const useTimeStopsColumns = ( disabled: true, ...fixedWidth(45), }, + { + ...keyColumn('trackName', createTextColumn()), + title: t('trackName'), + component: ({ rowData }) => ( + + {rowData.trackName} + + ), + disabled: true, + ...fixedWidth(70), + }, { ...keyColumn('arrival', timeColumn(isOutputTable)), title: t('arrivalTime'), diff --git a/front/src/modules/timesStops/types.ts b/front/src/modules/timesStops/types.ts index 46b03a0d6a0..8fd0a267795 100644 --- a/front/src/modules/timesStops/types.ts +++ b/front/src/modules/timesStops/types.ts @@ -13,6 +13,7 @@ export type TimeStopsRow = { opId: string; name?: string; ch?: string; + trackName?: string; isWaypoint: boolean; arrival?: TimeExtraDays; // value asked by user diff --git a/front/src/modules/trainschedule/components/ManageTrainSchedule/types.ts b/front/src/modules/trainschedule/components/ManageTrainSchedule/types.ts index 44cae2b5d82..99dc031339d 100644 --- a/front/src/modules/trainschedule/components/ManageTrainSchedule/types.ts +++ b/front/src/modules/trainschedule/components/ManageTrainSchedule/types.ts @@ -15,6 +15,7 @@ export type SuggestedOP = { trigram?: string; offsetOnTrack: number; track: string; + trackName?: string; /** Distance from the beginning of the path in mm */ positionOnPath: number; coordinates?: Position; diff --git a/front/tests/011-op-times-and-stops-tab.spec.ts b/front/tests/011-op-times-and-stops-tab.spec.ts index f26cc916eb7..eed7c51be3a 100644 --- a/front/tests/011-op-times-and-stops-tab.spec.ts +++ b/front/tests/011-op-times-and-stops-tab.spec.ts @@ -125,6 +125,7 @@ test.describe('Times and Stops Tab Verification', () => { const expectedColumnNames = cleanWhitespaceInArray([ translations.name, translations.ch, + translations.trackName, translations.arrivalTime, translations.stopTime, translations.departureTime, From 6bf38f949eaafbbe5ddbe50aa2b4f131338cf8da Mon Sep 17 00:00:00 2001 From: Alice Khoudli Date: Fri, 15 Nov 2024 21:26:30 +0100 Subject: [PATCH 2/4] front: add scenario content context with cached tracks and infraid Signed-off-by: Alice Khoudli --- .../hooks/useCachedTrackSections.ts | 41 ++++++++++ .../hooks/useScenarioContext.tsx | 35 ++++++++ .../hooks/useSetupItineraryForTrainUpdate.ts | 22 +++--- .../operationalStudies/views/Scenario.tsx | 5 +- .../views/SimulationResults.tsx | 3 +- .../pathfinding/hooks/usePathfinding.ts | 20 +++-- front/src/modules/pathfinding/utils.ts | 62 ++------------- .../SimulationResultExport/utils.ts | 25 +----- .../hooks/useFormattedOperationalPoints.ts | 14 ++-- front/src/modules/timesStops/TimesStops.tsx | 12 +++ .../modules/timesStops/TimesStopsInput.tsx | 33 +++++--- .../modules/timesStops/TimesStopsOutput.tsx | 11 +-- .../timesStops/hooks/useOutputTableData.ts | 79 +++++++++++-------- 13 files changed, 202 insertions(+), 160 deletions(-) create mode 100644 front/src/applications/operationalStudies/hooks/useCachedTrackSections.ts create mode 100644 front/src/applications/operationalStudies/hooks/useScenarioContext.tsx diff --git a/front/src/applications/operationalStudies/hooks/useCachedTrackSections.ts b/front/src/applications/operationalStudies/hooks/useCachedTrackSections.ts new file mode 100644 index 00000000000..13f938f29e5 --- /dev/null +++ b/front/src/applications/operationalStudies/hooks/useCachedTrackSections.ts @@ -0,0 +1,41 @@ +import { useRef, useCallback } from 'react'; + +import { uniq } from 'lodash'; + +import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; +import type { TrackSection } from 'common/api/osrdEditoastApi'; + +export default function useCachedTrackSections(infraId: number) { + const trackIdsRef = useRef>(new Set()); + const trackSectionsRef = useRef>({}); + const [loadInfraObject, { isLoading }] = + osrdEditoastApi.endpoints.postInfraByInfraIdObjectsAndObjectType.useMutation(); + + const getTrackSectionsByIds = useCallback( + async (requestedTrackIds: string[]) => { + const uniqueNewIds = uniq(requestedTrackIds.filter((id) => !trackIdsRef.current.has(id))); + if (uniqueNewIds.length !== 0) { + try { + const fetchedSections = await loadInfraObject({ + infraId, + objectType: 'TrackSection', + body: uniqueNewIds, + }).unwrap(); + + uniqueNewIds.forEach((id) => trackIdsRef.current.add(id)); + fetchedSections.forEach((rawSection) => { + const trackSection = rawSection.railjson as TrackSection; + trackSectionsRef.current[trackSection.id] = trackSection; + }); + } catch (error) { + console.error('Failed to fetch track sections:', error); + } + } + + return trackSectionsRef.current; + }, + [infraId] + ); + + return { getTrackSectionsByIds, isLoading }; +} diff --git a/front/src/applications/operationalStudies/hooks/useScenarioContext.tsx b/front/src/applications/operationalStudies/hooks/useScenarioContext.tsx new file mode 100644 index 00000000000..929b3f230f9 --- /dev/null +++ b/front/src/applications/operationalStudies/hooks/useScenarioContext.tsx @@ -0,0 +1,35 @@ +import { createContext, useContext, useMemo, type ReactNode } from 'react'; + +import useCachedTrackSections from 'applications/operationalStudies/hooks/useCachedTrackSections'; +import type { TrackSection } from 'common/api/osrdEditoastApi'; + +type ScenarioContextType = { + getTrackSectionsByIds: (requestedTrackIds: string[]) => Promise>; + infraId: number; + trackSectionsLoading: boolean; +} | null; +const ScenarioContext = createContext(null); + +type ScenarioContextProviderProps = { infraId: number; children: ReactNode }; + +export const ScenarioContextProvider = ({ infraId, children }: ScenarioContextProviderProps) => { + const { getTrackSectionsByIds, isLoading: trackSectionsLoading } = + useCachedTrackSections(infraId); + const providedContext = useMemo( + () => ({ + getTrackSectionsByIds, + infraId, + trackSectionsLoading, + }), + [getTrackSectionsByIds, infraId, trackSectionsLoading] + ); + return {children}; +}; + +export const useScenarioContext = () => { + const context = useContext(ScenarioContext); + if (!context) { + throw new Error('useScenarioContext must be used within a ScenarioContextProvider'); + } + return context; +}; diff --git a/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts b/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts index 59bc1672f23..c0ce6ac2c94 100644 --- a/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts +++ b/front/src/applications/operationalStudies/hooks/useSetupItineraryForTrainUpdate.ts @@ -2,7 +2,6 @@ import { useEffect } from 'react'; import { type Position } from '@turf/helpers'; import { omit } from 'lodash'; -import { useSelector } from 'react-redux'; import { osrdEditoastApi, @@ -13,9 +12,9 @@ import { type TrainScheduleResult, type PathfindingResult, } from 'common/api/osrdEditoastApi'; -import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext'; +import { useOsrdConfActions } from 'common/osrdContext'; import { - formatSuggestedOperationalPointsWithTrackName, + formatSuggestedOperationalPoints, matchPathStepAndOp, upsertPathStepsInOPs, } from 'modules/pathfinding/utils'; @@ -29,6 +28,7 @@ import { castErrorToFailure } from 'utils/error'; import { getPointCoordinates } from 'utils/geometry'; import type { ManageTrainSchedulePathProperties } from '../types'; +import { useScenarioContext } from './useScenarioContext'; type ItineraryForTrainUpdate = { pathSteps: (PathStep | null)[]; @@ -64,8 +64,6 @@ const useSetupItineraryForTrainUpdate = ( setPathProperties: (pathProperties: ManageTrainSchedulePathProperties) => void, trainIdToEdit: number ) => { - const { getInfraID } = useOsrdConfSelectors(); - const infraId = useSelector(getInfraID); const dispatch = useAppDispatch(); const { updatePathSteps } = useOsrdConfActions(); @@ -77,6 +75,7 @@ const useSetupItineraryForTrainUpdate = ( osrdEditoastApi.endpoints.postInfraByInfraIdPathfindingBlocks.useMutation(); const [postPathProperties] = osrdEditoastApi.endpoints.postInfraByInfraIdPathProperties.useMutation(); + const { infraId } = useScenarioContext(); useEffect(() => { const computeItineraryForTrainUpdate = async ( @@ -124,14 +123,11 @@ const useSetupItineraryForTrainUpdate = ( const stepsCoordinates = pathfindingResult.path_item_positions.map((position) => getPointCoordinates(geometry, pathfindingResult.length, position) ); - const suggestedOperationalPoints: SuggestedOP[] = - await formatSuggestedOperationalPointsWithTrackName( - operational_points, - geometry, - pathfindingResult.length, - infraId, - dispatch - ); + const suggestedOperationalPoints: SuggestedOP[] = formatSuggestedOperationalPoints( + operational_points, + geometry, + pathfindingResult.length + ); const computedpathSteps = computeBasePathSteps(trainSchedule); const updatedPathSteps: PathStep[] = updatePathStepsFromOperationalPoints( diff --git a/front/src/applications/operationalStudies/views/Scenario.tsx b/front/src/applications/operationalStudies/views/Scenario.tsx index 62bccaa60d2..4516d03ad90 100644 --- a/front/src/applications/operationalStudies/views/Scenario.tsx +++ b/front/src/applications/operationalStudies/views/Scenario.tsx @@ -1,6 +1,7 @@ import BreadCrumbs from 'applications/operationalStudies/components/BreadCrumbs'; import ScenarioContent from 'applications/operationalStudies/components/Scenario/ScenarioContent'; import useScenario from 'applications/operationalStudies/hooks/useScenario'; +import { ScenarioContextProvider } from 'applications/operationalStudies/hooks/useScenarioContext'; import useScenarioQueryParams from 'applications/operationalStudies/hooks/useScenarioQueryParams'; import NavBarSNCF from 'common/BootstrapSNCF/NavBarSNCF'; import useInfraStatus from 'modules/pathfinding/hooks/useInfraStatus'; @@ -17,7 +18,7 @@ const Scenario = () => { if (!scenario || !timetable || !infra) return null; return ( - <> + @@ -29,7 +30,7 @@ const Scenario = () => { infra={infra} infraMetadata={infraData} /> - + ); }; diff --git a/front/src/applications/operationalStudies/views/SimulationResults.tsx b/front/src/applications/operationalStudies/views/SimulationResults.tsx index 45444fef38b..fc29092bf30 100644 --- a/front/src/applications/operationalStudies/views/SimulationResults.tsx +++ b/front/src/applications/operationalStudies/views/SimulationResults.tsx @@ -71,8 +71,7 @@ const SimulationResults = ({ const { operationalPoints, loading: formattedOpPointsLoading } = useFormattedOperationalPoints( selectedTrainSchedule, trainSimulation, - pathProperties, - infraId + pathProperties ); // Compute path items coordinates in order to place them on the map diff --git a/front/src/modules/pathfinding/hooks/usePathfinding.ts b/front/src/modules/pathfinding/hooks/usePathfinding.ts index d1919c3d715..1b97034dc55 100644 --- a/front/src/modules/pathfinding/hooks/usePathfinding.ts +++ b/front/src/modules/pathfinding/hooks/usePathfinding.ts @@ -4,6 +4,7 @@ import { compact, isEqual, isObject } from 'lodash'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; +import { useScenarioContext } from 'applications/operationalStudies/hooks/useScenarioContext'; import type { ManageTrainSchedulePathProperties } from 'applications/operationalStudies/types'; import type { PathfindingInputError, @@ -16,7 +17,7 @@ import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext'; import { initialState } from 'modules/pathfinding/consts'; import type { PathfindingAction, PathfindingState } from 'modules/pathfinding/types'; import { - formatSuggestedOperationalPointsWithTrackName, + formatSuggestedOperationalPoints, getPathfindingQuery, matchPathStepAndOp, upsertPathStepsInOPs, @@ -150,9 +151,8 @@ export const usePathfinding = ( ) => { const { t } = useTranslation(['operationalStudies/manageTrainSchedule']); const dispatch = useAppDispatch(); - const { getInfraID, getOrigin, getDestination, getVias, getPathSteps, getPowerRestriction } = + const { getOrigin, getDestination, getVias, getPathSteps, getPowerRestriction } = useOsrdConfSelectors(); - const infraId = useSelector(getInfraID, isEqual); const origin = useSelector(getOrigin, isEqual); const destination = useSelector(getDestination, isEqual); const vias = useSelector(getVias(), isEqual); @@ -178,6 +178,7 @@ export const usePathfinding = ( osrdEditoastApi.endpoints.postInfraByInfraIdPathProperties.useMutation(); const { updatePathSteps } = useOsrdConfActions(); + const { infraId } = useScenarioContext(); const generatePathfindingParams = (): PostInfraByInfraIdPathfindingBlocksApiArg | null => { setPathProperties?.(undefined); @@ -294,14 +295,11 @@ export const usePathfinding = ( await postPathProperties(pathPropertiesParams).unwrap(); if (electrifications && geometry && operational_points) { - const suggestedOperationalPoints: SuggestedOP[] = - await formatSuggestedOperationalPointsWithTrackName( - operational_points, - geometry, - pathResult.length, - infraId, - dispatch - ); + const suggestedOperationalPoints: SuggestedOP[] = formatSuggestedOperationalPoints( + operational_points, + geometry, + pathResult.length + ); // We update existing pathsteps with coordinates, positionOnPath and kp corresponding to the new pathfinding result const updatedPathSteps: (PathStep | null)[] = pathSteps.map((step, i) => { diff --git a/front/src/modules/pathfinding/utils.ts b/front/src/modules/pathfinding/utils.ts index 829362aaade..46d5823cdcf 100644 --- a/front/src/modules/pathfinding/utils.ts +++ b/front/src/modules/pathfinding/utils.ts @@ -1,19 +1,15 @@ -import { compact, uniq } from 'lodash'; +import { compact } from 'lodash'; -import type { TrackSectionEntity } from 'applications/editor/tools/trackEdition/types'; -import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; import type { GeoJsonLineString, PathProperties, PathfindingInput, PostInfraByInfraIdPathfindingBlocksApiArg, RollingStockWithLiveries, - TrackSection, } from 'common/api/osrdEditoastApi'; import { getSupportedElectrification, isThermal } from 'modules/rollingStock/helpers/electric'; import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types'; import type { PathStep } from 'reducers/osrdconf/types'; -import type { AppDispatch } from 'store'; import { addElementAtIndex } from 'utils/array'; import { getPointCoordinates } from 'utils/geometry'; @@ -21,8 +17,8 @@ import getStepLocation from './helpers/getStepLocation'; export const formatSuggestedOperationalPoints = ( operationalPoints: NonNullable>, - geometry: GeoJsonLineString, - pathLength: number + geometry?: GeoJsonLineString, + pathLength?: number ): SuggestedOP[] => operationalPoints.map((op) => ({ opId: op.id, @@ -37,55 +33,13 @@ export const formatSuggestedOperationalPoints = ( offsetOnTrack: op.part.position, track: op.part.track, positionOnPath: op.position, - coordinates: getPointCoordinates(geometry, pathLength, op.position), + coordinates: + (geometry !== undefined && + pathLength !== undefined && + getPointCoordinates(geometry, pathLength, op.position)) || + undefined, })); -export const formatSuggestedOperationalPointsWithTrackName = async ( - operationalPoints: NonNullable>, - geometry: GeoJsonLineString, - pathLength: number, - infraId: number, - dispatch: AppDispatch -): Promise => { - // Extract track IDs to fetch track names - const trackIds = uniq(operationalPoints.map((op) => op.part.track)); - const trackSections = await dispatch( - osrdEditoastApi.endpoints.postInfraByInfraIdObjectsAndObjectType.initiate({ - infraId, - objectType: 'TrackSection', - body: trackIds, - }) - ).unwrap(); - - return operationalPoints.map((op) => { - const associatedTrackSection = trackSections.find( - (trackSection) => (trackSection.railjson as TrackSection).id === op.part.track - ); - - const trackName = associatedTrackSection - ? (associatedTrackSection.railjson as TrackSectionEntity['properties']).extensions?.sncf - ?.track_name - : null; - - return { - opId: op.id, - name: op.extensions?.identifier?.name, - uic: op.extensions?.identifier?.uic, - ch: op.extensions?.sncf?.ch, - kp: op.part.extensions?.sncf?.kp, - chLongLabel: op.extensions?.sncf?.ch_long_label, - chShortLabel: op.extensions?.sncf?.ch_short_label, - ci: op.extensions?.sncf?.ci, - trigram: op.extensions?.sncf?.trigram, - offsetOnTrack: op.part.position, - track: op.part.track, - positionOnPath: op.position, - coordinates: getPointCoordinates(geometry, pathLength, op.position), - trackName: trackName || undefined, - }; - }); -}; - export const matchPathStepAndOp = ( step: PathStep, op: Pick diff --git a/front/src/modules/simulationResult/SimulationResultExport/utils.ts b/front/src/modules/simulationResult/SimulationResultExport/utils.ts index d799c21e0f9..44b0c9bd4f7 100644 --- a/front/src/modules/simulationResult/SimulationResultExport/utils.ts +++ b/front/src/modules/simulationResult/SimulationResultExport/utils.ts @@ -1,7 +1,5 @@ import * as d3 from 'd3'; -import { uniq } from 'lodash'; -import type { TrackSectionEntity } from 'applications/editor/tools/trackEdition/types'; import type { OperationalPointWithTimeAndSpeed, PathPropertiesFormatted, @@ -9,13 +7,11 @@ import type { } from 'applications/operationalStudies/types'; import { convertDepartureTimeIntoSec } from 'applications/operationalStudies/utils'; import { - osrdEditoastApi, type ReportTrain, type TrackSection, type TrainScheduleBase, } from 'common/api/osrdEditoastApi'; import type { SpeedRanges } from 'reducers/simulationResults/types'; -import { store } from 'store'; import { mmToM, msToKmhRounded } from 'utils/physics'; import { ISO8601Duration2sec, ms2sec } from 'utils/timeManipulation'; @@ -108,20 +104,8 @@ export const formatOperationalPoints = async ( operationalPoints: PathPropertiesFormatted['operationalPoints'], simulatedTrain: SimulationResponseSuccess, train: TrainScheduleBase, - infraId: number + trackSections: Record ): Promise => { - // Get operational points metadata - const trackIds = uniq(operationalPoints.map((op) => op.part.track)); - const trackSections = await store - .dispatch( - osrdEditoastApi.endpoints.postInfraByInfraIdObjectsAndObjectType.initiate({ - infraId, - objectType: 'TrackSection', - body: trackIds, - }) - ) - .unwrap(); - // Format operational points const formattedStops: OperationalPointWithTimeAndSpeed[] = []; @@ -147,14 +131,11 @@ export const formatOperationalPoints = async ( } } - const associatedTrackSection = trackSections.find( - (trackSection) => (trackSection.railjson as TrackSection).id === op.part.track - ); + const associatedTrackSection = trackSections[op.part.track]; let metadata; if (associatedTrackSection) { - metadata = (associatedTrackSection.railjson as TrackSectionEntity['properties']).extensions - ?.sncf; + metadata = associatedTrackSection.extensions?.sncf; } const opCommonProp = { diff --git a/front/src/modules/simulationResult/hooks/useFormattedOperationalPoints.ts b/front/src/modules/simulationResult/hooks/useFormattedOperationalPoints.ts index 102627cd82a..95cf75a97a9 100644 --- a/front/src/modules/simulationResult/hooks/useFormattedOperationalPoints.ts +++ b/front/src/modules/simulationResult/hooks/useFormattedOperationalPoints.ts @@ -1,6 +1,7 @@ /* eslint-disable import/prefer-default-export */ import { useEffect, useState } from 'react'; +import { useScenarioContext } from 'applications/operationalStudies/hooks/useScenarioContext'; import type { OperationalPointWithTimeAndSpeed, PathPropertiesFormatted, @@ -16,28 +17,31 @@ import { formatOperationalPoints } from '../SimulationResultExport/utils'; export const useFormattedOperationalPoints = ( train?: TrainScheduleBase, simulatedTrain?: SimulationResponseSuccess, - pathProperties?: PathPropertiesFormatted, - infraId?: number + pathProperties?: PathPropertiesFormatted ) => { const [operationalPoints, setOperationalPoints] = useState(); const [loading, setLoading] = useState(false); + const { getTrackSectionsByIds } = useScenarioContext(); useEffect(() => { - if (train && simulatedTrain && pathProperties && infraId) { + if (train && simulatedTrain && pathProperties) { const fetchOperationalPoints = async () => { setLoading(true); + + const trackIds = pathProperties.operationalPoints.map((op) => op.part.track); + const trackSections = await getTrackSectionsByIds(trackIds); const formattedOperationalPoints = await formatOperationalPoints( pathProperties.operationalPoints, simulatedTrain, train, - infraId + trackSections ); setOperationalPoints(formattedOperationalPoints); setLoading(false); }; fetchOperationalPoints(); } - }, [train, simulatedTrain, pathProperties, infraId]); + }, [train, simulatedTrain, pathProperties, getTrackSectionsByIds]); return { operationalPoints, loading }; }; diff --git a/front/src/modules/timesStops/TimesStops.tsx b/front/src/modules/timesStops/TimesStops.tsx index ced3317077a..1791b74d609 100644 --- a/front/src/modules/timesStops/TimesStops.tsx +++ b/front/src/modules/timesStops/TimesStops.tsx @@ -3,6 +3,8 @@ import { DynamicDataSheetGrid, type DataSheetGridProps } from 'react-datasheet-g import type { Operation } from 'react-datasheet-grid/dist/types'; import { useTranslation } from 'react-i18next'; +import { Loader } from 'common/Loaders/Loader'; + import { useTimeStopsColumns } from './hooks/useTimeStopsColumns'; import { type TableType, type TimeStopsRow } from './types'; @@ -13,6 +15,7 @@ type TimesStopsProps = { stickyRightColumn?: DataSheetGridProps['stickyRightColumn']; headerRowHeight?: number; onChange?: (newRows: T[], operation: Operation) => void; + dataIsLoading: boolean; }; const TimesStops = ({ @@ -22,11 +25,20 @@ const TimesStops = ({ stickyRightColumn, headerRowHeight, onChange, + dataIsLoading, }: TimesStopsProps) => { const { t } = useTranslation('timesStops'); const columns = useTimeStopsColumns(tableType, rows); + if (dataIsLoading) { + return ( +
+ +
+ ); + } + if (!rows) { return (
diff --git a/front/src/modules/timesStops/TimesStopsInput.tsx b/front/src/modules/timesStops/TimesStopsInput.tsx index cc298669cd7..da89b7e911f 100644 --- a/front/src/modules/timesStops/TimesStopsInput.tsx +++ b/front/src/modules/timesStops/TimesStopsInput.tsx @@ -5,6 +5,7 @@ import { isEqual, isNil } from 'lodash'; import type { Operation } from 'react-datasheet-grid/dist/types'; import { useTranslation } from 'react-i18next'; +import { useScenarioContext } from 'applications/operationalStudies/hooks/useScenarioContext'; import { useOsrdConfActions } from 'common/osrdContext'; import { isVia, matchPathStepAndOp } from 'modules/pathfinding/utils'; import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types'; @@ -68,6 +69,7 @@ const TimesStopsInput = ({ allWaypoints, startTime, pathSteps }: TimesStopsInput const { updatePathSteps, upsertSeveralViasFromSuggestedOP } = useOsrdConfActions(); const [rows, setRows] = useState([]); + const { getTrackSectionsByIds, trackSectionsLoading } = useScenarioContext(); const clearPathStep = (rowData: TimesStopsInputRow) => { const index = pathSteps.findIndex( @@ -123,16 +125,26 @@ const TimesStopsInput = ({ allWaypoints, startTime, pathSteps }: TimesStopsInput ); useEffect(() => { - if (allWaypoints) { - const suggestedOPs = formatSuggestedViasToRowVias( - allWaypoints, - pathSteps || [], - t, - startTime, - TableType.Input - ); - setRows(updateDaySinceDeparture(suggestedOPs, startTime, { keepFirstIndexArrival: true })); - } + const fetchAndFormatRows = async () => { + if (allWaypoints) { + const trackIds = allWaypoints.map((op) => op.track); + const trackSections = await getTrackSectionsByIds(trackIds); + const suggestedOPsWithTrackNames = allWaypoints.map((op) => ({ + ...op, + trackName: trackSections[op.track]?.extensions?.sncf?.track_name, + })); + const formatedRows = formatSuggestedViasToRowVias( + suggestedOPsWithTrackNames, + pathSteps || [], + t, + startTime, + TableType.Input + ); + setRows(updateDaySinceDeparture(formatedRows, startTime, { keepFirstIndexArrival: true })); + } + }; + + fetchAndFormatRows(); }, [allWaypoints, pathSteps, startTime]); return ( @@ -150,6 +162,7 @@ const TimesStopsInput = ({ allWaypoints, startTime, pathSteps }: TimesStopsInput }), }} onChange={onChange} + dataIsLoading={trackSectionsLoading} /> ); }; diff --git a/front/src/modules/timesStops/TimesStopsOutput.tsx b/front/src/modules/timesStops/TimesStopsOutput.tsx index e62d58fbb52..91f9e7e09c9 100644 --- a/front/src/modules/timesStops/TimesStopsOutput.tsx +++ b/front/src/modules/timesStops/TimesStopsOutput.tsx @@ -5,7 +5,6 @@ import type { SimulationResponseSuccess, } from 'applications/operationalStudies/types'; import type { PathfindingResultSuccess, TrainScheduleResult } from 'common/api/osrdEditoastApi'; -import { Loader } from 'common/Loaders/Loader'; import type { TrainScheduleWithDetails } from 'modules/trainschedule/components/Timetable/types'; import { NO_BREAK_SPACE } from 'utils/strings'; @@ -37,15 +36,6 @@ const TimesStopsOutput = ({ selectedTrainSchedule, path ); - - if (dataIsLoading || !trainSummary || !operationalPoints || !selectedTrainSchedule) { - return ( -
- -
- ); - } - return ( ); }; diff --git a/front/src/modules/timesStops/hooks/useOutputTableData.ts b/front/src/modules/timesStops/hooks/useOutputTableData.ts index 5c32db8cdba..ba7d4d904ff 100644 --- a/front/src/modules/timesStops/hooks/useOutputTableData.ts +++ b/front/src/modules/timesStops/hooks/useOutputTableData.ts @@ -1,8 +1,9 @@ -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { keyBy } from 'lodash'; import { useTranslation } from 'react-i18next'; +import { useScenarioContext } from 'applications/operationalStudies/hooks/useScenarioContext'; import type { PathPropertiesFormatted, SimulationResponseSuccess, @@ -27,6 +28,9 @@ const useOutputTableData = ( path?: PathfindingResultSuccess ): TimeStopsRow[] => { const { t } = useTranslation('timesStops'); + const { getTrackSectionsByIds } = useScenarioContext(); + + const [rows, setRows] = useState([]); const scheduleByAt: Record = keyBy(selectedTrainSchedule?.schedule, 'at'); const theoreticalMargins = selectedTrainSchedule && getTheoreticalMargins(selectedTrainSchedule); @@ -101,44 +105,57 @@ const useOutputTableData = ( positionOnPath: path.path_item_positions[index], }; }); - }, [selectedTrainSchedule, path, trainSummary?.pathItemTimes, startDatetime]); + }, [selectedTrainSchedule, path, trainSummary?.pathItemTimes]); - const rows: TimeStopsRow[] = useMemo(() => { - if (!operationalPoints || !startDatetime) return []; + useEffect(() => { + const formatRows = async () => { + if (!operationalPoints || !startDatetime) { + setRows([]); + return; + } + + const trackIds = operationalPoints.map((op) => op.part.track); + const trackSections = await getTrackSectionsByIds(trackIds); + + const formattedRows = operationalPoints.map((op) => { + const matchingPathStep = pathStepRows.find( + (pathStepRow) => op.position === pathStepRow.positionOnPath + ); + if (matchingPathStep) { + return { + ...matchingPathStep, + opId: op.id, + name: op.extensions?.identifier?.name, + ch: op.extensions?.sncf?.ch, + trackName: trackSections[op.part.track]?.extensions?.sncf?.track_name, + }; + } + + // compute arrival time + const matchingReportTrainIndex = simulatedTrain.positions.findIndex( + (position) => position === op.position + ); + + const time = + matchingReportTrainIndex === -1 + ? interpolateValue(simulatedTrain, op.position, 'times') + : simulatedTrain.times[matchingReportTrainIndex]; + const calculatedArrival = new Date(startDatetime.getTime() + time); - return operationalPoints.map((op) => { - const matchingPathStep = pathStepRows.find( - (pathStepRow) => op.position === pathStepRow.positionOnPath - ); - if (matchingPathStep) { return { - ...matchingPathStep, + isWaypoint: false, opId: op.id, name: op.extensions?.identifier?.name, ch: op.extensions?.sncf?.ch, + calculatedArrival: dateToHHMMSS(calculatedArrival), + trackName: trackSections[op.part.track]?.extensions?.sncf?.track_name, }; - } - - // compute arrival time - const matchingReportTrainIndex = simulatedTrain.positions.findIndex( - (position) => position === op.position - ); - - const time = - matchingReportTrainIndex === -1 - ? interpolateValue(simulatedTrain, op.position, 'times') - : simulatedTrain.times[matchingReportTrainIndex]; - const calculatedArrival = new Date(startDatetime.getTime() + time); + }); + setRows(formattedRows); + }; - return { - isWaypoint: false, - opId: op.id, - name: op.extensions?.identifier?.name, - ch: op.extensions?.sncf?.ch, - calculatedArrival: dateToHHMMSS(calculatedArrival), - }; - }); - }, [operationalPoints, pathStepRows, simulatedTrain, startDatetime]); + formatRows(); + }, [operationalPoints, pathStepRows, simulatedTrain, getTrackSectionsByIds]); return rows; }; From c736ade763b5998856984ae000fafb8519546254 Mon Sep 17 00:00:00 2001 From: Alice Khoudli Date: Fri, 22 Nov 2024 21:27:19 +0100 Subject: [PATCH 3/4] front: fix flaky scroll container selection in e2e tests Signed-off-by: Alice Khoudli --- front/tests/utils/scrollHelper.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/front/tests/utils/scrollHelper.ts b/front/tests/utils/scrollHelper.ts index 1e3a7b8f45b..d58b604ad53 100644 --- a/front/tests/utils/scrollHelper.ts +++ b/front/tests/utils/scrollHelper.ts @@ -20,6 +20,7 @@ const scrollContainer = async ( { stepSize = 300, timeout = 20, scrollOffsetThreshold = 200 }: ScrollOptions = {} ): Promise => { // Locate the scrollable container on the page + await page.waitForSelector(containerSelector, { state: 'visible' }); const container = await page.evaluateHandle( (selector: string) => document.querySelector(selector), containerSelector From 2e4b9027175d5eb84d63008db3c2944946c32f54 Mon Sep 17 00:00:00 2001 From: Alice Khoudli Date: Thu, 28 Nov 2024 11:55:09 +0100 Subject: [PATCH 4/4] front: add track check to output and input timestops table e2e tests Signed-off-by: Alice Khoudli --- .../modules/timesStops/hooks/useTimeStopsColumns.tsx | 12 +++++++----- .../simulationSettings/allSettings.json | 4 ++++ .../simulationSettings/codeCompo/codeCompoOFF.json | 4 ++++ .../simulationSettings/codeCompo/codeCompoON.json | 4 ++++ .../electricalProfiles/electricalProfileOFF.json | 4 ++++ .../electricalProfiles/electricalProfileON.json | 4 ++++ .../simulationSettings/margin/linearMargin.json | 4 ++++ .../simulationSettings/margin/marecoMargin.json | 4 ++++ .../timesAndStops/expectedInputsCellsData.json | 8 ++++---- .../timesAndStops/expectedOutputsCellsData.json | 4 ++++ .../timesAndStops/updatedInputsCellsData.json | 8 ++++---- front/tests/pages/op-output-table-page-model.ts | 6 ++++++ front/tests/utils/dataNormalizer.ts | 2 ++ 13 files changed, 55 insertions(+), 13 deletions(-) diff --git a/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx b/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx index 2fde7f0df75..26aed1cb091 100644 --- a/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx +++ b/front/src/modules/timesStops/hooks/useTimeStopsColumns.tsx @@ -103,11 +103,13 @@ export const useTimeStopsColumns = ( { ...keyColumn('trackName', createTextColumn()), title: t('trackName'), - component: ({ rowData }) => ( - - {rowData.trackName} - - ), + ...(isOutputTable && { + component: ({ rowData }) => ( + + {rowData.trackName} + + ), + }), disabled: true, ...fixedWidth(70), }, diff --git a/front/tests/assets/operationStudies/simulationSettings/allSettings.json b/front/tests/assets/operationStudies/simulationSettings/allSettings.json index 8447a80c4e3..ea82661daa9 100644 --- a/front/tests/assets/operationStudies/simulationSettings/allSettings.json +++ b/front/tests/assets/operationStudies/simulationSettings/allSettings.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "", @@ -34,6 +36,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "124", @@ -50,6 +53,7 @@ { "stationName": "South_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoOFF.json b/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoOFF.json index d1228895f7c..16e90cbeea0 100644 --- a/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoOFF.json +++ b/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoOFF.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "", @@ -34,6 +36,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "124", @@ -50,6 +53,7 @@ { "stationName": "South_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoON.json b/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoON.json index f59ba41d1b1..17e640d2342 100644 --- a/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoON.json +++ b/front/tests/assets/operationStudies/simulationSettings/codeCompo/codeCompoON.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "", @@ -34,6 +36,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "124", @@ -50,6 +53,7 @@ { "stationName": "South_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileOFF.json b/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileOFF.json index d1228895f7c..16e90cbeea0 100644 --- a/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileOFF.json +++ b/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileOFF.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "", @@ -34,6 +36,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "124", @@ -50,6 +53,7 @@ { "stationName": "South_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileON.json b/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileON.json index dbfbdff8b37..34bb1e776fb 100644 --- a/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileON.json +++ b/front/tests/assets/operationStudies/simulationSettings/electricalProfiles/electricalProfileON.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "", @@ -34,6 +36,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "124", @@ -50,6 +53,7 @@ { "stationName": "South_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/simulationSettings/margin/linearMargin.json b/front/tests/assets/operationStudies/simulationSettings/margin/linearMargin.json index 6699850d98e..010b0e76634 100644 --- a/front/tests/assets/operationStudies/simulationSettings/margin/linearMargin.json +++ b/front/tests/assets/operationStudies/simulationSettings/margin/linearMargin.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "", @@ -34,6 +36,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "124", @@ -50,6 +53,7 @@ { "stationName": "South_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/simulationSettings/margin/marecoMargin.json b/front/tests/assets/operationStudies/simulationSettings/margin/marecoMargin.json index 2c8c65f8caa..1a6cd673439 100644 --- a/front/tests/assets/operationStudies/simulationSettings/margin/marecoMargin.json +++ b/front/tests/assets/operationStudies/simulationSettings/margin/marecoMargin.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "", @@ -34,6 +36,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "124", @@ -50,6 +53,7 @@ { "stationName": "South_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/timesAndStops/expectedInputsCellsData.json b/front/tests/assets/operationStudies/timesAndStops/expectedInputsCellsData.json index e11dc07070c..0d672d544fa 100644 --- a/front/tests/assets/operationStudies/timesAndStops/expectedInputsCellsData.json +++ b/front/tests/assets/operationStudies/timesAndStops/expectedInputsCellsData.json @@ -1,18 +1,18 @@ [ { "row": 1, - "values": ["West_station", "BV", "11:22:40", "", "", "5%"] + "values": ["West_station", "BV", "V2", "11:22:40", "", "", "5%"] }, { "row": 2, - "values": ["Mid_West_station", "BV", "11:47:40", "300", "11:52:40", "1min/100km"] + "values": ["Mid_West_station", "BV", "V1", "11:47:40", "300", "11:52:40", "1min/100km"] }, { "row": 3, - "values": ["Mid_East_station", "BV", "12:05:21", "124", "12:07:25", ""] + "values": ["Mid_East_station", "BV", "V1", "12:05:21", "124", "12:07:25", ""] }, { "row": 4, - "values": ["North_East_station", "BV", "", "0", "", ""] + "values": ["North_East_station", "BV", "V2", "", "0", "", ""] } ] diff --git a/front/tests/assets/operationStudies/timesAndStops/expectedOutputsCellsData.json b/front/tests/assets/operationStudies/timesAndStops/expectedOutputsCellsData.json index a4a41d5d553..558b5e0967d 100644 --- a/front/tests/assets/operationStudies/timesAndStops/expectedOutputsCellsData.json +++ b/front/tests/assets/operationStudies/timesAndStops/expectedOutputsCellsData.json @@ -2,6 +2,7 @@ { "stationName": "West_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "11:22:40", "requestedDeparture": "", "stopTime": "", @@ -18,6 +19,7 @@ { "stationName": "Mid_West_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "11:47:40", "requestedDeparture": "11:52:40", "stopTime": "300", @@ -35,6 +37,7 @@ { "stationName": "Mid_East_station", "stationCh": "BV", + "trackName": "V1", "requestedArrival": "12:05:21", "requestedDeparture": "12:07:25", "stopTime": "124", @@ -51,6 +54,7 @@ { "stationName": "North_East_station", "stationCh": "BV", + "trackName": "V2", "requestedArrival": "", "requestedDeparture": "", "stopTime": "0", diff --git a/front/tests/assets/operationStudies/timesAndStops/updatedInputsCellsData.json b/front/tests/assets/operationStudies/timesAndStops/updatedInputsCellsData.json index 51c6db076b2..bebefde2fbd 100644 --- a/front/tests/assets/operationStudies/timesAndStops/updatedInputsCellsData.json +++ b/front/tests/assets/operationStudies/timesAndStops/updatedInputsCellsData.json @@ -1,18 +1,18 @@ [ { "row": 1, - "values": ["West_station", "BV", "11:22:40", "", "", "3%"] + "values": ["West_station", "BV", "V2", "11:22:40", "", "", "3%"] }, { "row": 2, - "values": ["Mid_West_station", "BV", "", "", "", ""] + "values": ["Mid_West_station", "BV", "V1", "", "", "", ""] }, { "row": 3, - "values": ["Mid_East_station", "BV", "13:58:19", "21", "13:58:40", ""] + "values": ["Mid_East_station", "BV", "V1", "13:58:19", "21", "13:58:40", ""] }, { "row": 4, - "values": ["North_East_station", "BV", "", "0", "", ""] + "values": ["North_East_station", "BV", "V2", "", "0", "", ""] } ] diff --git a/front/tests/pages/op-output-table-page-model.ts b/front/tests/pages/op-output-table-page-model.ts index f4725ee7f2a..789909be16b 100644 --- a/front/tests/pages/op-output-table-page-model.ts +++ b/front/tests/pages/op-output-table-page-model.ts @@ -53,6 +53,7 @@ class OperationalStudiesOutputTablePage extends OperationalStudiesTimetablePage const [ stationName, stationCh, + trackName, requestedArrival, requestedDeparture, stopTime, @@ -70,6 +71,10 @@ class OperationalStudiesOutputTablePage extends OperationalStudiesTimetablePage false ), OperationalStudiesOutputTablePage.getCellValue(cells.nth(headerIndexMap[translations.ch])), + OperationalStudiesOutputTablePage.getCellValue( + cells.nth(headerIndexMap[translations.trackName]), + false + ), OperationalStudiesOutputTablePage.getCellValue( cells.nth(headerIndexMap[translations.arrivalTime]), false @@ -114,6 +119,7 @@ class OperationalStudiesOutputTablePage extends OperationalStudiesTimetablePage actualTableData.push({ stationName, stationCh, + trackName, requestedArrival, requestedDeparture, stopTime, diff --git a/front/tests/utils/dataNormalizer.ts b/front/tests/utils/dataNormalizer.ts index 1cca0c5da40..5f73a4e3a7c 100644 --- a/front/tests/utils/dataNormalizer.ts +++ b/front/tests/utils/dataNormalizer.ts @@ -8,6 +8,7 @@ interface Margin { export interface StationData { stationName: string; stationCh: string; + trackName: string; requestedArrival: string; requestedDeparture: string; stopTime: string; @@ -58,6 +59,7 @@ export function normalizeData(data: StationData[]): StationData[] { return data.map((item) => ({ stationName: cleanWhitespace(item.stationName), stationCh: cleanWhitespace(item.stationCh), + trackName: cleanWhitespace(item.trackName), requestedArrival: cleanWhitespace(item.requestedArrival), requestedDeparture: cleanWhitespace(item.requestedDeparture), stopTime: cleanWhitespace(item.stopTime),