Skip to content
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

Nwz/import trains from opendata #2586

Merged
merged 27 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7ac114e
front: importGraou: first try
nicolaswurtz Dec 3, 2022
0ee0a48
front: importGraou: date & time added
nicolaswurtz Dec 3, 2022
f750b3b
front: GraouImport: working config, working getTrainsList
nicolaswurtz Dec 4, 2022
999ed71
front: GraouImport: trainslist ok, beginning modal import
nicolaswurtz Dec 4, 2022
521f6aa
front: GraouImport: path complete done
nicolaswurtz Dec 4, 2022
0a0f0fe
front: GraouImport: pathfinding ok
nicolaswurtz Dec 5, 2022
2ec7e68
front: GraouImport: adding global settings from osrdconfig
nicolaswurtz Dec 5, 2022
d8cd778
front: OpenDataImport: switching from Graou to OpenData
nicolaswurtz Dec 5, 2022
ff8db18
front: OpenDataImport: added rollingstockid to result
nicolaswurtz Dec 5, 2022
15f6267
front: OpenDataImport: it's working !
nicolaswurtz Dec 5, 2022
9f4a0b8
front: OpenDataImport: using real external serveur from Graou
nicolaswurtz Dec 6, 2022
cc3387a
front: OpenDataImport: some corrections
nicolaswurtz Dec 7, 2022
96d17e4
front: OpenDataImport: adapt map to maplibre migration
nicolaswurtz Dec 10, 2022
da0d5d4
front: OpenDataImport: cleaning timetableselector a little
nicolaswurtz Dec 11, 2022
4dddb93
front: OpenDataImport: direct links to simulation & stdcm after import
nicolaswurtz Dec 11, 2022
5f174b1
front: OpenDataImport: first pass to make pathfinding by OPs trigram …
nicolaswurtz Dec 11, 2022
264730f
front: OpenDataImport: some bugfixes
nicolaswurtz Dec 12, 2022
6257713
front: OpenDataImport: some corrections
nicolaswurtz Dec 12, 2022
0f6bdf6
front: some bugfixes
nicolaswurtz Dec 12, 2022
bcd7543
front: Remove DGEX Solutions mentions
nicolaswurtz Dec 12, 2022
101f1c9
front: fast relooking homepage
nicolaswurtz Dec 12, 2022
9d0ea81
front: rework home page
nicolaswurtz Dec 12, 2022
585cb4d
front: opendataimport: bugfix
nicolaswurtz Dec 14, 2022
9ba4a04
front: replace png by svg when possible & svgo
nicolaswurtz Dec 14, 2022
c46544a
front: OpenDataImport: add defaultProps values
nicolaswurtz Dec 15, 2022
3df5fac
front: OpenDataImport: bugfix on state selection for mapStyle
nicolaswurtz Dec 15, 2022
c567887
front: OpenDataImport: state selector for timetableID more lightweight
nicolaswurtz Dec 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion front/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>OSRD - DGEX Solutions</title>
<title>OSRD</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
8 changes: 8 additions & 0 deletions front/public/locales/fr/home.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"customget": "Visualisation JSON GET",
"editor": "Éditeur d'infrastructure",
"map": "Cartographie",
"opendataimport": "Importation horaires",
"stdcm": "Sillons de dernière minute",
"timetable": "Grilles horaires"
}
44 changes: 44 additions & 0 deletions front/public/locales/fr/opendata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"closeOSRDConfig": "Fermer",
"completeTrackSectionID": "Compléter les coordonnées",
"date": "DATE",
"datetime": "Date & horaires",
"endTime": "FIN",
"errorMessages": {
"error": "Une erreur est survenue",
"errorNoDate": "Vous devez renseigner une date.",
"errorNoFrom": "Vous devez renseigner une origine.",
"errorNoTo": "Vous devez renseigner une destination.",
"errorSameFromTo": "L'origine et la destination doivent être différentes.",
"unableToRetrievePathfinding": "Impossible de créer un chemin"
},
"from": "Origine",
"generatePaths": "Générer les pathfinding",
"generatePathsAuto": "Compléter et générer les pathfinding automatiquement",
"generateTrainSchedules": "Générer les calculs de marche",
"goToSimulation": "Résultats de simulation",
"goToSTDCM": "Sillon de dernière minute",
"import": "Importation",
"inputPlaceholder": "Nom, trigramme",
"launchImport": "Démarrer l'importation",
"noResults": "Aucun résultat",
"openOSRDConfig": "Infra / Table horaire / Matériel",
"startTime": "DÉBUT",
"status": {
"calculatingTrainSchedule": "Calcul de marches en cours...",
"calculatingTrainScheduleComplete": "Calcul de marches terminé",
"calculatingTrainScheduleCompleteAll": "Tous les calculs de marches sont terminés.",
"calculatingTrainScheduleError": "Le calcul de marche a échoué",
"complete": "positionnez",
"missingInfra": "Vous devez renseigner une infrastructure",
"missingRollingStock": "Vous devez choisir un matériel roulant par défaut",
"missingTimetable": "Vous devez choisir une grille horaire",
"noImportationPossible": "L'importation n'est pas possible pour l'instant :",
"pathComplete": "Tous les pathfinding ont été effectués",
"ready": "Prêt.",
"searchingPath": "Génération pathfinding",
"uicComplete": "Tous les lieux ont été renseignés."
},
"to": "Destination",
"trainsFound": "trains trouvé(s)"
}
7 changes: 0 additions & 7 deletions front/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,6 @@
"track_section-length": "Taille"
}
},
"Home": {
"customget": "Visualisation JSON GET",
"map": "Cartographie",
"editor": "Éditeur d'infrastructure",
"timetable": "Grilles horaires",
"stdcm": "Sillons de dernière minute (en travaux)"
},
"Login": {
"connect": "Se connecter",
"englishFlag": "drapeau anglais",
Expand Down
2 changes: 1 addition & 1 deletion front/src/applications/carto/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function Map() {
touchZoomRotate
>
<VirtualLayers />
<AttributionControl customAttribution="©SNCF/DGEX Solutions" />
<AttributionControl customAttribution="©SNCF Réseau" />
<ScaleControl maxWidth={100} unit="metric" style={scaleControlStyle} />

<Background
Expand Down
6 changes: 6 additions & 0 deletions front/src/applications/customget/views/SpaceTimeChart.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,13 @@ export default function SpaceTimeChart(props) {
setTimeout(() => {
dispatch(updateMustRedraw(true));
}, 0);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
// ADN, entire fonction operation is subject to one condition, so aopply this condition before OR write clear and first condition to return (do nothing)
offsetTimeByDragging(dragOffset);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dragOffset]);

useEffect(() => {
Expand All @@ -196,6 +198,7 @@ export default function SpaceTimeChart(props) {
drawAllTrains(resetChart);
handleWindowResize(CHART_ID, dispatch, drawAllTrains, isResizeActive, setResizeActive);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mustRedraw, rotate, selectedTrain, consolidatedSimulation]);

// ADN: trigger a redraw on every simulation change. This is the right pattern.
Expand All @@ -208,6 +211,7 @@ export default function SpaceTimeChart(props) {
drawAllTrains(resetChart, true, newDataSimulation);
handleWindowResize(CHART_ID, dispatch, drawAllTrains, isResizeActive, setResizeActive);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [simulation.trains]);

useEffect(() => {
Expand All @@ -221,6 +225,7 @@ export default function SpaceTimeChart(props) {
);
dispatch(updatePositionValues(newPositionValues));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [chart, mustRedraw]);

useEffect(() => {
Expand All @@ -236,6 +241,7 @@ export default function SpaceTimeChart(props) {
timePosition
);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [positionValues]);

useEffect(() => {
Expand Down
3 changes: 3 additions & 0 deletions front/src/applications/customget/views/TrainList.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,19 +163,22 @@ export default function TrainsList() {
setOnInput(false);
dispatch(updateMustRedraw(true));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedInputName]);

useEffect(() => {
if (debouncedInputTime) {
setOnInput(false);
dispatch(updateMustRedraw(true));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedInputTime]);

useEffect(() => {
if (!onInput) {
setFormattedList(formatTrainsList());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedTrain, departureArrivalTimes, trainNameClickedIDX, typeOfInputFocused]);

return (
Expand Down
2 changes: 1 addition & 1 deletion front/src/applications/editor/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ const MapUnplugged: FC<PropsWithChildren<MapProps>> = ({
}}
>
<VirtualLayers />
<AttributionControl position="bottom-right" customAttribution="©SNCF/DGEX Solutions" />
<AttributionControl position="bottom-right" customAttribution="©SNCF Réseau" />
<ScaleControl
maxWidth={100}
unit="metric"
Expand Down
30 changes: 30 additions & 0 deletions front/src/applications/opendata/Home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import MastNavItemSNCF from 'common/BootstrapSNCF/MastNavItemSNCF';
import MastNavSNCF from 'common/BootstrapSNCF/MastNavSNCF';
import NavBarSNCF from 'common/BootstrapSNCF/NavBarSNCF';
import { NotificationsState } from 'common/Notifications';
import { useTranslation } from 'react-i18next';
import { MdMoreTime } from 'react-icons/md';
import logo from 'assets/logo_osrd_seul_blanc.svg';
import './opendata.scss';
import OpenDataImport from './OpenDataImport';

export default function HomeOpenData() {
const { t } = useTranslation(['opendata']);
return (
<>
<MastNavSNCF
items={
<MastNavItemSNCF link="/opendata/import" linkname={t('import')} icon={<MdMoreTime />} />
}
/>
<NavBarSNCF appName="OSRD / Open data" logo={logo} />
<Routes>
<Route path="/import" element={<OpenDataImport />} />
<Route path="" element={<Navigate to="/opendata/import" replace />} />
</Routes>
<NotificationsState />
</>
);
}
49 changes: 49 additions & 0 deletions front/src/applications/opendata/OpenDataImport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { useEffect, useState } from 'react';
import OpenDataImportConfig from 'applications/opendata/views/OpenDataImportConfig';
import OpenDataTrainsList from 'applications/opendata/views/OpenDataTrainsList';
import OpenDataGlobalSettings from 'applications/opendata/views/OpenDataGlobalSettings';
import { get } from 'common/requests';
import Loader from 'common/Loader';

const ROLLING_STOCK_URL = '/light_rolling_stock/';

export default function OpenDataImport() {
const [config, setConfig] = useState();
const [rollingStockDB, setRollingStockDB] = useState();
const [mustUpdateTimetable, setMustUpdateTimetable] = useState(true);

async function getRollingStockDB() {
try {
const data = await get(ROLLING_STOCK_URL, { page_size: 1000 });
setRollingStockDB(data.results);
} catch (error) {
console.log(error);
}
}

useEffect(() => {
if (!rollingStockDB) {
getRollingStockDB();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return rollingStockDB ? (
<main className="osrd-config-mastcontainer mastcontainer opendata-import">
<div className="p-3">
<OpenDataImportConfig setConfig={setConfig} />
<OpenDataGlobalSettings
mustUpdateTimetable={mustUpdateTimetable}
setMustUpdateTimetable={setMustUpdateTimetable}
/>
<OpenDataTrainsList
config={config}
rollingStockDB={rollingStockDB}
setMustUpdateTimetable={setMustUpdateTimetable}
/>
</div>
</main>
) : (
<Loader />
);
}
122 changes: 122 additions & 0 deletions front/src/applications/opendata/components/Map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import maplibregl from 'maplibre-gl';
import ReactMapGL, { AttributionControl, ScaleControl } from 'react-map-gl';
import { point as turfPoint } from '@turf/helpers';
import { useSelector } from 'react-redux';
import turfNearestPointOnLine from '@turf/nearest-point-on-line';

/* Main data & layers */
import Background from 'common/Map/Layers/Background';
import VirtualLayers from 'applications/osrd/views/OSRDSimulation/VirtualLayers';
import SnappedMarker from 'common/Map/Layers/SnappedMarker';
/* Objects & various */
import TracksGeographic from 'common/Map/Layers/TracksGeographic';
import colors from 'common/Map/Consts/colors';
import osmBlankStyle from 'common/Map/Layers/osmBlankStyle';
import { LAYER_GROUPS_ORDER, LAYERS } from 'config/layerOrder';

import 'common/Map/Map.scss';
import OperationalPoints from 'common/Map/Layers/OperationalPoints';
import Platforms from 'common/Map/Layers/Platforms';
import { getMapMouseEventNearestFeature } from 'utils/mapboxHelper';

export default function Map(props) {
const { viewport, setViewport, setClickedFeature } = props;
const mapStyle = useSelector((state) => state.map.mapStyle);
const [lngLatHover, setLngLatHover] = useState();
const [trackSectionGeoJSON, setTrackSectionGeoJSON] = useState();
const [snappedPoint, setSnappedPoint] = useState();
const mapRef = useRef(null);
const scaleControlStyle = {
left: 20,
bottom: 20,
};

const onFeatureClick = (e) => {
const result = getMapMouseEventNearestFeature(e);
if (
result &&
result.feature.properties &&
result.feature.properties.id &&
result.feature.geometry.type === 'LineString'
) {
setClickedFeature(result.feature);
}
};

const onMoveGetFeature = (e) => {
const result = getMapMouseEventNearestFeature(e);
if (
result &&
result.feature.properties &&
result.feature.properties.id &&
result.feature.geometry.type === 'LineString'
) {
setTrackSectionGeoJSON(result.feature.geometry);
setLngLatHover(result.nearest);
} else {
setSnappedPoint(undefined);
}
};

useEffect(() => {
if (trackSectionGeoJSON !== undefined && lngLatHover !== undefined) {
const point = turfPoint(lngLatHover);
try {
setSnappedPoint(turfNearestPointOnLine(trackSectionGeoJSON, point));
} catch (error) {
console.warn(`Ìmpossible to snapPoint - error ${error}`);
}
}
}, [trackSectionGeoJSON, lngLatHover]);

return (
<ReactMapGL
ref={mapRef}
{...viewport}
style={{ cursor: 'pointer' }}
width="100%"
height="100%"
mapLib={maplibregl}
mapStyle={osmBlankStyle}
onMove={(e) => setViewport(e.viewState)}
onMouseMove={(e) => onMoveGetFeature(e)}
attributionControl={false} // Defined below
onClick={onFeatureClick}
interactiveLayerIds={['chartis/tracks-geo/main']}
touchZoomRotate
>
<VirtualLayers />
<AttributionControl className="attribution-control" customAttribution="©SNCF Réseau" />
<ScaleControl maxWidth={100} unit="metric" style={scaleControlStyle} />

<Background
colors={colors[mapStyle]}
layerOrder={LAYER_GROUPS_ORDER[LAYERS.BACKGROUND.GROUP]}
/>

<Platforms
colors={colors[mapStyle]}
layerOrder={LAYER_GROUPS_ORDER[LAYERS.PLATFORMS.GROUP]}
/>

<TracksGeographic
colors={colors[mapStyle]}
layerOrder={LAYER_GROUPS_ORDER[LAYERS.TRACKS_GEOGRAPHIC.GROUP]}
/>
<OperationalPoints
geomType="geo"
colors={colors[mapStyle]}
layerOrder={LAYER_GROUPS_ORDER[LAYERS.OPERATIONAL_POINTS.GROUP]}
/>
{snappedPoint !== undefined ? <SnappedMarker geojson={snappedPoint} /> : null}
</ReactMapGL>
);
}

Map.propTypes = {
viewport: PropTypes.object.isRequired,
setViewport: PropTypes.func.isRequired,
setClickedFeature: PropTypes.func.isRequired,
};
Loading