Skip to content

Commit cdcda49

Browse files
theocrsbWadjetz
authored andcommitted
front: create exception when train is duplicate
Signed-off-by: theocrsb <theo_crosbie@yahoo.fr>
1 parent c490352 commit cdcda49

File tree

10 files changed

+142
-34
lines changed

10 files changed

+142
-34
lines changed

front/src/applications/operationalStudies/views/Scenario/components/ManageTimetableItem/CreateTimetableItemButton.tsx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,42 @@ const CreateTimetableItemButton = ({
6363
await createPacedTrains(dispatch, sandboxId, [newTrainSchedulePayload])
6464
)[0];
6565

66+
let timetableItemToUpsert = formattedNewTrainSchedule;
67+
6668
if (updatedExceptions.length > 0) {
67-
await createExceptions(
69+
const newExceptions = await createExceptions(
6870
dispatch,
6971
updatedExceptions,
7072
formattedNewTrainSchedule.id,
7173
timetableId
7274
);
75+
76+
// TODO : remove this part when the back will be done inserting the new exception format in TrainSchedule
77+
const formattedExceptions = newExceptions.map((exceptionNewModel) => {
78+
const {
79+
change_groups,
80+
train_schedule_id: _train_schedule_id,
81+
timetable_id: _timetable_id,
82+
...restExceptions
83+
} = exceptionNewModel;
84+
return {
85+
...change_groups,
86+
...restExceptions,
87+
// TODO: drop this when drop key in the model
88+
key: restExceptions.key ?? restExceptions.id.toString(),
89+
};
90+
});
91+
92+
// Add the new exceptions to the timetable item so they contain their new exception ids
93+
timetableItemToUpsert = {
94+
...formattedNewTrainSchedule,
95+
...(formattedNewTrainSchedule.paced && {
96+
paced: {
97+
...formattedNewTrainSchedule.paced,
98+
exceptions: formattedExceptions,
99+
},
100+
}),
101+
};
73102
}
74103

75104
dispatch(
@@ -81,7 +110,7 @@ const CreateTimetableItemButton = ({
81110
if (simulationConf.editingItemType === 'pacedTrain') {
82111
dispatch(clearAddedExceptionsList());
83112
}
84-
upsertTimetableItems([formattedNewTrainSchedule]);
113+
upsertTimetableItems([timetableItemToUpsert]);
85114
} catch (e) {
86115
dispatch(setFailure(castErrorToFailure(e)));
87116
} finally {

front/src/applications/operationalStudies/views/Scenario/components/ManageTimetableItem/helpers/__tests__/formatTimetableItemPayload.spec.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,11 @@ describe('formatTimetableItemPayload', () => {
200200
...rawOsrdconf,
201201
...userChanges,
202202
};
203-
const result = formatPacedTrainPayload(osrdconfWithUserChanges, rollingStockName);
204-
expect(result).toEqual({
203+
const { newTrainSchedulePayload } = formatPacedTrainPayload(
204+
osrdconfWithUserChanges,
205+
rollingStockName
206+
);
207+
expect(newTrainSchedulePayload).toEqual({
205208
category: {
206209
main_category: 'FREIGHT_TRAIN',
207210
},
@@ -299,12 +302,12 @@ describe('formatTimetableItemPayload', () => {
299302
},
300303
},
301304
};
302-
const result = formatPacedTrainPayload(
305+
const { newTrainSchedulePayload } = formatPacedTrainPayload(
303306
osrdconfWithUserChanges,
304307
rollingStockName,
305308
itemDataWithPREVIOUSLYAddedException
306309
);
307-
expect(result).toEqual({
310+
expect(newTrainSchedulePayload).toEqual({
308311
category: {
309312
main_category: 'FREIGHT_TRAIN',
310313
},

front/src/applications/operationalStudies/views/Scenario/components/ManageTimetableItem/helpers/formatTimetableItemPayload.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export function formatPacedTrainPayload(
133133
paced: {
134134
time_window: osrdconf.timeWindow.toISOString(),
135135
interval: osrdconf.interval.toISOString(),
136+
// TODO: remove exceptions when the migration is done
136137
exceptions,
137138
},
138139
};
@@ -180,6 +181,7 @@ export function formatPacedTrainPayload(
180181
// with only its exceptions updated
181182
newPacedTrain = {
182183
...originalPacedTrain,
184+
// TODO: remove exceptions when the migration is done
183185
paced: { ...originalPacedTrain.paced, exceptions: updatedExceptions },
184186
};
185187
// ========== user modified the whole paced train ==========
@@ -204,6 +206,7 @@ export function formatPacedTrainPayload(
204206

205207
newPacedTrain = {
206208
...newPacedTrain,
209+
// TODO: remove exceptions when the migration is done
207210
paced: { ...newPacedTrain.paced, exceptions: newExceptionList },
208211
};
209212
}

front/src/applications/operationalStudies/views/Scenario/components/Timetable/CalendarTrainList.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const CalendarTrainList = ({
6060
}: CalendarTrainListProps) => {
6161
const dateTimeLocale = useDateTimeLocale();
6262

63-
const { workerStatus } = useScenarioContext();
63+
const { workerStatus, timetableId } = useScenarioContext();
6464
const subCategories = useSubCategoryContext();
6565

6666
const [expandedTimetableItemIds, setExpandedTimetableItemIds] = useState<Set<TimetableItemId>>(
@@ -183,6 +183,7 @@ const CalendarTrainList = ({
183183
isSelectMode={isSelectMode}
184184
moveTimetableItem={() => moveTimetableItem?.([timetableItem.id])}
185185
showMovebutton={timetableMode === 'trainScheduleSet'}
186+
timetableId={timetableId}
186187
/>
187188
)}
188189
</div>

front/src/applications/operationalStudies/views/Scenario/components/Timetable/PacedTrain/OccurrenceIndicator.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ const OccurrenceIndicator = ({ occurrence, subCategories }: OccurrenceIndicatorP
4242

4343
const categoryValue = occurrence.category;
4444

45+
const exceptionChangeGroups = occurrence.exception?.exceptionChangeGroups;
46+
4547
const displayedChangeGroups =
46-
occurrence.exceptionChangeGroups &&
47-
Object.entries(occurrence.exceptionChangeGroups)
48+
exceptionChangeGroups &&
49+
Object.entries(exceptionChangeGroups)
4850
.filter(([_, isPresent]) => isPresent !== null)
4951
.map(([changeGroup]) => changeGroup as keyof ExceptionChangeGroups)
5052
.map((changeGroup) => {
@@ -95,7 +97,7 @@ const OccurrenceIndicator = ({ occurrence, subCategories }: OccurrenceIndicatorP
9597
setIsHovering(false);
9698
}}
9799
>
98-
{isHovering && (occurrence.disabled || !isEmpty(occurrence.exceptionChangeGroups)) && (
100+
{isHovering && (occurrence.disabled || !isEmpty(exceptionChangeGroups)) && (
99101
<OSRDTooltip
100102
containerRef={dotRef}
101103
header={tooltipHeader()}
@@ -105,7 +107,7 @@ const OccurrenceIndicator = ({ occurrence, subCategories }: OccurrenceIndicatorP
105107
)}
106108
<span
107109
className={cx('icon', getTrainCategoryClassName(occurrence.category, 'bg'), {
108-
exception: !isEmpty(occurrence.exceptionChangeGroups),
110+
exception: !isEmpty(exceptionChangeGroups),
109111
disabled: occurrence.disabled,
110112
})}
111113
style={{

front/src/applications/operationalStudies/views/Scenario/components/Timetable/PacedTrain/OccurrenceItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ const OccurrenceItem = ({
9393

9494
const trainIdUsedForProjection = useSelector(getTrainIdUsedForProjection);
9595

96-
const { trainName, rollingStock, startTime, disabled, exceptionChangeGroups, summary } =
97-
occurrence;
96+
const { trainName, rollingStock, startTime, disabled, exception, summary } = occurrence;
97+
const exceptionChangeGroups = exception?.exceptionChangeGroups;
9898

9999
let arrivalTime: Date | undefined;
100100
let isAfterMidnight = false;

front/src/applications/operationalStudies/views/Scenario/components/Timetable/PacedTrain/PacedTrainItem.tsx

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { useRollingStockContext } from 'common/RollingStockContext';
2323
import isMainCategory from 'modules/rollingStock/helpers/category';
2424
import { getOccurrencesWorstStatus } from 'modules/timetableItem/helpers/pacedTrain';
2525
import {
26+
createExceptions,
2627
createPacedTrains,
2728
deleteTrainSchedules,
2829
storePacedTrain,
@@ -82,6 +83,7 @@ type PacedTrainItemProps = {
8283
isSelectMode: boolean;
8384
moveTimetableItem: () => void;
8485
showMovebutton: boolean;
86+
timetableId: number;
8587
};
8688

8789
const PacedTrainItem = ({
@@ -102,6 +104,7 @@ const PacedTrainItem = ({
102104
isSelectMode,
103105
moveTimetableItem,
104106
showMovebutton,
107+
timetableId,
105108
}: PacedTrainItemProps) => {
106109
const { editedElementContainer } = useContext(EditedElementContainerContext);
107110
const { t } = useTranslation('operational-studies', { keyPrefix: 'main' });
@@ -220,10 +223,54 @@ const PacedTrainItem = ({
220223
train_name: pacedTrainName,
221224
};
222225

226+
// We don't want to send summary to create exceptions
227+
const payloadExceptions = pacedTrain.paced?.exceptions.map((exception) => {
228+
const { summary: _summary, ...changeGroups } = exception;
229+
return changeGroups;
230+
});
231+
223232
const formattedPacedTrainResponse: TimetableItem = (
224233
await createPacedTrains(dispatch, pacedTrainDetail.train_schedule_set_id, [newPacedTrain])
225234
)[0];
226-
upsertTimetableItems([formattedPacedTrainResponse]);
235+
236+
const newExceptions =
237+
payloadExceptions.length > 0
238+
? await createExceptions(
239+
dispatch,
240+
payloadExceptions,
241+
formattedPacedTrainResponse.id,
242+
timetableId
243+
)
244+
: [];
245+
246+
// TODO : remove this part when the back will be done inserting the new exception format in TrainSchedule
247+
const formattedExceptions = newExceptions.map((exceptionNewModel) => {
248+
const {
249+
change_groups,
250+
train_schedule_id: _train_schedule_id,
251+
timetable_id: _timetable_id,
252+
...restExceptions
253+
} = exceptionNewModel;
254+
return {
255+
...change_groups,
256+
...restExceptions,
257+
// TODO: drop this when drop key in the model
258+
key: restExceptions.key ?? restExceptions.id.toString(),
259+
};
260+
});
261+
262+
// We add the new exceptions to the duplicate paced train, so they contain their new exception ids
263+
upsertTimetableItems([
264+
{
265+
...formattedPacedTrainResponse,
266+
...(formattedPacedTrainResponse.paced && {
267+
paced: {
268+
...formattedPacedTrainResponse.paced,
269+
exceptions: formattedExceptions,
270+
},
271+
}),
272+
},
273+
]);
227274
dispatch(
228275
setSuccess({
229276
title: t('timetable.pacedTrainAdded'),

front/src/applications/operationalStudies/views/Scenario/components/Timetable/PacedTrain/hooks/useOccurrences.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,20 @@ const useOccurrences = (
6666
? correspondingException.rolling_stock_category.value
6767
: pacedTrainCategory,
6868
occurrenceIndex: i,
69-
exceptionChangeGroups: correspondingException
70-
? omit(correspondingException, ['key', 'occurrence_index', 'disabled', 'id', 'summary'])
71-
: undefined,
69+
exception:
70+
correspondingException && correspondingException.id
71+
? {
72+
id: correspondingException.id,
73+
exceptionChangeGroups: omit(correspondingException, [
74+
'key',
75+
'occurrence_index',
76+
'disabled',
77+
'summary',
78+
'id',
79+
]),
80+
}
81+
: undefined,
82+
7283
summary: correspondingException?.summary ?? summary,
7384
});
7485
}
@@ -98,13 +109,20 @@ const useOccurrences = (
98109
category: exception.rolling_stock_category
99110
? exception.rolling_stock_category.value
100111
: pacedTrainCategory,
101-
exceptionChangeGroups: omit(exception, [
102-
'key',
103-
'disabled',
104-
'occurrence_index',
105-
'id',
106-
'summary',
107-
]),
112+
113+
exception: exception.id
114+
? {
115+
id: exception.id,
116+
exceptionChangeGroups: omit(exception, [
117+
'key',
118+
'disabled',
119+
'occurrence_index',
120+
'summary',
121+
'id',
122+
]),
123+
}
124+
: undefined,
125+
108126
summary: exception.summary ?? summary,
109127
});
110128
});

front/src/modules/timetableItem/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export type Occurrence = {
125125
rollingStock?: LightRollingStockWithLiveries;
126126
startTime: Date;
127127
stopsCount: number;
128-
exceptionChangeGroups?: ExceptionChangeGroups;
128+
exception?: { id: number; exceptionChangeGroups: ExceptionChangeGroups };
129129
summary?: SimulationSummary;
130130
};
131131

front/src/utils/trainId.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export const isTrainId = (id: string): id is TrainId => isOccurrenceId(id) || is
3030
* - An added exception that has been modified is still considered as an added exception.
3131
*/
3232
export const getExceptionType = (occurrence: Occurrence): 'added' | 'modified' | null => {
33-
const { id, exceptionChangeGroups } = occurrence;
33+
const { id, exception } = occurrence;
34+
const exceptionChangeGroups = exception && exception.exceptionChangeGroups;
3435
if (isAddedExceptionId(id)) {
3536
return 'added';
3637
}
@@ -45,14 +46,18 @@ export const isException = (occurrence: Occurrence) => !!getExceptionType(occurr
4546
/**
4647
* Checks if an exception is related to the path or simulation.
4748
*/
48-
export const isExceptionFromPathOrSimulation = ({ exceptionChangeGroups }: Occurrence) =>
49-
exceptionChangeGroups &&
50-
(exceptionChangeGroups.path_and_schedule ||
51-
exceptionChangeGroups.options ||
52-
exceptionChangeGroups.constraint_distribution ||
53-
exceptionChangeGroups.speed_limit_tag ||
54-
exceptionChangeGroups.initial_speed ||
55-
exceptionChangeGroups.rolling_stock);
49+
export const isExceptionFromPathOrSimulation = ({ exception }: Occurrence) => {
50+
const exceptionChangeGroups = exception?.exceptionChangeGroups;
51+
return (
52+
exceptionChangeGroups &&
53+
(exceptionChangeGroups.path_and_schedule ||
54+
exceptionChangeGroups.options ||
55+
exceptionChangeGroups.constraint_distribution ||
56+
exceptionChangeGroups.speed_limit_tag ||
57+
exceptionChangeGroups.initial_speed ||
58+
exceptionChangeGroups.rolling_stock)
59+
);
60+
};
5661

5762
/**
5863
* Given a train id in the Editoast format (used for api),

0 commit comments

Comments
 (0)