Skip to content

Commit f7c77b2

Browse files
jacomyalsim51
authored andcommitted
editor: allows user to select infra
This commit fixes #1986. Details: - Adds a button in the right of the map that opens a modal where the user can select which infra to edit - Also removes viewport data from URLs in editor, since they caused more trouble than they solved issues
1 parent 0205a8a commit f7c77b2

File tree

5 files changed

+135
-24
lines changed

5 files changed

+135
-24
lines changed

front/public/locales/fr/translation.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
"tool-help": "Voir la description de l'outil actif",
3131
"nav": {
3232
"recenter": "Recentrer la carte",
33-
"toggle-layers": "[TODO] Choisir les couches à afficher"
33+
"toggle-layers": "[TODO] Choisir les couches à afficher",
34+
"select-infra": "Choisir l'infrastructure à éditer",
35+
"infra-changed": "Vous éditez maintenant l'infra \"{{label}}\" (id \"{{id}}\")."
3436
},
3537
"errors": {
3638
"infra-not-found": "L'infrastructure {{id}} non trouvée",

front/src/applications/editor/Editor.tsx

+13-21
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,22 @@ const EditorUnplugged: FC<{ t: TFunction }> = ({ t }) => {
4040
const [toolState, setToolState] = useState<any>(activeTool.getInitialState({ osrdConf }));
4141
const [modal, setModal] = useState<ModalRequest<any, any> | null>(null);
4242
/* eslint-enable @typescript-eslint/no-explicit-any */
43+
const openModal = useCallback(
44+
<ArgumentsType, SubmitArgumentsType>(
45+
request: ModalRequest<ArgumentsType, SubmitArgumentsType>
46+
) => {
47+
setModal(request as ModalRequest<unknown, unknown>);
48+
},
49+
[setModal]
50+
);
4351

44-
const { infra, urlLat, urlLon, urlZoom, urlBearing, urlPitch } =
45-
useParams<Record<string, string>>();
52+
const { infra } = useParams<{ infra?: string }>();
4653
const { mapStyle, viewport } = useSelector(
4754
(state: { map: { mapStyle: string; viewport: ViewportProps } }) => state.map
4855
);
4956
const setViewport = useCallback(
5057
(value) => {
51-
dispatch(updateViewport(value, `/editor/${osrdConf.infraID || '-1'}`));
58+
dispatch(updateViewport(value, `/editor/${osrdConf.infraID || '-1'}`, false));
5259
},
5360
[dispatch, osrdConf.infraID]
5461
);
@@ -57,11 +64,7 @@ const EditorUnplugged: FC<{ t: TFunction }> = ({ t }) => {
5764
() => ({
5865
t,
5966
modal,
60-
openModal: <ArgumentsType, SubmitArgumentsType>(
61-
request: ModalRequest<ArgumentsType, SubmitArgumentsType>
62-
) => {
63-
setModal(request as ModalRequest<unknown, unknown>);
64-
},
67+
openModal,
6568
closeModal: () => {
6669
setModal(null);
6770
},
@@ -98,17 +101,6 @@ const EditorUnplugged: FC<{ t: TFunction }> = ({ t }) => {
98101
useEffect(() => {
99102
// load the data model
100103
dispatch(loadDataModel());
101-
if (urlLat) {
102-
setViewport({
103-
...viewport,
104-
latitude: parseFloat(urlLat || '0'),
105-
longitude: parseFloat(urlLon || '0'),
106-
zoom: parseFloat(urlZoom || '1'),
107-
bearing: parseFloat(urlBearing || '1'),
108-
pitch: parseFloat(urlPitch || '1'),
109-
});
110-
}
111-
// eslint-disable-next-line react-hooks/exhaustive-deps
112104
}, []);
113105

114106
// Update the infrastructure in state
@@ -139,7 +131,7 @@ const EditorUnplugged: FC<{ t: TFunction }> = ({ t }) => {
139131
dispatch(setFailure(new Error(t('Editor.errors.technical', { msg: e.message }))));
140132
});
141133
}
142-
}, [dispatch, infra, osrdConf.infraID, t]);
134+
}, [infra, osrdConf.infraID]);
143135

144136
// Lifecycle events on tools:
145137
useEffect(() => {
@@ -267,7 +259,7 @@ const EditorUnplugged: FC<{ t: TFunction }> = ({ t }) => {
267259
)}
268260
onClick={() => {
269261
if (onClick) {
270-
onClick({ dispatch, setViewport, viewport }, editorState);
262+
onClick({ dispatch, setViewport, viewport, openModal }, editorState);
271263
}
272264
}}
273265
disabled={isDisabled && isDisabled(editorState)}

front/src/applications/editor/Home.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class HomeEditorUnplugged extends React.Component {
2222
<Routes>
2323
<Route path="/" element={<Editor urlmap={config.proxy} />} />
2424
<Route
25-
path="/:infra/:urlLat/:urlLon/:urlZoom/:urlBearing/:urlPitch"
25+
path="/:infra"
2626
element={<Editor urlmap={config.proxy} />}
2727
/>
2828
</Routes>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import React, { FC, useEffect, useState } from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
import { useDispatch } from 'react-redux';
4+
import { datetime2string } from 'utils/timeManipulation';
5+
6+
import { ModalProps } from '../tools/types';
7+
import Modal from './Modal';
8+
import { get } from '../../../common/requests';
9+
import { addNotification, setFailure } from '../../../reducers/main';
10+
import history from '../../../main/history';
11+
import { useNavigate } from 'react-router';
12+
13+
const infraURL = '/infra/';
14+
type InfrasList = {
15+
id: string;
16+
name: string;
17+
modified: number;
18+
}[];
19+
20+
async function getInfrasList(): Promise<InfrasList> {
21+
const response = await get<{ results: InfrasList }>(infraURL, {});
22+
return response.results;
23+
}
24+
25+
const InfraSelectorModal: FC<ModalProps<{}>> = ({ submit, cancel }) => {
26+
const dispatch = useDispatch();
27+
const navigate = useNavigate();
28+
const { t } = useTranslation(['translation', 'osrdconf']);
29+
const [infras, setInfras] = useState<InfrasList | null>(null);
30+
31+
useEffect(() => {
32+
getInfrasList()
33+
.then((list) => setInfras(list))
34+
.catch((e) => {
35+
dispatch(
36+
setFailure({
37+
name: t('errorMessages.unableToRetrieveInfraList'),
38+
message: e.message,
39+
})
40+
);
41+
console.log('ERROR', e);
42+
});
43+
}, []);
44+
45+
return (
46+
<Modal onClose={cancel} title={t('osrdconf:infrachoose')}>
47+
<div className="mb-3 osrd-config-infraselector">
48+
{infras?.map((infra) => (
49+
<div
50+
role="button"
51+
tabIndex={-1}
52+
onClick={() => {
53+
dispatch(
54+
addNotification({
55+
type: 'info',
56+
text: t('Editor.nav.infra-changed', { id: infra.id, label: infra.name }),
57+
})
58+
);
59+
navigate(`/editor/${infra.id}`);
60+
submit({});
61+
}}
62+
key={infra.id}
63+
data-dismiss="modal"
64+
className="osrd-config-infraselector-item mb-2"
65+
>
66+
<div className="d-flex align-items-center">
67+
<div className="text-primary small mr-2">{infra.id}</div>
68+
<div className="flex-grow-1">{infra.name}</div>
69+
<div className="small">{datetime2string(infra.modified)}</div>
70+
</div>
71+
</div>
72+
))}
73+
{!infras && (
74+
<div className="d-flex align-items-center justify-content-center" style={{ width: 100 }}>
75+
<div className="spinner-border" role="status">
76+
<span className="sr-only">Loading...</span>
77+
</div>
78+
</div>
79+
)}
80+
</div>
81+
82+
<div className="text-right">
83+
<button type="button" className="btn btn-danger mr-2" onClick={cancel}>
84+
{t('common.cancel')}
85+
</button>
86+
<button
87+
type="button"
88+
className="btn btn-primary"
89+
onClick={() => submit({})}
90+
disabled={!infras}
91+
>
92+
{t('common.confirm')}
93+
</button>
94+
</div>
95+
</Modal>
96+
);
97+
};
98+
99+
export default InfraSelectorModal;

front/src/applications/editor/nav.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { Dispatch } from 'redux';
22
import { IconType } from 'react-icons/lib/esm/iconBase';
3-
import { BiTargetLock, FiLayers, FiZoomIn, FiZoomOut } from 'react-icons/all';
3+
import { BiTargetLock } from 'react-icons/bi';
4+
import { BsMap } from 'react-icons/bs';
5+
import { FiLayers, FiZoomIn, FiZoomOut } from 'react-icons/fi';
46
import { LinearInterpolator, ViewportProps } from 'react-map-gl';
57

68
import { EditorState } from '../../reducers/editor';
79
import { getZoneViewport } from '../../utils/mapboxHelper';
10+
import { ModalRequest } from './tools/types';
11+
import InfraSelectionModal from './components/InfraSelectionModal';
812

913
const ZOOM_DEFAULT = 5;
1014
const ZOOM_DELTA = 1.5;
@@ -30,6 +34,9 @@ export interface NavButton {
3034
dispatch: Dispatch;
3135
viewport: ViewportProps;
3236
setViewport: (newViewport: ViewportProps) => void;
37+
openModal: <ArgumentsType, SubmitArgumentsType>(
38+
request: ModalRequest<ArgumentsType, SubmitArgumentsType>
39+
) => void;
3340
},
3441
editorState: EditorState
3542
) => void;
@@ -96,6 +103,17 @@ const NavButtons: NavButton[][] = [
96103
// TODO
97104
},
98105
},
106+
{
107+
id: 'infras',
108+
icon: BsMap,
109+
labelTranslationKey: 'Editor.nav.select-infra',
110+
async onClick({ openModal }) {
111+
openModal({
112+
component: InfraSelectionModal,
113+
arguments: {},
114+
});
115+
},
116+
},
99117
],
100118
];
101119

0 commit comments

Comments
 (0)