-
Notifications
You must be signed in to change notification settings - Fork 74
front: handle unrecognized track in itinerary modal #16634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -426,6 +426,7 @@ | |||||
| "moveLocationOnMap": "Déplacer le point remarquable sur la carte", | ||||||
| "movePointOnMap": "Déplacez ce point en utilisant la carte", | ||||||
| "next": "Suivant", | ||||||
| "noComputation": "il n'y aura pas de calcul pour ce train", | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| "opId": "Identifiant de point", | ||||||
| "opName": "Nom du point remarquable", | ||||||
| "opType": "Type", | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,7 @@ import type { | |||||
| PathItemLocation, | ||||||
| TrainCategory, | ||||||
| } from 'common/api/osrdEditoastApi'; | ||||||
| import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; | ||||||
| import Banner from 'common/Banner'; | ||||||
| import { computeBBoxViewport } from 'common/Map/WarpedMap/core/helpers'; | ||||||
| import { useInfraID } from 'common/osrdContext'; | ||||||
|
|
@@ -35,7 +36,7 @@ import { | |||||
| getPathSteps, | ||||||
| getRollingStockName, | ||||||
| } from 'reducers/osrdconf/operationalStudiesConf/selectors'; | ||||||
| import type { PathStep, PathStepMetadata, PathStepV2 } from 'reducers/osrdconf/types'; | ||||||
| import type { PathStep, PathStepMetadata, PathStepV2, TrainScheduleToEditData } from 'reducers/osrdconf/types'; | ||||||
| import { useAppDispatch } from 'store'; | ||||||
| import { addElementAtIndex } from 'utils/array'; | ||||||
| import { Duration } from 'utils/duration'; | ||||||
|
|
@@ -61,6 +62,7 @@ type ItineraryModalProps = { | |||||
| itineraryModalIsOpen: boolean; | ||||||
| setItineraryModalIsOpen: (isOpen: boolean) => void; | ||||||
| displayTrainScheduleManagement: string; | ||||||
| trainScheduleToEditData?: TrainScheduleToEditData; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can only pass the |
||||||
| }; | ||||||
|
|
||||||
| export type ItineraryModalFormState = { | ||||||
|
|
@@ -75,6 +77,7 @@ const ItineraryModal = ({ | |||||
| itineraryModalIsOpen, | ||||||
| setItineraryModalIsOpen, | ||||||
| displayTrainScheduleManagement, | ||||||
| trainScheduleToEditData, | ||||||
| }: ItineraryModalProps) => { | ||||||
| const { t } = useTranslation('operational-studies', { | ||||||
| keyPrefix: 'manageTrainSchedule.itineraryModal', | ||||||
|
|
@@ -153,6 +156,42 @@ const ItineraryModal = ({ | |||||
| const { launchPathfindingV2, pathProperties, pathfindingError } = usePathfindingV2(); | ||||||
| const { convertFeatureClickToLocation } = useMapTrackSelection(infraId); | ||||||
|
|
||||||
| /** | ||||||
| * When a custom track name is added (one that doesn't exist in the OP parts), | ||||||
| * immediately update the train schedule's path via API to persist the local_track_name. | ||||||
| */ | ||||||
| const updateTrainSchedulePathTrackName = useCallback( | ||||||
| async (stepId: string, trackName: string) => { | ||||||
| if (!trainScheduleToEditData) return; | ||||||
|
|
||||||
| const { trainScheduleId } = trainScheduleToEditData; | ||||||
|
|
||||||
| // GET the current train schedule fresh from the DB to avoid overwriting anything | ||||||
| const { id: _, train_schedule_set_id: __, ...currentData } = await dispatch( | ||||||
| osrdEditoastApi.endpoints.getTrainSchedulesById.initiate( | ||||||
| { id: trainScheduleId }, | ||||||
| { subscribe: false } | ||||||
| ) | ||||||
| ).unwrap(); | ||||||
|
|
||||||
| // Only update the local_track_name on the matching path step | ||||||
| await dispatch( | ||||||
| osrdEditoastApi.endpoints.putTrainSchedulesById.initiate({ | ||||||
| id: trainScheduleId, | ||||||
| trainSchedule: { | ||||||
| ...currentData, | ||||||
| path: currentData.path.map((item) => | ||||||
| item.id === stepId && item.location.type !== 'track_offset' | ||||||
| ? { ...item, location: { ...item.location, local_track_name: trackName || undefined } } | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Comment on lines
+178
to
+185
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for this, you can sort of re-use a part of the |
||||||
| : item | ||||||
| ), | ||||||
| }, | ||||||
| }) | ||||||
| ).unwrap(); | ||||||
| }, | ||||||
| [dispatch, trainScheduleToEditData] | ||||||
| ); | ||||||
|
|
||||||
| const applyOperationalPointToStep = ( | ||||||
| stepId: string, | ||||||
| suggestion: OperationalPointSuggestion, | ||||||
|
|
@@ -546,12 +585,12 @@ const ItineraryModal = ({ | |||||
| {rollingStockMessage && <Banner type="info" message={rollingStockMessage} />} | ||||||
| {hasInvalidPathStepDisplay && ( | ||||||
| <div key={`invalid-op-${bannerWiggle}`}> | ||||||
| <Banner type="error" message={t('alertInvalidOP')} /> | ||||||
| <Banner type="info" message={`${t('alertInvalidOP')} ${t('noComputation')}`} /> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
You can either add the missing period between the two sentences here or, better, directly in the translation file :) |
||||||
| </div> | ||||||
| )} | ||||||
| {!hasInvalidPathStepDisplay && pathfindingError && ( | ||||||
| <div key={`pathfinding-${bannerWiggle}`}> | ||||||
| <Banner type="error" message={pathfindingError} /> | ||||||
| <Banner type="info" message={`${pathfindingError} ${t('noComputation')}`} /> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Same |
||||||
| </div> | ||||||
| )} | ||||||
| {submitAttempted && | ||||||
|
|
@@ -678,6 +717,9 @@ const ItineraryModal = ({ | |||||
| }) | ||||||
| ); | ||||||
| }} | ||||||
| onAddCustomTrackName={(trackName) => { | ||||||
| updateTrainSchedulePathTrackName(pathStep.id, trackName); | ||||||
| }} | ||||||
| onOpBlur={() => { | ||||||
| // If the user focuses out on an input with a valid op, we display the last valid op of this input (or empty) | ||||||
| const valueOnFocus = focusValueRef.current[pathStep.id]; | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -105,19 +105,22 @@ export const usePathStepsMetadata = ( | |
| const matchedOp = pathStepsOperationalPoints.get(pathStep.id)?.at(0); | ||
|
|
||
| const { local_track_name } = location; | ||
| const isValidLocalTrackName = local_track_name | ||
| ? matchedOp?.parts.some((part) => { | ||
|
|
||
| if (!matchedOp) { | ||
| newPathStepsMetadataById.set(pathStep.id, { | ||
| isInvalid: true, | ||
| localTrackName: local_track_name ?? undefined, | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| const isTrackNameUnknown = local_track_name | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find this naming/logic combination a bit odd: Also, if |
||
| ? !matchedOp.parts.some((part) => { | ||
| const track = trackSectionsById[part.track]; | ||
| if (!track) return false; | ||
| return local_track_name === part.local_track_name; | ||
| }) | ||
| : true; | ||
|
|
||
| // If no op is found or if its local_track_name is invalid, it means the path step is invalid | ||
| if (!isValidLocalTrackName || !matchedOp) { | ||
| newPathStepsMetadataById.set(pathStep.id, { isInvalid: true }); | ||
| return; | ||
| } | ||
| : false; | ||
|
|
||
| const parts: Extract<PathStepMetadata, { isInvalid: false; type: 'opRef' }>['parts'] = | ||
| matchedOp.parts.map((part) => ({ | ||
|
|
@@ -133,6 +136,7 @@ export const usePathStepsMetadata = ( | |
| uic: matchedOp.extensions?.identifier?.uic, | ||
| secondaryCode: matchedOp.extensions?.sncf?.ch, | ||
| trackName: local_track_name ?? undefined, | ||
| isTrackNameUnknown, | ||
| parts, | ||
| }); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -293,6 +293,11 @@ | |||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| &.is-invalid { | ||||||||
| // blackAlpha10 | ||||||||
| background-color: rgba(0, 0, 0, 0.1); | ||||||||
|
Comment on lines
+297
to
+298
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't you use black10 ?
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Black10 is different. where we using transparency
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can totally use |
||||||||
| } | ||||||||
|
|
||||||||
| .path-step-counter:not(.is-trailing-placeholder):not(.is-only-step):hover { | ||||||||
| opacity: 1; | ||||||||
| background-color: var(--error60) !important; | ||||||||
|
|
@@ -407,8 +412,7 @@ | |||||||
| } | ||||||||
|
|
||||||||
| &.invalid { | ||||||||
| background-color: var(--error60); | ||||||||
| border-color: var(--error30); | ||||||||
| background-color: var(--info60); | ||||||||
| } | ||||||||
| &.is-only-step { | ||||||||
| pointer-events: none; | ||||||||
|
|
@@ -423,7 +427,6 @@ | |||||||
|
|
||||||||
| &.invalid { | ||||||||
| border-radius: 3px; | ||||||||
| box-shadow: 0 0 0 1.5px rgba(255, 104, 104, 1); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
|
|
@@ -433,6 +436,11 @@ | |||||||
| border-radius: 4px; | ||||||||
| } | ||||||||
|
|
||||||||
| .track-name-unknown .ui-combo-box { | ||||||||
| border-radius: 3px; | ||||||||
| box-shadow: 0 0 0 1.5px var(--grey50); | ||||||||
| } | ||||||||
|
|
||||||||
| .map-interactions { | ||||||||
| margin-left: 5px; | ||||||||
| color: var(--primary60); | ||||||||
|
|
@@ -481,7 +489,7 @@ | |||||||
| } | ||||||||
|
|
||||||||
| .invalid-step-message { | ||||||||
| color: var(--error60); | ||||||||
| color: var(--grey60); | ||||||||
| padding-left: calc(51px - var(--path-step-wrapper-padding-left)); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.