Skip to content

Commit

Permalink
front: update train after drag in spacetimechart
Browse files Browse the repository at this point in the history
Signed-off-by: Math_R_ <[email protected]>

front: implement new function to update departureTime after train drag

Signed-off-by: Clara Ni <[email protected]>

front: fix order to prevent hook to trigger an error

Signed-off-by: Math_R_ <[email protected]>

front: use a new props to pass the selectedTrain update dispatch

- the component keeps the logic to know which element is clicked and what action should be performed

Signed-off-by: Math_R_ <[email protected]>

front: add a new util function to determine the style of an hovered path

Signed-off-by: Math_R_ <[email protected]>
  • Loading branch information
Math-R authored and SharglutDev committed Jan 16, 2025
1 parent d8a1715 commit d7e5438
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import useScenarioData from 'applications/operationalStudies/hooks/useScenarioDa
import ImportTrainSchedule from 'applications/operationalStudies/views/ImportTrainSchedule';
import ManageTrainSchedule from 'applications/operationalStudies/views/ManageTrainSchedule';
import SimulationResults from 'applications/operationalStudies/views/SimulationResults';
import {
osrdEditoastApi,
type InfraWithState,
type ScenarioResponse,
type TimetableDetailedResult,
type TrainScheduleResult,
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import type {
InfraWithState,
ScenarioResponse,
TimetableDetailedResult,
TrainScheduleResult,
} from 'common/api/osrdEditoastApi';
import ScenarioLoaderMessage from 'modules/scenario/components/ScenarioLoaderMessage';
import TimetableManageTrainSchedule from 'modules/trainschedule/components/ManageTrainSchedule/TimetableManageTrainSchedule';
Expand Down Expand Up @@ -56,14 +56,13 @@ const ScenarioContent = ({
const [trainIdToEdit, setTrainIdToEdit] = useState<number>();
const [isMacro, setIsMacro] = useState(false);
const {
selectedTrainId,
selectedTrainSummary,
trainScheduleSummaries,
trainSchedules,
projectionData,
conflicts,
upsertTrainSchedules,
removeTrains,
updateTrainDepartureTime,
} = useScenarioData(scenario, timetable, infra);
const macroEditorState = useRef<MacroEditorState>();
const [ngeDto, setNgeDto] = useState<NetzgrafikDto>();
Expand Down Expand Up @@ -161,7 +160,6 @@ const ScenarioContent = ({
<Timetable
setDisplayTrainScheduleManagement={setDisplayTrainScheduleManagement}
infraState={infra.state}
selectedTrainId={selectedTrainId}
conflicts={conflicts}
upsertTrainSchedules={upsertTrainSchedules}
removeTrains={removeTrains}
Expand Down Expand Up @@ -230,7 +228,8 @@ const ScenarioContent = ({
projectionData={projectionData}
infraId={infra.id}
conflicts={conflicts}
selectedTrainSummary={selectedTrainSummary}
trainScheduleSummaries={trainScheduleSummaries}
updateTrainDepartureTime={updateTrainDepartureTime}
/>
)
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const formatTrainScheduleSummaries = (

const trainScheduleWithDetails = relevantTrainSchedules.map((trainSchedule) => {
const rollingStock = rollingStocks.find((rs) => rs.name === trainSchedule.rolling_stock_name);

const trainSummary = rawSummaries[trainSchedule.id];

if (!trainSummary) return null;
Expand Down
203 changes: 136 additions & 67 deletions front/src/applications/operationalStudies/hooks/useScenarioData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,33 @@ import {
type TimetableDetailedResult,
type TrainScheduleResult,
} from 'common/api/osrdEditoastApi';
import { setFailure } from 'reducers/main';
import {
getSelectedTrainId,
getTrainIdUsedForProjection,
} from 'reducers/simulationResults/selectors';
import { useAppDispatch } from 'store';
import { castErrorToFailure } from 'utils/error';
import { useOsrdConfSelectors } from 'common/osrdContext';
import { getTrainIdUsedForProjection } from 'reducers/simulationResults/selectors';
import { mapBy } from 'utils/types';

import useAutoUpdateProjection from './useAutoUpdateProjection';
import useLazyLoadTrains from './useLazyLoadTrains';
import usePathProjection from './usePathProjection';
import formatTrainScheduleSummaries from '../helpers/formatTrainScheduleSummaries';

const useScenarioData = (
scenario: ScenarioResponse,
timetable: TimetableDetailedResult,
infra: InfraWithState
) => {
const dispatch = useAppDispatch();
const { getElectricalProfileSetId } = useOsrdConfSelectors();
const electricalProfileSetId = useSelector(getElectricalProfileSetId);
const trainIdUsedForProjection = useSelector(getTrainIdUsedForProjection);
const selectedTrainId = useSelector(getSelectedTrainId);

const [trainSchedules, setTrainSchedules] = useState<TrainScheduleResult[]>();
const [trainIdsToFetch, setTrainIdsToFetch] = useState<number[]>();

const { data: rawTrainSchedules, error: fetchTrainSchedulesError } =
osrdEditoastApi.endpoints.postTrainSchedule.useQuery({
body: {
ids: timetable.train_ids,
},
});
const [fetchTrainSchedules] = osrdEditoastApi.endpoints.postTrainSchedule.useLazyQuery();
const [putTrainScheduleById] = osrdEditoastApi.endpoints.putTrainScheduleById.useMutation();
const [postTrainScheduleSimulationSummary] =
osrdEditoastApi.endpoints.postTrainScheduleSimulationSummary.useLazyQuery();
const { data: { results: rollingStocks } = { results: null } } =
osrdEditoastApi.endpoints.getLightRollingStock.useQuery({ pageSize: 1000 });

const projectionPath = usePathProjection(infra);

Expand All @@ -59,15 +55,16 @@ const useScenarioData = (
trainSchedules,
});

const { data: conflicts } = osrdEditoastApi.endpoints.getTimetableByIdConflicts.useQuery(
{
id: scenario.timetable_id,
infraId: scenario.infra_id,
},
{
skip: !allTrainsLoaded,
}
);
const { data: conflicts, refetch: refetchConflicts } =
osrdEditoastApi.endpoints.getTimetableByIdConflicts.useQuery(
{
id: scenario.timetable_id,
infraId: scenario.infra_id,
},
{
skip: !allTrainsLoaded,
}
);

const trainScheduleSummaries = useMemo(
() => sortBy(Array.from(trainScheduleSummariesById.values()), 'startTime'),
Expand All @@ -87,13 +84,18 @@ const useScenarioData = (
useAutoUpdateProjection(infra, timetable.train_ids, trainScheduleSummaries);

useEffect(() => {
if (!rawTrainSchedules) {
setTrainSchedules(undefined);
} else {
const fetchTrains = async () => {
const rawTrainSchedules = await fetchTrainSchedules({
body: {
ids: timetable.train_ids,
},
}).unwrap();
const sortedTrainSchedules = sortBy(rawTrainSchedules, 'start_time');
setTrainSchedules(sortedTrainSchedules);
}
}, [rawTrainSchedules]);
};

fetchTrains();
}, []);

// first load of the trainScheduleSummaries
useEffect(() => {
Expand All @@ -103,23 +105,8 @@ const useScenarioData = (
}
}, [trainSchedules, infra.state]);

useEffect(() => {
if (fetchTrainSchedulesError) {
dispatch(setFailure(castErrorToFailure(fetchTrainSchedulesError)));
}
}, [fetchTrainSchedulesError]);

const upsertTrainSchedules = useCallback(
(trainSchedulesToUpsert: TrainScheduleResult[]) => {
setTrainSchedules((prev) => {
const newTrainSchedulesById = {
...keyBy(prev, 'id'),
...keyBy(trainSchedulesToUpsert, 'id'),
};
const newTrainSchedules = sortBy(Object.values(newTrainSchedulesById), 'start_time');
return newTrainSchedules;
});

setProjectedTrainsById((prev) => {
const newProjectedTrainsById = new Map(prev);
trainSchedulesToUpsert.forEach((trainSchedule) => {
Expand All @@ -128,6 +115,14 @@ const useScenarioData = (
return newProjectedTrainsById;
});

setTrainSchedules((prev) => {
const newTrainSchedulesById = {
...keyBy(prev, 'id'),
...keyBy(trainSchedulesToUpsert, 'id'),
};
return sortBy(Object.values(newTrainSchedulesById), 'start_time');
});

const sortedTrainSchedulesToUpsert = sortBy(trainSchedulesToUpsert, 'start_time');
setTrainIdsToFetch(sortedTrainSchedulesToUpsert.map((trainSchedule) => trainSchedule.id));
},
Expand Down Expand Up @@ -160,29 +155,103 @@ const useScenarioData = (
});
}, []);

return {
selectedTrainId,
selectedTrainSummary: selectedTrainId
? trainScheduleSummariesById.get(selectedTrainId)
: undefined,
trainScheduleSummaries,
trainSchedules,
projectionData:
trainScheduleUsedForProjection && projectionPath
? {
trainSchedule: trainScheduleUsedForProjection,
...projectionPath,
projectedTrains,
projectionLoaderData: {
allTrainsProjected,
totalTrains: timetable.train_ids.length,
},
}
: undefined,
conflicts,
removeTrains,
upsertTrainSchedules,
};
/** Update only depature time of a train */
const updateTrainDepartureTime = useCallback(
async (trainId: number, newDeparture: Date) => {
const trainSchedule = trainSchedules?.find((train) => train.id === trainId);

if (!trainSchedule) {
throw new Error('Train non trouvé');
}

const trainScheduleResult = await putTrainScheduleById({
id: trainId,
trainScheduleForm: {
...trainSchedule,
start_time: newDeparture.toISOString(),
},
}).unwrap();

setProjectedTrainsById((prev) => {
const newProjectedTrainsById = new Map(prev);
newProjectedTrainsById.set(trainScheduleResult.id, {
...newProjectedTrainsById.get(trainScheduleResult.id)!,
departureTime: newDeparture,
});
return newProjectedTrainsById;
});

setTrainSchedules((prev) => {
const newTrainSchedulesById = {
...keyBy(prev, 'id'),
...keyBy([trainScheduleResult], 'id'),
};
return sortBy(Object.values(newTrainSchedulesById), 'start_time');
});

// update its summary
const rawSummaries = await postTrainScheduleSimulationSummary({
body: {
infra_id: scenario.infra_id,
ids: [trainId],
electrical_profile_set_id: electricalProfileSetId,
},
}).unwrap();
const summaries = formatTrainScheduleSummaries(
[trainId],
rawSummaries,
mapBy([trainScheduleResult], 'id'),
rollingStocks!
);
setTrainScheduleSummariesById((prev) => {
const newTrainScheduleSummariesById = new Map(prev);
newTrainScheduleSummariesById.set(trainId, summaries.get(trainId)!);
return newTrainScheduleSummariesById;
});

// fetch conflicts
refetchConflicts();
},
[trainSchedules, rollingStocks]
);

const results = useMemo(
() => ({
trainScheduleSummaries,
trainSchedules,
projectionData:
trainScheduleUsedForProjection && projectionPath
? {
trainSchedule: trainScheduleUsedForProjection,
...projectionPath,
projectedTrains,
projectionLoaderData: {
allTrainsProjected,
totalTrains: timetable.train_ids.length,
},
}
: undefined,
conflicts,
removeTrains,
upsertTrainSchedules,
updateTrainDepartureTime,
}),
[
trainScheduleSummaries,
trainSchedules,
trainScheduleUsedForProjection,
projectionPath,
projectedTrains,
allTrainsProjected,
timetable.train_ids.length,
conflicts,
removeTrains,
upsertTrainSchedules,
updateTrainDepartureTime,
]
);

return results;
};

export default useScenarioData;
Loading

0 comments on commit d7e5438

Please sign in to comment.