diff --git a/front/src/applications/operationalStudies/components/MacroEditor/import.ts b/front/src/applications/operationalStudies/components/MacroEditor/import.ts index 39705dccfcc..0c1cc20f25b 100644 --- a/front/src/applications/operationalStudies/components/MacroEditor/import.ts +++ b/front/src/applications/operationalStudies/components/MacroEditor/import.ts @@ -1,14 +1,22 @@ import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; -import type { SearchResultItemOperationalPoint, SearchPayload } from 'common/api/osrdEditoastApi'; +import type { + SearchResultItemOperationalPoint, + SearchPayload, + TrainScheduleBase, +} from 'common/api/osrdEditoastApi'; import type { AppDispatch } from 'store'; import type { Node, + Port, + Trainrun, + TrainrunSection, TrainrunCategory, TrainrunFrequency, TrainrunTimeCategory, NetzgrafikDto, } from './types'; +import { PortAlignment } from './types'; // TODO: make this optional in NGE since it's SBB-specific const TRAINRUN_CATEGORY_HALTEZEITEN = { @@ -100,6 +108,24 @@ const convertGeoCoords = (nodes: Node[]) => { }); }; +const findOp = ( + pathItem: TrainScheduleBase['path'], + searchResults: SearchResultItemOperationalPoint[] +) => { + return searchResults.find((searchResult) => { + if ('uic' in pathItem) { + return searchResult.uic === pathItem.uic; + } + if ('trigram' in pathItem) { + return searchResult.trigram === pathItem.trigram; + } + if ('operational_point' in pathItem) { + return searchResult.obj_id === pathItem.operational_point; + } + return false; + }); +}; + const importTimetable = async ( infraId: number, timetableId: number, @@ -153,7 +179,7 @@ const importTimetable = async ( ], }; - const searchResults = []; + const searchResults: SearchResultItemOperationalPoint[] = []; const pageSize = 100; let done = false; for (let page = 1; !done; page += 1) { @@ -165,7 +191,7 @@ const importTimetable = async ( }) ); // eslint-disable-next-line no-await-in-loop - const results = await searchPromise.unwrap(); + const results = (await searchPromise.unwrap()) as SearchResultItemOperationalPoint[]; searchResults.push(...results); done = results.length < pageSize; } @@ -175,8 +201,7 @@ const importTimetable = async ( capacity: trainSchedules.length, }; - let nodes: Node[] = searchResults.map((searchResult) => { - const op = searchResult as SearchResultItemOperationalPoint; + let nodes: Node[] = searchResults.map((op) => { return { id: op.obj_id, betriebspunktName: op.trigram, @@ -197,6 +222,75 @@ const importTimetable = async ( }); nodes = convertGeoCoords(nodes); + const trainruns: Trainrun[] = trainSchedules.map((trainSchedule) => ({ + id: trainSchedule.id, + name: trainSchedule.train_name, + categoryId: DEFAULT_TRAINRUN_CATEGORY.id, + frequencyId: DEFAULT_TRAINRUN_FREQUENCY.id, + trainrunTimeCategoryId: DEFAULT_TRAINRUN_TIME_CATEGORY.id, + labelIds: [], + })); + + const ports: Port[] = []; + let portId = 0; + const createPort = (trainrunSectionId: number) => { + const port = { + id: portId, + trainrunSectionId, + positionIndex: 0, + positionAlignment: PortAlignment.Top, + }; + portId += 1; + ports.push(port); + return port; + }; + + let trainrunSectionId = 0; + const trainrunSections: TrainrunSection[] = trainSchedules + .map((trainSchedule) => { + const ops = trainSchedule.path.map((pathItem) => findOp(pathItem, searchResults)); + const foundAllOps = ops.every((op) => op); + if (!foundAllOps) { + return []; + } + return trainSchedule.path.slice(0, -1).map((sourcePathItem, i) => { + const timeLockStub = { + time: 0, + consecutiveTime: null, + lock: false, + warning: null, + timeFormatter: null, + }; + + const sourcePort = createPort(trainrunSectionId); + const targetPort = createPort(trainrunSectionId); + + const trainrunSection = { + id: trainrunSectionId, + sourceNodeId: ops[i]!.obj_id, + sourcePortId: sourcePort.id, + targetNodeId: ops[i + 1]!.obj_id, + targetPortId: targetPort.id, + travelTime: timeLockStub, + sourceDeparture: timeLockStub, + sourceArrival: timeLockStub, + targetDeparture: timeLockStub, + targetArrival: timeLockStub, + numberOfStops: 0, + trainrunId: trainSchedule.id, + resourceId: resource.id, + path: { + path: [], + textPositions: [], + }, + }; + trainrunSectionId += 1; + + return trainrunSection; + }); + }) + .flat(); + return { ...EMPTY_DTO, resources: [resource], @@ -207,6 +301,8 @@ const importTimetable = async ( trainrunTimeCategories: [DEFAULT_TRAINRUN_TIME_CATEGORY], }, nodes, + trainruns, + trainrunSections, }; }; diff --git a/front/src/applications/operationalStudies/components/MacroEditor/types.ts b/front/src/applications/operationalStudies/components/MacroEditor/types.ts index 94c9959f9bf..8e63f292c6b 100644 --- a/front/src/applications/operationalStudies/components/MacroEditor/types.ts +++ b/front/src/applications/operationalStudies/components/MacroEditor/types.ts @@ -27,6 +27,20 @@ export type Node = { labelIds: number[]; }; +export type Port = { + id: number; + positionIndex: number; + positionAlignment: PortAlignment; + trainrunSectionId: number; +}; + +export enum PortAlignment { + Top, + Bottom, + Left, + Right, +}; + export type Trainrun = { id: number; name: string; @@ -38,7 +52,7 @@ export type Trainrun = { export type TimeLock = { time: number; - consecutiveTime: number; + consecutiveTime: number | null; lock: boolean; warning: null; timeFormatter: null; @@ -51,11 +65,11 @@ export type TrainrunSection = { targetNodeId: number; targetPortId: number; - sourceArrival: TimeLock; + travelTime: TimeLock; sourceDeparture: TimeLock; - targetArrival: TimeLock; + sourceArrival: TimeLock; targetDeparture: TimeLock; - travelTime: TimeLock; + targetArrival: TimeLock; numberOfStops: number; @@ -63,7 +77,10 @@ export type TrainrunSection = { resourceId: number; specificTrainrunSectionFrequencyId: number; - path: null; + path: { + path: unknown[]; + textPositions: unknown[]; + }; warnings: unknown[]; };