Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
anisometropie committed Sep 3, 2024
1 parent c4a0b63 commit 4fef754
Show file tree
Hide file tree
Showing 25 changed files with 803 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { setFailure } from 'reducers/main';
import type { OperationalStudiesConfSliceActions } from 'reducers/osrdconf/operationalStudiesConf';
import type { PathStep } from 'reducers/osrdconf/types';
import { useAppDispatch } from 'store';
import { addDurationToIsoDate } from 'utils/date';
import { castErrorToFailure } from 'utils/error';
import { getPointCoordinates } from 'utils/geometry';
import { mmToM } from 'utils/physics';
Expand Down Expand Up @@ -67,13 +66,13 @@ const computeBasePathSteps = (trainSchedule: TrainScheduleResult) =>
name = step.operational_point;
}

// NOTE: arrival was the time "HH:MM:SS"
// addDurationToIsoDate(trainSchedule.start_time, arrival).substring(11, 19)
return {
...stepWithoutSecondaryCode,
ch: 'secondary_code' in step ? step.secondary_code : undefined,
name,
arrival: arrival
? addDurationToIsoDate(trainSchedule.start_time, arrival).substring(11, 19)
: arrival,
arrival,
stopFor: stopFor ? ISO8601Duration2sec(stopFor).toString() : stopFor,
locked,
onStopSignal,
Expand Down Expand Up @@ -258,7 +257,6 @@ const useSetupItineraryForTrainUpdate = (
dispatch(setFailure(castErrorToFailure(e)));
}
}

adjustConfWithTrainToModifyV2(
trainSchedule,
pathSteps || computeBasePathSteps(trainSchedule),
Expand Down
15 changes: 15 additions & 0 deletions front/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,23 @@ export const DATA_TYPES = {
*/
export type TimeString = string;

/**
* A string with the complete iso format
*
* @example "2024-08-08T10:12:46.209Z"
* @example "2024-08-08T10:12:46Z"
* @example "2024-08-08T10:12:46+02:00"
*/
export type IsoDateTimeString = string;

export type RangedValue = {
begin: number;
end: number;
value: string;
};

/**
* A ISO 8601 duration string
* @example "PT3600S"
*/
export type IsoDurationString = string;
13 changes: 10 additions & 3 deletions front/src/modules/pathfinding/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ export const upsertPathStepsInOPs = (ops: SuggestedOP[], pathSteps: PathStep[]):
return updatedOPs;
};

export const pathStepMatchesOp = (pathStep: PathStep, op: SuggestedOP, withKP = false) =>
export const pathStepMatchesOp = (
pathStep: PathStep,
op: Pick<SuggestedOP, 'uic' | 'ch' | 'kp' | 'name' | 'opId'>,
withKP = false
) =>
('uic' in pathStep &&
'ch' in pathStep &&
pathStep.uic === op.uic &&
Expand All @@ -172,5 +176,8 @@ export const pathStepMatchesOp = (pathStep: PathStep, op: SuggestedOP, withKP =
* @param withKP - If true, we check the kp compatibility instead of the name.
* It is used in the times and stops table to check if an operational point is a via.
*/
export const isVia = (vias: PathStep[], op: SuggestedOP, withKP = false) =>
vias.some((via) => pathStepMatchesOp(via, op, withKP));
export const isVia = (
vias: PathStep[],
op: Pick<SuggestedOP, 'uic' | 'ch' | 'kp' | 'name' | 'opId'>,
withKP = false
) => vias.some((via) => pathStepMatchesOp(via, op, withKP));
21 changes: 21 additions & 0 deletions front/src/modules/timesStops/ReadOnlyTime.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';

import type { CellProps } from 'react-datasheet-grid/dist/types';

import type { TimeExtraDays } from './types';

type ReadOnlyTimeProps = CellProps<TimeExtraDays | null | undefined, string>;

const ReadOnlyTime = ({ rowData }: ReadOnlyTimeProps) => {
const { time, daySinceDeparture, dayDisplayed } = rowData || {};
if (time) {
const fullString =
daySinceDeparture !== undefined && dayDisplayed ? `${time} J+${daySinceDeparture}` : time;
return <div className="read-only-time">{fullString}</div>;
}
return null;
};

ReadOnlyTime.displayName = 'ReadOnlyTime';

export default ReadOnlyTime;
29 changes: 19 additions & 10 deletions front/src/modules/timesStops/TimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import React, { useRef, useState, useEffect } from 'react';

import type { CellProps } from 'react-datasheet-grid/dist/types';

const TimeInput = ({
focus,
rowData,
active,
setRowData,
}: CellProps<string | null | undefined, string>) => {
import type { TimeExtraDays } from './types';

type TimeInputProps = CellProps<TimeExtraDays | null | undefined, string>;

const TimeInput = ({ focus, rowData, active, setRowData }: TimeInputProps) => {
const ref = useRef<HTMLInputElement>(null);
const [tempTimeValue, setTempTimeValue] = useState<string | null | undefined>(rowData);
const [tempTimeValue, setTempTimeValue] = useState<TimeExtraDays | null | undefined>(rowData);

useEffect(() => {
if (active) {
Expand All @@ -26,7 +25,7 @@ const TimeInput = ({
setTempTimeValue(rowData);
}, [rowData]);

return (
const input = (
<input
className="dsg-input"
type="time"
Expand All @@ -37,9 +36,9 @@ const TimeInput = ({
pointerEvents: focus ? 'auto' : 'none',
opacity: rowData || active ? undefined : 0,
}}
value={tempTimeValue ?? ''}
value={tempTimeValue?.time ?? ''}
onChange={(e) => {
setTempTimeValue(e.target.value);
setTempTimeValue((prev) => ({ ...prev, time: e.target.value }));
}}
onBlur={() => {
// To prevent the operational point to be transformed into a via if we leave the cell empty after focusing it
Expand All @@ -49,6 +48,16 @@ const TimeInput = ({
}}
/>
);

if (tempTimeValue?.daySinceDeparture && tempTimeValue.dayDisplayed) {
return (
<div className="time-input-container">
{input}
<span className="extra-text">J+{tempTimeValue.daySinceDeparture}</span>
</div>
);
}
return input;
};

TimeInput.displayName = 'TimeInput';
Expand Down
44 changes: 33 additions & 11 deletions front/src/modules/timesStops/TimesStops.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import { DynamicDataSheetGrid, type DataSheetGridProps } from 'react-datasheet-g
import { useTranslation } from 'react-i18next';

import { useOsrdConfActions } from 'common/osrdContext';
import type { IsoDateTimeString } from 'common/types';
import { isVia } from 'modules/pathfinding/utils';
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
import type { PathStep } from 'reducers/osrdconf/types';
import { useAppDispatch } from 'store';
import { time2sec } from 'utils/timeManipulation';

import { marginRegExValidation } from './consts';
import { formatSuggestedViasToRowVias, transformRowDataOnChange } from './helpers/utils';
import {
formatSuggestedViasToRowVias,
updateRowTimesAndMargin,
updateDaySinceDeparture,
durationSinceStartTime,
} from './helpers/utils';
import { useTimeStopsColumns } from './hooks/useTimeStopsColumns';
import { TableType } from './types';
import type { PathWaypointRow } from './types';
Expand All @@ -22,7 +26,7 @@ export const WITH_KP = true;
type TimesStopsProps = {
allWaypoints?: SuggestedOP[];
pathSteps?: PathStep[];
startTime?: string;
startTime?: IsoDateTimeString;
tableType: TableType;
cellClassName?: DataSheetGridProps['cellClassName'];
stickyRightColumn?: DataSheetGridProps['stickyRightColumn'];
Expand All @@ -42,7 +46,7 @@ const TimesStops = ({
const { t } = useTranslation('timesStops');

const dispatch = useAppDispatch();
const { upsertViaFromSuggestedOP } = useOsrdConfActions();
const { upsertSeveralViasFromSuggestedOP } = useOsrdConfActions();

const [rows, setRows] = useState<PathWaypointRow[]>([]);

Expand All @@ -55,7 +59,7 @@ const TimesStops = ({
startTime,
tableType
);
setRows(suggestedOPs);
setRows(updateDaySinceDeparture(suggestedOPs, startTime, true, true));
}
}, [allWaypoints, pathSteps, startTime]);

Expand All @@ -74,15 +78,33 @@ const TimesStops = ({
className="time-stops-datasheet"
columns={columns}
value={rows}
onChange={(row: PathWaypointRow[], [op]) => {
onChange={(newRows: PathWaypointRow[], [op]) => {
if (!isInputTable) {
return;
}
const newRowData = transformRowDataOnChange(row[op.fromRowIndex], rows[op.fromRowIndex], op, allWaypoints.length);
if (!newRowData.isMarginValid) {
setRows(row);
let updatedRows = [...newRows];
updatedRows[op.fromRowIndex] = updateRowTimesAndMargin(
newRows[op.fromRowIndex],
rows[op.fromRowIndex],
op,
allWaypoints.length
);
updatedRows = updateDaySinceDeparture(updatedRows, startTime!);
if (!updatedRows[op.fromRowIndex].isMarginValid) {
setRows(newRows);
} else {
dispatch(upsertViaFromSuggestedOP(newRowData as SuggestedOP));
const newVias = updatedRows
.filter((row) => row.arrival)
.map((row) => {
const arrival = durationSinceStartTime(startTime, row.arrival);
const departure = durationSinceStartTime(startTime, row.departure);
return {
...row,
arrival,
departure,
};
});
dispatch(upsertSeveralViasFromSuggestedOP(newVias));
}
}}
stickyRightColumn={stickyRightColumn}
Expand Down
2 changes: 0 additions & 2 deletions front/src/modules/timesStops/TimesStopsInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ type TimesStopsInputProps = {
startTime: string;
pathSteps: PathStep[];
};

const TimesStopsinput = ({ allWaypoints, startTime, pathSteps }: TimesStopsInputProps) => {
const dispatch = useAppDispatch();
const { updatePathSteps } = useOsrdConfActions();
Expand Down Expand Up @@ -80,7 +79,6 @@ const TimesStopsinput = ({ allWaypoints, startTime, pathSteps }: TimesStopsInput
});
dispatch(updatePathSteps({ pathSteps: updatedPathSteps }));
};

return (
<TimesStops
allWaypoints={allWaypoints}
Expand Down
6 changes: 3 additions & 3 deletions front/src/modules/timesStops/TimesStopsOutput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const TimesStopsOutput = ({
simulatedTrain,
pathProperties,
operationalPoints,
selectedTrainSchedule,
selectedTrainSchedule, // coming straight from GET /train_schedule
pathSteps,
pathLength,
dataIsLoading,
Expand Down Expand Up @@ -59,8 +59,8 @@ const TimesStopsOutput = ({
tableType={TableType.Output}
cellClassName={({ rowData: rowData_ }) => {
const rowData = rowData_ as PathWaypointRow;
const arrivalScheduleNotRespected = rowData.arrival
? rowData.calculatedArrival !== rowData.arrival
const arrivalScheduleNotRespected = rowData?.arrival?.time
? rowData.calculatedArrival !== rowData.arrival.time
: false;
const negativeDiffMargins = Number(rowData.diffMargins?.split(NO_BREAK_SPACE)[0]) < 0;
return cx({
Expand Down
62 changes: 49 additions & 13 deletions front/src/modules/timesStops/helpers/__tests__/scheduleData.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,56 @@ import { describe, it, expect } from 'vitest';
import { computeScheduleData } from '../scheduleData';

describe('computeScheduleData', () => {
it('should compute simple arrival time in the correct timezone', () => {
const schedule = {
at: 'id325',
arrival: 'PT3600S',
stop_for: 'PT100S',
on_stop_signal: false,
locked: false,
};
const startTime = '2024-05-14T00:00:00Z';
describe('same day', () => {
it('should compute simple arrival time in the correct timezone', () => {
const schedule = {
at: 'id325',
arrival: 'PT3600S',
stop_for: 'PT100S',
on_stop_signal: false,
locked: false,
};
const startTime = '2024-05-14T00:00:00Z';

expect(computeScheduleData(schedule, startTime)).toEqual({
arrival: 3600,
departure: 3700,
stopFor: 100,
expect(computeScheduleData(schedule, startTime)).toEqual({
arrival: 3600,
departure: 3700,
stopFor: 100,
});
});
it('should compute simple arrival time in the correct timezone 2', () => {
const schedule = {
at: 'id325',
arrival: 'PT3600S',
stop_for: 'PT100S',
on_stop_signal: false,
locked: false,
};
const startTime = '2024-05-14T01:00:00Z';

expect(computeScheduleData(schedule, startTime)).toEqual({
arrival: 7200,
departure: 7300,
stopFor: 100,
});
});
});
describe('after midnight', () => {
it('should compute simple arrival time in the correct timezone', () => {
const schedule = {
at: 'id325',
arrival: 'PT3600S',
stop_for: 'PT100S',
on_stop_signal: false,
locked: false,
};
const startTime = '2024-05-14T23:50:00Z';

expect(computeScheduleData(schedule, startTime)).toEqual({
arrival: 3000,
departure: 3100,
stopFor: 100,
});
});
});
});
Loading

0 comments on commit 4fef754

Please sign in to comment.