Skip to content

Commit

Permalink
front: add scenario content context with cached tracks and infraid
Browse files Browse the repository at this point in the history
Signed-off-by: Alice Khoudli <alice.khoudli@polytechnique.org>
  • Loading branch information
Synar committed Nov 22, 2024
1 parent 84b140f commit 23c2391
Show file tree
Hide file tree
Showing 14 changed files with 292 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import MicroMacroSwitch from 'applications/operationalStudies/components/MicroMa
import NGE from 'applications/operationalStudies/components/NGE/NGE';
import type { NetzgrafikDto, NGEEvent } from 'applications/operationalStudies/components/NGE/types';
import { MANAGE_TRAIN_SCHEDULE_TYPES } from 'applications/operationalStudies/consts';
import { ScenarioContextProvider } from 'applications/operationalStudies/hooks/useScenarioContext';
import useScenarioData from 'applications/operationalStudies/hooks/useScenarioData';
import ImportTrainSchedule from 'applications/operationalStudies/views/ImportTrainSchedule';
import ManageTrainSchedule from 'applications/operationalStudies/views/ManageTrainSchedule';
Expand Down Expand Up @@ -120,123 +121,125 @@ const ScenarioContent = ({
});

return (
<main className="mastcontainer mastcontainer-no-mastnav">
<div className="scenario">
<div className="row scenario-container">
<div
data-testid="scenario-sidemenu"
className={`scenario-sidemenu ${collapsedTimetable ? 'd-none' : 'col-hdp-3 col-xl-4 col-lg-5 col-md-6'}`}
>
<div className="scenario-sidemenu">
<ScenarioDescription
scenario={scenario}
infra={infra}
infraReloadCount={reloadCount}
collapseTimetable={() => setCollapsedTimetable(true)}
/>
<MicroMacroSwitch isMacro={isMacro} setIsMacro={toggleMicroMacroButton} />
{!isMacro && infra && (
<>
{displayTrainScheduleManagement !== MANAGE_TRAIN_SCHEDULE_TYPES.none && (
<TimetableManageTrainSchedule
displayTrainScheduleManagement={displayTrainScheduleManagement}
<ScenarioContextProvider infraId={infra.id}>
<main className="mastcontainer mastcontainer-no-mastnav">
<div className="scenario">
<div className="row scenario-container">
<div
data-testid="scenario-sidemenu"
className={`scenario-sidemenu ${collapsedTimetable ? 'd-none' : 'col-hdp-3 col-xl-4 col-lg-5 col-md-6'}`}
>
<div className="scenario-sidemenu">
<ScenarioDescription
scenario={scenario}
infra={infra}
infraReloadCount={reloadCount}
collapseTimetable={() => setCollapsedTimetable(true)}
/>
<MicroMacroSwitch isMacro={isMacro} setIsMacro={toggleMicroMacroButton} />
{!isMacro && infra && (
<>
{displayTrainScheduleManagement !== MANAGE_TRAIN_SCHEDULE_TYPES.none && (
<TimetableManageTrainSchedule
displayTrainScheduleManagement={displayTrainScheduleManagement}
setDisplayTrainScheduleManagement={setDisplayTrainScheduleManagement}
upsertTrainSchedules={upsertTrainSchedules}
trainIdToEdit={trainIdToEdit}
setTrainIdToEdit={setTrainIdToEdit}
infraState={infra.state}
/>
)}
<Timetable
setDisplayTrainScheduleManagement={setDisplayTrainScheduleManagement}
infraState={infra.state}
selectedTrainId={selectedTrainId}
conflicts={conflicts}
upsertTrainSchedules={upsertTrainSchedules}
trainIdToEdit={trainIdToEdit}
removeTrains={removeTrains}
setTrainIdToEdit={setTrainIdToEdit}
infraState={infra.state}
trainIdToEdit={trainIdToEdit}
trainSchedules={trainSchedules}
trainSchedulesWithDetails={trainScheduleSummaries}
/>
)}
<Timetable
setDisplayTrainScheduleManagement={setDisplayTrainScheduleManagement}
infraState={infra.state}
selectedTrainId={selectedTrainId}
conflicts={conflicts}
upsertTrainSchedules={upsertTrainSchedules}
removeTrains={removeTrains}
setTrainIdToEdit={setTrainIdToEdit}
trainIdToEdit={trainIdToEdit}
trainSchedules={trainSchedules}
trainSchedulesWithDetails={trainScheduleSummaries}
/>
</>
)}
</>
)}
</div>
</div>
</div>

<div className={collapsedTimetable ? 'col-12' : 'col-hdp-9 col-xl-8 col-lg-7 col-md-6'}>
{!isInfraLoaded &&
!isMacro &&
displayTrainScheduleManagement !== MANAGE_TRAIN_SCHEDULE_TYPES.add &&
displayTrainScheduleManagement !== MANAGE_TRAIN_SCHEDULE_TYPES.edit && (
<ScenarioLoaderMessage infraState={infra?.state} />
)}
{(displayTrainScheduleManagement === MANAGE_TRAIN_SCHEDULE_TYPES.add ||
displayTrainScheduleManagement === MANAGE_TRAIN_SCHEDULE_TYPES.edit) && (
<div className="scenario-managetrainschedule">
<ManageTrainSchedule trainIdToEdit={trainIdToEdit} />
</div>
)}
{displayTrainScheduleManagement === MANAGE_TRAIN_SCHEDULE_TYPES.import && (
<div className="scenario-managetrainschedule">
<ImportTrainSchedule
timetableId={scenario.timetable_id}
upsertTrainSchedules={upsertTrainSchedules}
/>
</div>
)}
<div className="scenario-results">
{collapsedTimetable && (
<>
<div className="scenario-timetable-collapsed">
<button
data-testid="timetable-collapse-button"
className="timetable-collapse-button"
type="button"
aria-label={t('toggleTimetable')}
onClick={() => setCollapsedTimetable(false)}
>
<ChevronRight />
</button>
<div className="lead ml-2">{scenario.name}</div>
<div className="d-flex align-items-center ml-auto">
<img src={infraLogo} alt="Infra logo" className="infra-logo mr-2" />
{scenario.infra_name}
</div>
<div className="d-flex align-items-center ml-4">
<span className="mr-1">
<GiElectric />
</span>
{scenario.electrical_profile_set_id
? scenario.electrical_profile_set_id
: t('noElectricalProfileSet')}
</div>
</div>
<MicroMacroSwitch isMacro={isMacro} setIsMacro={toggleMicroMacroButton} />
</>
)}
{isMacro ? (
<div className={cx(collapsedTimetable ? 'macro-container' : 'h-100')}>
<NGE dto={ngeDto} onOperation={handleNGEOperation} />
<div className={collapsedTimetable ? 'col-12' : 'col-hdp-9 col-xl-8 col-lg-7 col-md-6'}>
{!isInfraLoaded &&
!isMacro &&
displayTrainScheduleManagement !== MANAGE_TRAIN_SCHEDULE_TYPES.add &&
displayTrainScheduleManagement !== MANAGE_TRAIN_SCHEDULE_TYPES.edit && (
<ScenarioLoaderMessage infraState={infra?.state} />
)}
{(displayTrainScheduleManagement === MANAGE_TRAIN_SCHEDULE_TYPES.add ||
displayTrainScheduleManagement === MANAGE_TRAIN_SCHEDULE_TYPES.edit) && (
<div className="scenario-managetrainschedule">
<ManageTrainSchedule trainIdToEdit={trainIdToEdit} />
</div>
) : (
isInfraLoaded &&
infra && (
<SimulationResults
scenarioData={{ name: scenario.name, infraName: scenario.infra_name }}
collapsedTimetable={collapsedTimetable}
projectionData={projectionData}
simulationResults={simulationResults}
infraId={infra.id}
conflicts={conflicts}
)}
{displayTrainScheduleManagement === MANAGE_TRAIN_SCHEDULE_TYPES.import && (
<div className="scenario-managetrainschedule">
<ImportTrainSchedule
timetableId={scenario.timetable_id}
upsertTrainSchedules={upsertTrainSchedules}
/>
)
</div>
)}
<div className="scenario-results">
{collapsedTimetable && (
<>
<div className="scenario-timetable-collapsed">
<button
data-testid="timetable-collapse-button"
className="timetable-collapse-button"
type="button"
aria-label={t('toggleTimetable')}
onClick={() => setCollapsedTimetable(false)}
>
<ChevronRight />
</button>
<div className="lead ml-2">{scenario.name}</div>
<div className="d-flex align-items-center ml-auto">
<img src={infraLogo} alt="Infra logo" className="infra-logo mr-2" />
{scenario.infra_name}
</div>
<div className="d-flex align-items-center ml-4">
<span className="mr-1">
<GiElectric />
</span>
{scenario.electrical_profile_set_id
? scenario.electrical_profile_set_id
: t('noElectricalProfileSet')}
</div>
</div>
<MicroMacroSwitch isMacro={isMacro} setIsMacro={toggleMicroMacroButton} />
</>
)}
{isMacro ? (
<div className={cx(collapsedTimetable ? 'macro-container' : 'h-100')}>
<NGE dto={ngeDto} onOperation={handleNGEOperation} />
</div>
) : (
isInfraLoaded &&
infra && (
<SimulationResults
scenarioData={{ name: scenario.name, infraName: scenario.infra_name }}
collapsedTimetable={collapsedTimetable}
projectionData={projectionData}
simulationResults={simulationResults}
infraId={infra.id}
conflicts={conflicts}
/>
)
)}
</div>
</div>
</div>
</div>
</div>
</main>
</main>
</ScenarioContextProvider>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useRef, useCallback } from 'react';

import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import type { InfraObjectWithGeometry } from 'common/api/osrdEditoastApi';

export default function useCachedTrackSections(infraId: number) {
const trackIdsRef = useRef<Set<string>>(new Set());
const trackSectionsRef = useRef<InfraObjectWithGeometry[]>([]);
const [loadInfraObject, { isLoading }] =
osrdEditoastApi.endpoints.postInfraByInfraIdObjectsAndObjectType.useMutation();

const getTrackSectionsByIds = useCallback(
async (requestedTrackIds: string[]) => {
let fetchedSections: InfraObjectWithGeometry[] = [];
const uniqueNewIds = requestedTrackIds.filter((id) => !trackIdsRef.current.has(id));
if (uniqueNewIds.length !== 0) {
try {
fetchedSections = await loadInfraObject({
infraId,
objectType: 'TrackSection',
body: uniqueNewIds,
}).unwrap();

uniqueNewIds.forEach((id) => trackIdsRef.current.add(id));
trackSectionsRef.current = [...trackSectionsRef.current, ...fetchedSections];
} catch (error) {
console.error('Failed to fetch track sections:', error);
}
}

return trackSectionsRef.current.filter((section) =>
requestedTrackIds.includes(section.obj_id)
);
},
[infraId]
);

return { getTrackSectionsByIds, isLoading };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createContext, useContext, useMemo, type ReactNode } from 'react';

import useCachedTrackSections from 'applications/operationalStudies/hooks/useCachedTrackSections';
import type { InfraObjectWithGeometry } from 'common/api/osrdEditoastApi';

type ScenarioContextType = {
getTrackSectionsByIds: (requestedTrackIds: string[]) => Promise<InfraObjectWithGeometry[]>;
infraId: number;
trackSectionsLoading: boolean;
} | null;
const ScenarioContext = createContext<ScenarioContextType>(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 <ScenarioContext.Provider value={providedContext}>{children}</ScenarioContext.Provider>;
};

export const useScenarioContext = () => {
const context = useContext(ScenarioContext);
if (!context) {
throw new Error('useScenarioContext must be used within a TrackSectionsProvider');
}
return context;
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ import {
type PathfindingResult,
} from 'common/api/osrdEditoastApi';
import { useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext';
import {
formatSuggestedOperationalPointsWithTrackName,
upsertPathStepsInOPs,
} from 'modules/pathfinding/utils';
import { formatSuggestedOperationalPoints, upsertPathStepsInOPs } from 'modules/pathfinding/utils';
import { getSupportedElectrification, isThermal } from 'modules/rollingStock/helpers/electric';
import { adjustConfWithTrainToModify } from 'modules/trainschedule/components/ManageTrainSchedule/helpers/adjustConfWithTrainToModify';
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
Expand All @@ -31,6 +28,7 @@ import { mmToM } from 'utils/physics';
import { ISO8601Duration2sec } from 'utils/timeManipulation';

import type { ManageTrainSchedulePathProperties } from '../types';
import { useScenarioContext } from './useScenarioContext';

type ItineraryForTrainUpdate = {
pathSteps: (PathStep | null)[];
Expand Down Expand Up @@ -125,8 +123,7 @@ const useSetupItineraryForTrainUpdate = (
setPathProperties: (pathProperties: ManageTrainSchedulePathProperties) => void,
trainIdToEdit: number
) => {
const { getInfraID, getUsingElectricalProfiles } = useOsrdConfSelectors();
const infraId = useSelector(getInfraID);
const { getUsingElectricalProfiles } = useOsrdConfSelectors();
const usingElectricalProfiles = useSelector(getUsingElectricalProfiles);
const dispatch = useAppDispatch();
const osrdActions = useOsrdConfActions() as OperationalStudiesConfSliceActions;
Expand All @@ -137,6 +134,7 @@ const useSetupItineraryForTrainUpdate = (
osrdEditoastApi.endpoints.postInfraByInfraIdPathfindingBlocks.useMutation();
const [postPathProperties] =
osrdEditoastApi.endpoints.postInfraByInfraIdPathProperties.useMutation();
const { infraId } = useScenarioContext();

useEffect(() => {
const computeItineraryForTrainUpdate = async (
Expand Down Expand Up @@ -184,14 +182,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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import SimulationSettings from 'modules/trainschedule/components/ManageTrainSche
import TrainSettings from 'modules/trainschedule/components/ManageTrainSchedule/TrainSettings';
import { formatKmValue } from 'utils/strings';

import { useScenarioContext } from '../hooks/useScenarioContext';

type ManageTrainScheduleProps = {
trainIdToEdit?: number;
};
Expand All @@ -50,6 +52,8 @@ const ManageTrainSchedule = ({ trainIdToEdit }: ManageTrainScheduleProps) => {
const { rollingStockId, rollingStockComfort, rollingStock } =
useStoreDataForRollingStockSelector();

const { trackSectionsLoading } = useScenarioContext();

useEffect(() => {
if (pathProperties) {
const allWaypoints = upsertPathStepsInOPs(
Expand Down Expand Up @@ -143,6 +147,7 @@ const ManageTrainSchedule = ({ trainIdToEdit }: ManageTrainScheduleProps) => {
allWaypoints={pathProperties?.allWaypoints}
startTime={startTime}
pathSteps={compact(pathSteps)}
dataIsLoading={trackSectionsLoading}
/>
),
};
Expand Down
Loading

0 comments on commit 23c2391

Please sign in to comment.