Skip to content

Commit

Permalink
front: add vias in stdcm simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
SarahBellaha authored and flomonster committed Jul 4, 2024
1 parent 97b41b0 commit 2c70a65
Show file tree
Hide file tree
Showing 32 changed files with 1,075 additions and 556 deletions.
6 changes: 5 additions & 1 deletion front/public/locales/en/stdcm.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"loaderImageLegend": "The TGV Nord line",
"notificationTitle": "Phase 1: from D-7 to D-1 5pm, on the Perrigny-Miramas axis.",
"pathfindingFailed": "No path have been found for these waypoints.",
"pleaseWait": "Please wait…",
"simulation":{
"averageRequestTime": "For your request, the time required is generally 90 seconds.",
Expand All @@ -24,12 +25,15 @@
"stdcmResults": "Results",
"stdcmSimulationReport": "Path simulation report",
"trainPath": {
"addVia": "Add intermediate OP",
"asSoonAsPossible": "As soon as possible",
"ch": "CH",
"ci": "CI",
"date": "Date",
"destination": "Destination",
"origin": "Origin",
"time": "Time"
"stopFor": "Minimum stop time",
"time": "Time",
"vias" : "Intermediate OP"
}
}
6 changes: 5 additions & 1 deletion front/public/locales/fr/stdcm.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"loaderImageLegend": "La ligne TGV Nord",
"notificationTitle": "Phase 1 : de J-7 à J-1 17h, sur l’axe Perrigny—Miramas.",
"pathfindingFailed": "Aucun chemin n'a été trouvé pour ces points de jalonnement.",
"pleaseWait": "Veuillez patientez…",
"simulation":{
"averageRequestTime": "Pour votre demande, le temps nécessaire est généralement de 90 secondes.",
Expand All @@ -24,12 +25,15 @@
"stdcmResults": "Résultats",
"stdcmSimulationReport": "Fiche simulation",
"trainPath": {
"addVia": "Ajouter un PR intermédiaire",
"asSoonAsPossible": "Dès que possible",
"ch": "CH",
"ci": "CI",
"date": "Date",
"destination": "Destination",
"origin": "Origine",
"time": "Heure"
"stopFor": "Temps d'arrêt minimum",
"time": "Heure",
"vias": "PR intermédiaire"
}
}
43 changes: 3 additions & 40 deletions front/src/applications/operationalStudies/views/v2/ScenarioV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import { useModal } from 'common/BootstrapSNCF/ModalSNCF';
import NavBarSNCF from 'common/BootstrapSNCF/NavBarSNCF';
import { useInfraID, useOsrdConfActions, useOsrdConfSelectors } from 'common/osrdContext';
import useInfraStatus from 'modules/pathfinding/hook/useInfraStatus';
import AddAndEditScenarioModal from 'modules/scenario/components/AddOrEditScenarioModal';
import ScenarioLoaderMessage from 'modules/scenario/components/ScenarioLoaderMessage';
import TimetableManageTrainScheduleV2 from 'modules/trainschedule/components/ManageTrainSchedule/TimetableManageTrainScheduleV2';
Expand Down Expand Up @@ -43,14 +44,14 @@ const ScenarioV2 = () => {
);
const [trainsWithDetails, setTrainsWithDetails] = useState(false);
const [collapsedTimetable, setCollapsedTimetable] = useState(false);
const [isInfraLoaded, setIsInfraLoaded] = useState(false);
const [reloadCount, setReloadCount] = useState(1);
const [trainSpaceTimeData, setTrainSpaceTimeData] = useState<TrainSpaceTimeData[]>([]);
const [trainResultsToFetch, setTrainResultsToFetch] = useState<number[]>();
const isUpdating = useSelector((state: RootState) => state.osrdsimulation.isUpdating);

const { openModal } = useModal();

const { infra, isInfraLoaded, reloadCount } = useInfraStatus();

const {
projectId: urlProjectId,
studyId: urlStudyId,
Expand Down Expand Up @@ -99,44 +100,6 @@ const ScenarioV2 = () => {
}
}, [scenario]);

const { data: infra } = osrdEditoastApi.endpoints.getInfraByInfraId.useQuery(
{ infraId: infraId as number },
{
skip: !infraId,
refetchOnMountOrArgChange: true,
pollingInterval: !isInfraLoaded ? 1000 : undefined,
}
);
const [reloadInfra] = osrdEditoastApi.endpoints.postInfraByInfraIdLoad.useMutation();

useEffect(() => {
if (reloadCount <= 5 && infra && infra.state === 'TRANSIENT_ERROR') {
setTimeout(() => {
reloadInfra({ infraId: infraId as number }).unwrap();
setReloadCount((count) => count + 1);
}, 1000);
}
}, [infra, reloadCount]);

useEffect(() => {
if (infra && (infra.state === 'NOT_LOADED' || infra.state === 'DOWNLOADING')) {
setIsInfraLoaded(false);
}

if (
infra &&
(infra.state === 'CACHED' || infra.state === 'ERROR' || infra.state === 'TRANSIENT_ERROR')
) {
setIsInfraLoaded(true);
}
}, [infra]);

useEffect(() => {
if (infraId) {
reloadInfra({ infraId }).unwrap();
}
}, [infraId]);

const { data: timetable } = osrdEditoastApi.endpoints.getV2TimetableById.useQuery(
{ id: timetableId! },
{
Expand Down
10 changes: 2 additions & 8 deletions front/src/applications/stdcm/utils/formatStdcmConfV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export const checkStdcmConf = (
rollingStockId: rollingStockID!,
timetableId: timetableID!,
rollingStockComfort: rollingStockComfortV2,
path: compact(osrdconf.pathSteps).map((step, index) => {
path: compact(osrdconf.pathSteps).map((step) => {
const {
id,
arrival,
Expand All @@ -142,15 +142,9 @@ export const checkStdcmConf = (
} = step;

const secondary_code = 'trigram' in stepLocation || 'uic' in stepLocation ? ch : undefined;
let duration: number;
if (index === osrdconf.pathSteps.length - 1) {
duration = 1;
} else {
duration = sec2ms(ISO8601Duration2sec(stopFor || '')) || 0;
}

return {
duration,
duration: stopFor ? sec2ms(ISO8601Duration2sec(stopFor) || Number(stopFor)) : 0,
location: { ...stepLocation, secondary_code },
};
}),
Expand Down
125 changes: 125 additions & 0 deletions front/src/applications/stdcmV2/components/StdcmConfig.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, { useRef, useEffect } from 'react';

import { Button } from '@osrd-project/ui-core';
import { Alert } from '@osrd-project/ui-icons';
import cx from 'classnames';
import { useTranslation } from 'react-i18next';

import type { ManageTrainSchedulePathProperties } from 'applications/operationalStudies/types';
import { STDCM_REQUEST_STATUS } from 'applications/stdcm/consts';
import useStdcm from 'applications/stdcm/hooks/useStdcm';
import { useOsrdConfActions } from 'common/osrdContext';
import { usePathfindingV2 } from 'modules/pathfinding/hook/usePathfinding';
import { Map } from 'modules/trainschedule/components/ManageTrainSchedule';
import type { StdcmConfSliceActions } from 'reducers/osrdconf/stdcmConf';
import { useAppDispatch } from 'store';

import StdcmConsist from './StdcmConsist';
import StdcmDestination from './StdcmDestination';
import StdcmLoader from './StdcmLoader';
import StdcmOrigin from './StdcmOrigin';
import StdcmVias from './StdcmVias';
import type { StdcmSimulationResult } from '../types';

type StdcmConfigProps = {
currentSimulationInputs: StdcmSimulationResult['input'] | undefined;
pathProperties?: ManageTrainSchedulePathProperties;
setPathProperties: (pathProperties?: ManageTrainSchedulePathProperties) => void;
setCurrentSimulationInputs: React.Dispatch<
React.SetStateAction<StdcmSimulationResult['input'] | undefined>
>;
};

const StdcmConfig = ({
currentSimulationInputs,
pathProperties,
setPathProperties,
setCurrentSimulationInputs,
}: StdcmConfigProps) => {
const { t } = useTranslation('stdcm');
const loaderRef = useRef<HTMLDivElement>(null);

const { launchStdcmRequest, cancelStdcmRequest, currentStdcmRequestStatus } = useStdcm();
const isPending = currentStdcmRequestStatus === STDCM_REQUEST_STATUS.pending;

const dispatch = useAppDispatch();
const { updateGridMarginAfter, updateGridMarginBefore, updateStdcmStandardAllowance } =
useOsrdConfActions() as StdcmConfSliceActions;

const { pathfindingState } = usePathfindingV2(setPathProperties, pathProperties);

useEffect(() => {
if (isPending) {
loaderRef?.current?.scrollIntoView({ behavior: 'smooth' });
}
}, [isPending]);

// TODO: DROP STDCMV1: set those values by default in the store when <StdcmAllowances/> is not used anymore.
useEffect(() => {
dispatch(updateGridMarginAfter(35));
dispatch(updateGridMarginBefore(35));
dispatch(updateStdcmStandardAllowance({ type: 'time_per_distance', value: 4.5 }));
}, []);

return (
<div className="stdcm-v2__body">
<div className="stdcm-v2-simulation-settings">
<div className="stdcm-v2-consist-container">
<StdcmConsist
disabled={isPending}
setCurrentSimulationInputs={setCurrentSimulationInputs}
/>
</div>
<div className="stdcm-v2__separator" />
<div className="stdcm-v2-simulation-itinerary">
{/* //TODO: use them when we implement this feature #403 */}
{/* <StdcmDefaultCard text="Indiquer le sillon antérieur" Icon={<ArrowUp size="lg" />} /> */}
<StdcmOrigin
disabled={isPending}
setCurrentSimulationInputs={setCurrentSimulationInputs}
/>
<StdcmVias disabled={isPending} setCurrentSimulationInputs={setCurrentSimulationInputs} />
<StdcmDestination
disabled={isPending}
setCurrentSimulationInputs={setCurrentSimulationInputs}
/>
{/* <StdcmDefaultCard text="Indiquer le sillon postérieur" Icon={<ArrowDown size="lg" />} /> */}
{/* //TODO: replace .wizz-effect once we have the definitive one */}
<div
className={cx('stdcm-v2-launch-request', {
'wizz-effect': !pathfindingState.done,
'pb-5': !pathfindingState.error,
})}
>
{currentSimulationInputs && (
<Button
label={t('simulation.getSimulation')}
onClick={() => {
if (pathfindingState.done) {
launchStdcmRequest();
setCurrentSimulationInputs(undefined);
}
}}
/>
)}
{pathfindingState.error && (
<div className="warning-box">
<span>
<Alert variant="fill" />
</span>
<p className="mb-0">{t('pathfindingFailed')}</p>
</div>
)}
</div>
{isPending && <StdcmLoader cancelStdcmRequest={cancelStdcmRequest} ref={loaderRef} />}
</div>
</div>
<div className="osrd-config-item-container osrd-config-item-container-map stdcm-v2-map">
<Map hideAttribution />
</div>
<div />
</div>
);
};

export default StdcmConfig;
33 changes: 18 additions & 15 deletions front/src/applications/stdcmV2/components/StdcmConsist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import { useAppDispatch } from 'store';

import StdcmCard from './StdcmCard';
import StdcmSuggestions from './StdcmSuggestions';
import type { StdcmConfigCardProps } from '../types';

interface StdcmSuggestionsConsistOption
extends SelectOptionObject,
Omit<LightRollingStockWithLiveries, 'id'> {
value: LightRollingStockWithLiveries;
}
type StdcmSuggestionsConsistOption = SelectOptionObject &
Omit<LightRollingStockWithLiveries, 'id'> & {
value: LightRollingStockWithLiveries;
};

const ConsistCardTitle = ({
rollingStock,
Expand All @@ -37,7 +37,7 @@ const ConsistCardTitle = ({
);
};

const StdcmConsist = ({ disabled = false }: { disabled?: boolean }) => {
const StdcmConsist = ({ setCurrentSimulationInputs, disabled = false }: StdcmConfigCardProps) => {
const { t } = useTranslation('stdcm');
const { speedLimitByTag, speedLimitsByTags, dispatchUpdateSpeedLimitByTag } =
useStoreDataForSpeedLimitByTagSelector();
Expand Down Expand Up @@ -88,6 +88,12 @@ const StdcmConsist = ({ disabled = false }: { disabled?: boolean }) => {
} else {
searchRollingStock('');
}
setCurrentSimulationInputs((prevState) => ({
...prevState,
consist: {
tractionEngine: rollingStock,
},
}));
}, [rollingStock]);

return (
Expand All @@ -105,15 +111,12 @@ const StdcmConsist = ({ disabled = false }: { disabled?: boolean }) => {
onChange={onInputChange}
onBlur={onInputOnBlur}
disabled={disabled}
options={filteredRollingStockList.map(
(rs: LightRollingStockWithLiveries) =>
({
value: rs,
label: getLabel(rs),
...rs,
id: rs.id.toString(),
}) as StdcmSuggestionsConsistOption
)}
options={filteredRollingStockList.map((rs) => ({
value: rs,
label: getLabel(rs),
...rs,
id: rs.id.toString(),
}))}
onSelectSuggestion={onSelectSuggestion}
/>
</div>
Expand Down
14 changes: 8 additions & 6 deletions front/src/applications/stdcmV2/components/StdcmDefaultCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import StdcmCard from './StdcmCard';
type StdcmCardProps = {
text: string;
Icon: React.ReactNode;
hasTip?: boolean;
onClick?: () => void;
};
const StdcmDefaultCard = ({ text, Icon }: StdcmCardProps) => (
<StdcmCard hasTip>
<div>
<span>{Icon}</span>
<span>{text}</span>
</div>
const StdcmDefaultCard = ({ text, Icon, hasTip = false, onClick }: StdcmCardProps) => (
<StdcmCard hasTip={hasTip}>
<button type="button" onClick={onClick}>
<span className="stdcm-v2-default-card-icon">{Icon}</span>
<span className="stdcm-v2-default-card-button pl-3">{text}</span>
</button>
</StdcmCard>
);

Expand Down
Loading

0 comments on commit 2c70a65

Please sign in to comment.