From 1249fa5bed1753dce749854eedb1895022396c18 Mon Sep 17 00:00:00 2001 From: Angelina Kuntz Date: Wed, 6 May 2026 10:02:30 +0200 Subject: [PATCH 01/13] editoast: rename operational point fields For the international format, the extensions have been flatten and some fields have been renamed. Previous fields : `trigram` is now `main_code` `ch` is now `secondary_code` `ch_long_label` is now `secondary_name` New fields : `country_code` : "FR" as example for the France `is_passenger_station` as a boolean Signed-off-by: Angelina Kuntz --- .../kotlin/fr/sncf/osrd/RawInfraRJSParser.kt | 23 +- .../osrd/railjson/schema/infra/RJSInfra.java | 2 +- .../schema/infra/RJSOperationalPoint.kt | 26 ++ .../infra/RJSOperationalPointExtensions.java | 18 -- ...JSOperationalPointIdentifierExtension.java | 11 - .../RJSOperationalPointSncfExtension.java | 25 -- core/settings.gradle | 4 +- .../api/path_properties/PathPropResponse.kt | 24 +- .../PathPropResponseConverter.kt | 37 +-- .../osrd/pathfinding/PathPropEndpointTest.kt | 24 +- .../sim_infra_adapter/PathPropertiesTests.kt | 33 ++- editoast/core_client/src/path_properties.rs | 35 ++- editoast/database/src/tables.rs | 7 +- editoast/editoast_models/src/infra.rs | 4 +- editoast/editoast_models/src/infra_objects.rs | 9 +- .../down.sql | 31 +++ .../up.sql | 20 ++ .../down.sql | 7 + .../up.sql | 90 +++++++ editoast/openapi.yaml | 252 ++++++++++++------ .../osm_to_railjson/src/osm_to_railjson.rs | 8 +- editoast/osm_to_railjson/src/utils.rs | 43 ++- editoast/schemas/src/infra.rs | 3 - .../schemas/src/infra/operational_point.rs | 66 +---- editoast/schemas/src/infra/railjson.rs | 2 +- editoast/schemas/src/train_schedule.rs | 4 +- .../schemas/src/train_schedule/path_item.rs | 6 +- editoast/src/views/infra/mod.rs | 27 +- .../src/views/path/operational_point_cache.rs | 60 ++--- editoast/src/views/projection.rs | 2 +- editoast/src/views/search.rs | 47 ++-- editoast/src/views/timetable/stdcm.rs | 6 +- .../src/views/timetable/train_schedule.rs | 2 +- front/public/locales/en/infraEditor.json | 69 ++--- front/src/common/api/generatedEditoastApi.ts | 75 ++++-- front/src/common/api/osrdRailwayManagerApi.ts | 8 +- front/src/reducers/osrdconf/infra_schema.json | 157 +++++------ osrd_schemas_auto/osrd_schemas_auto/models.py | 147 ++++++++-- python/osrd_schemas/osrd_schemas/infra.py | 54 ++-- python/osrd_schemas/pyproject.toml | 2 +- python/osrd_schemas/uv.lock | 2 +- .../railjson_generator/schema/infra/infra.py | 22 +- .../schema/infra/operational_point.py | 28 +- python/railjson_generator/uv.lock | 2 +- tests/data/infras/etcs_infra/infra.json | 178 +++++-------- tests/data/infras/example_script/infra.json | 24 +- tests/data/infras/medium_infra/infra.json | 222 ++++++--------- tests/data/infras/nested_switches/infra.json | 2 +- .../data/infras/overlapping_routes/infra.json | 90 +++---- tests/data/infras/small_infra/infra.json | 178 +++++-------- tests/data/infras/tiny_infra/infra.json | 46 ++-- tests/data/infras/y_infra/infra.json | 55 ++-- tests/infra-scripts/medium_infra.py | 24 +- .../small_infra_creator/__init__.py | 20 +- tests/tests/test_pathfinding.py | 20 +- tests/uv.lock | 2 +- 56 files changed, 1226 insertions(+), 1159 deletions(-) create mode 100644 core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPoint.kt delete mode 100644 core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointExtensions.java delete mode 100644 core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointIdentifierExtension.java delete mode 100644 core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointSncfExtension.java create mode 100644 editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/down.sql create mode 100644 editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/up.sql create mode 100644 editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/down.sql create mode 100644 editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/up.sql diff --git a/core/kt-osrd-rjs-parser/src/main/kotlin/fr/sncf/osrd/RawInfraRJSParser.kt b/core/kt-osrd-rjs-parser/src/main/kotlin/fr/sncf/osrd/RawInfraRJSParser.kt index b856271dcfc..03febf3e375 100644 --- a/core/kt-osrd-rjs-parser/src/main/kotlin/fr/sncf/osrd/RawInfraRJSParser.kt +++ b/core/kt-osrd-rjs-parser/src/main/kotlin/fr/sncf/osrd/RawInfraRJSParser.kt @@ -751,19 +751,16 @@ fun parseRJSInfra(rjsInfra: RJSInfra): RawInfra { val trackSectionName = opPart.track val trackSectionOffset = Offset(opPart.position.meters) val props = mutableMapOf() - if (operationalPoint.extensions?.identifier != null) { - val identifier = operationalPoint.extensions!!.identifier!! - props["identifier"] = identifier.name - props["uic"] = identifier.uic.toString() - } - if (operationalPoint.extensions?.sncf != null) { - val sncf = operationalPoint.extensions!!.sncf!! - props["ci"] = sncf.ci.toString() - props["ch"] = sncf.ch - props["chShortLabel"] = sncf.chShortLabel - props["chLongLabel"] = sncf.chLongLabel - props["trigram"] = sncf.trigram - } + props["name"] = operationalPoint.name + props["uic"] = operationalPoint.uic.toString() + props["mainCode"] = operationalPoint.mainCode + props["countryCode"] = operationalPoint.countryCode + props["isPassengerStation"] = operationalPoint.isPassengerStation.toString() + if (operationalPoint.plc != null) props["plc"] = operationalPoint.plc!! + if (operationalPoint.secondaryCode != null) + props["secondaryCode"] = operationalPoint.secondaryCode!! + if (operationalPoint.secondaryName != null) + props["secondaryName"] = operationalPoint.secondaryName!! val weight = operationalPoint.weight if (weight != null) { props["weight"] = weight diff --git a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSInfra.java b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSInfra.java index a43d91fee04..b2217850c29 100644 --- a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSInfra.java +++ b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSInfra.java @@ -22,7 +22,7 @@ public class RJSInfra { .build() .adapter(RJSInfra.class); - public static final transient String CURRENT_VERSION = "3.5.2"; + public static final transient String CURRENT_VERSION = "3.5.3"; /** The version of the infra format used */ public String version; diff --git a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPoint.kt b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPoint.kt new file mode 100644 index 00000000000..9adb14dc58a --- /dev/null +++ b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPoint.kt @@ -0,0 +1,26 @@ +package fr.sncf.osrd.railjson.schema.infra + +import com.squareup.moshi.Json +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings +import fr.sncf.osrd.railjson.schema.common.Identified +import fr.sncf.osrd.railjson.schema.infra.trackranges.RJSOperationalPointPart + +@SuppressFBWarnings("UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD") +class RJSOperationalPoint( + val id: String, + val parts: List, + val weight: String?, + val name: String, + val uic: Long?, + val plc: String?, + @property:Json(name = "country_code") val countryCode: String, + @property:Json(name = "main_code") val mainCode: String, + @property:Json(name = "secondary_code") val secondaryCode: String?, + @property:Json(name = "is_passenger_station") val isPassengerStation: Boolean, + @property:Json(name = "secondary_name") val secondaryName: String?, +) : Identified { + + override fun getID(): String { + return id + } +} diff --git a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointExtensions.java b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointExtensions.java deleted file mode 100644 index 0eff9280938..00000000000 --- a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointExtensions.java +++ /dev/null @@ -1,18 +0,0 @@ -package fr.sncf.osrd.railjson.schema.infra; - -import org.jetbrains.annotations.Nullable; - -public class RJSOperationalPointExtensions { - @Nullable - public RJSOperationalPointSncfExtension sncf; - - @Nullable - public RJSOperationalPointIdentifierExtension identifier; - - public RJSOperationalPointExtensions( - @Nullable RJSOperationalPointSncfExtension sncf, - @Nullable RJSOperationalPointIdentifierExtension identifier) { - this.sncf = sncf; - this.identifier = identifier; - } -} diff --git a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointIdentifierExtension.java b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointIdentifierExtension.java deleted file mode 100644 index 8e38e8858c6..00000000000 --- a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointIdentifierExtension.java +++ /dev/null @@ -1,11 +0,0 @@ -package fr.sncf.osrd.railjson.schema.infra; - -public class RJSOperationalPointIdentifierExtension { - public String name; - public long uic; - - public RJSOperationalPointIdentifierExtension(String name, long uic) { - this.name = name; - this.uic = uic; - } -} diff --git a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointSncfExtension.java b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointSncfExtension.java deleted file mode 100644 index acb1f85b7b7..00000000000 --- a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/infra/RJSOperationalPointSncfExtension.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.sncf.osrd.railjson.schema.infra; - -import com.squareup.moshi.Json; - -public class RJSOperationalPointSncfExtension { - public Long ci; - public String ch; - - @Json(name = "ch_short_label") - public String chShortLabel; - - @Json(name = "ch_long_label") - public String chLongLabel; - - public String trigram; - - public RJSOperationalPointSncfExtension( - Long ci, String ch, String chShortLabel, String chLongLabel, String trigram) { - this.ci = ci; - this.ch = ch; - this.chShortLabel = chShortLabel; - this.chLongLabel = chLongLabel; - this.trigram = trigram; - } -} diff --git a/core/settings.gradle b/core/settings.gradle index 93764ae2467..ee457160eb1 100644 --- a/core/settings.gradle +++ b/core/settings.gradle @@ -1,7 +1,7 @@ pluginManagement { repositories { gradlePluginPortal() - maven { url "https://maven-central.storage-download.googleapis.com/maven2/" } + maven { url = "https://maven-central.storage-download.googleapis.com/maven2/" } mavenCentral() } } @@ -30,7 +30,7 @@ dependencyResolutionManagement { versionCatalogs repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { - maven { url "https://maven-central-eu.storage-download.googleapis.com/maven2/" } + maven { url = "https://maven-central-eu.storage-download.googleapis.com/maven2/" } mavenCentral() } } diff --git a/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponse.kt b/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponse.kt index bd1594629db..0467418972a 100644 --- a/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponse.kt +++ b/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponse.kt @@ -31,9 +31,16 @@ class NonElectrified : Electrification data class OperationalPointResponse( val id: String, val part: OperationalPointPartResponse, - val extensions: OperationalPointExtensions?, val position: Offset, val weight: Long?, + val name: String, + val uic: Long?, + val plc: String?, + @Json(name = "country_code") val countryCode: String, + @Json(name = "main_code") val mainCode: String, + @Json(name = "secondary_code") val secondaryCode: String?, + @Json(name = "is_passenger_station") val isPassengerStation: Boolean, + @Json(name = "secondary_name") val secondaryName: String?, ) data class OperationalPointPartResponse( @@ -43,21 +50,6 @@ data class OperationalPointPartResponse( val extensions: OperationalPointPartExtension?, ) -data class OperationalPointExtensions( - val sncf: OperationalPointSncfExtension?, - val identifier: OperationalPointIdentifierExtension?, -) - -data class OperationalPointSncfExtension( - val ci: Long, - val ch: String, - @Json(name = "ch_short_label") val chShortLabel: String, - @Json(name = "ch_long_label") val chLongLabel: String, - val trigram: String, -) - -data class OperationalPointIdentifierExtension(val name: String, val uic: Long) - data class OperationalPointPartExtension(val sncf: OperationalPointPartSncfExtension?) data class OperationalPointPartSncfExtension(val kp: String) diff --git a/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponseConverter.kt b/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponseConverter.kt index 5f6eb5b77ad..cc538475648 100644 --- a/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponseConverter.kt +++ b/core/src/main/kotlin/fr/sncf/osrd/api/path_properties/PathPropResponseConverter.kt @@ -84,31 +84,22 @@ private fun makeOperationalPoints( OperationalPointPartSncfExtension(opPartProps["kp"]!!) ), ) - // If ci is null, then all its other values and the entire op sncf extension are null - val opSncfExtension = - if (opPartProps["ci"] == null) null - else - OperationalPointSncfExtension( - opPartProps["ci"]!!.toLong(), - opPartProps["ch"]!!, - opPartProps["chShortLabel"]!!, - opPartProps["chLongLabel"]!!, - opPartProps["trigram"]!!, - ) - // if name is null, uic and the op id extension are null - val opIdExtension = - if (opPartProps["identifier"] == null) null - else - OperationalPointIdentifierExtension( - opPartProps["identifier"]!!, - opPartProps["uic"]!!.toLong(), - ) - val opExtensions = - if (opSncfExtension == null && opIdExtension == null) null - else OperationalPointExtensions(opSncfExtension, opIdExtension) val weight = if (opPartProps["weight"] == null) null else opPartProps["weight"]!!.toLong() val opResult = - OperationalPointResponse(operationalPointId, opPartResult, opExtensions, offset, weight) + OperationalPointResponse( + operationalPointId, + opPartResult, + offset, + weight, + opPartProps["name"]!!, + opPartProps["uic"]?.toLong(), + opPartProps["plc"], + opPartProps["countryCode"]!!, + opPartProps["mainCode"]!!, + opPartProps["secondaryCode"], + opPartProps["isPassengerStation"] == "true", + opPartProps["secondaryName"], + ) res.add(opResult) } return res diff --git a/core/src/test/kotlin/fr/sncf/osrd/pathfinding/PathPropEndpointTest.kt b/core/src/test/kotlin/fr/sncf/osrd/pathfinding/PathPropEndpointTest.kt index 7abd572910e..f6ef6bbc712 100644 --- a/core/src/test/kotlin/fr/sncf/osrd/pathfinding/PathPropEndpointTest.kt +++ b/core/src/test/kotlin/fr/sncf/osrd/pathfinding/PathPropEndpointTest.kt @@ -59,22 +59,30 @@ class PathPropEndpointTest : ApiTest() { OperationalPointResponse( "West_station", OperationalPointPartResponse("TA0", 700.0, "V1", null), - OperationalPointExtensions( - OperationalPointSncfExtension(22, "BV", "BV", "0", "WS"), - OperationalPointIdentifierExtension("West_station", 8722), - ), Offset(650.meters), null, + "West_station", + 8722, + null, + "FR", + "WS", + "BV", + true, + "0", ), OperationalPointResponse( "West_station", OperationalPointPartResponse("TA1", 500.0, "V2", null), - OperationalPointExtensions( - OperationalPointSncfExtension(22, "BV", "BV", "0", "WS"), - OperationalPointIdentifierExtension("West_station", 8722), - ), Offset(2450.meters), null, + "West_station", + 8722, + null, + "FR", + "WS", + "BV", + true, + "0", ), ) assertEquals(parsed.operationalPoints, oPs) diff --git a/core/src/test/kotlin/fr/sncf/osrd/sim_infra_adapter/PathPropertiesTests.kt b/core/src/test/kotlin/fr/sncf/osrd/sim_infra_adapter/PathPropertiesTests.kt index 9ad33c67e0f..2dd4a0132cd 100644 --- a/core/src/test/kotlin/fr/sncf/osrd/sim_infra_adapter/PathPropertiesTests.kt +++ b/core/src/test/kotlin/fr/sncf/osrd/sim_infra_adapter/PathPropertiesTests.kt @@ -7,8 +7,6 @@ import fr.sncf.osrd.path.implementations.buildTrainPathFromBlock import fr.sncf.osrd.railjson.schema.common.graph.ApplicableDirection import fr.sncf.osrd.railjson.schema.geom.RJSLineString import fr.sncf.osrd.railjson.schema.infra.RJSOperationalPoint -import fr.sncf.osrd.railjson.schema.infra.RJSOperationalPointExtensions -import fr.sncf.osrd.railjson.schema.infra.RJSOperationalPointSncfExtension import fr.sncf.osrd.railjson.schema.infra.trackranges.* import fr.sncf.osrd.railjson.schema.rollingstock.RJSLoadingGaugeType import fr.sncf.osrd.sim_infra.api.BlockId @@ -105,7 +103,13 @@ class PathPropertiesTests { "new_op_1", listOf(RJSOperationalPointPart("ne.micro.foo_a", 200.0, "V1", null)), null, + "new_op_1", + 0, + null, + "FR", + "TRI", null, + false, null, ) ) @@ -114,7 +118,13 @@ class PathPropertiesTests { "new_op_2", listOf(RJSOperationalPointPart("ne.micro.bar_a", 0.0, "V1", null)), null, + "new_op_2", + 0, + null, + "FR", + "TRI", null, + false, null, ) ) @@ -172,12 +182,15 @@ class PathPropertiesTests { ), ), ), - RJSOperationalPointExtensions( - RJSOperationalPointSncfExtension(0, "BV", "B", "0", "TRI"), - null, - ), null, + "point1", + 0, null, + "FR", + "TRI", + "0", + false, + "0", ), RJSOperationalPoint( "point2", @@ -193,8 +206,14 @@ class PathPropertiesTests { RJSOperationalPointPart("TA1", 1_950.0, "V1", null), ), null, + "point2", + 0, null, - null, + "FR", + "TRI", + "0", + false, + "0", ), ) val infra = fullInfraFromRJS(rjsInfra, InfraMetadata("modified_small_infra")) diff --git a/editoast/core_client/src/path_properties.rs b/editoast/core_client/src/path_properties.rs index 505adaf8fd1..d063a4ac318 100644 --- a/editoast/core_client/src/path_properties.rs +++ b/editoast/core_client/src/path_properties.rs @@ -1,7 +1,7 @@ use geos::geojson::Geometry; -use schemas::infra::OperationalPointExtensions; use schemas::infra::OperationalPointPart; use schemas::primitives::Identifier; +use schemas::primitives::NonBlankString; use serde::Deserialize; use serde::Serialize; use utoipa::ToSchema; @@ -12,7 +12,6 @@ use crate::WorkerKey; use crate::pathfinding::TrackRange; use schemas::infra::OperationalPointPartExtension; -use schemas::infra::OperationalPointSncfExtension; #[derive(Debug, Hash, Serialize)] pub struct PathPropertiesRequest<'a> { @@ -100,18 +99,30 @@ pub struct OperationalPointOnPath { pub id: Identifier, /// The part along the path pub part: OperationalPointPart, - /// Extensions associated to the operational point - #[serde(default)] - pub extensions: OperationalPointExtensions, /// Distance from the beginning of the path in mm pub position: u64, /// Importance of the operational point #[schema(required, minimum = 0, maximum = 100)] pub weight: Option, + #[schema(inline)] + pub name: NonBlankString, + pub uic: u32, + /// Primary Location Code : https://rne.eu/it/products/ccs/crd/ + #[schema(inline)] + pub plc: Option, + #[schema(inline)] + pub country_code: NonBlankString, + #[schema(inline)] + pub main_code: NonBlankString, + #[schema(inline)] + pub secondary_code: Option, + pub is_passenger_station: bool, + #[schema(inline)] + pub secondary_name: Option, } impl OperationalPointOnPath { - pub fn new_test(id: &str, ci: i64, trigram: &str) -> Self { + pub fn new_test(id: &str, uic: u32, main_code: &str) -> Self { OperationalPointOnPath { id: Identifier(id.into()), part: OperationalPointPart { @@ -120,12 +131,16 @@ impl OperationalPointOnPath { local_track_name: "V1".into(), extensions: OperationalPointPartExtension { sncf: None }, }, - extensions: OperationalPointExtensions { - sncf: Some(OperationalPointSncfExtension::new(ci, "BV", trigram)), - identifier: None, - }, position: 0, weight: None, + name: "TEST OP".into(), + uic, + plc: None, + country_code: "FR".into(), + main_code: main_code.into(), + secondary_code: Some("BV".into()), + is_passenger_station: true, + secondary_name: Some("Test OP".into()), } } } diff --git a/editoast/database/src/tables.rs b/editoast/database/src/tables.rs index 15456c9b580..fd8f7c3188c 100644 --- a/editoast/database/src/tables.rs +++ b/editoast/database/src/tables.rs @@ -597,10 +597,11 @@ diesel::table! { infra_id -> Nullable, uic -> Nullable, #[max_length = 255] - trigram -> Nullable, - ci -> Nullable, - ch -> Nullable, + main_code -> Nullable, + secondary_code -> Nullable, name -> Nullable, + is_passenger_station -> Nullable, + secondary_name -> Nullable, } } diff --git a/editoast/editoast_models/src/infra.rs b/editoast/editoast_models/src/infra.rs index ea6bdb5edbb..e429fffaa06 100644 --- a/editoast/editoast_models/src/infra.rs +++ b/editoast/editoast_models/src/infra.rs @@ -191,8 +191,8 @@ impl Infra { .bind::(self.id) .execute(conn.write().await.deref_mut()).await?; - sql_query("INSERT INTO search_operational_point(id, infra_id, obj_id, uic, trigram, ci, ch, name) - SELECT op.id, $1, op.obj_id, uic, trigram, ci, ch, name FROM search_operational_point + sql_query("INSERT INTO search_operational_point(id, infra_id, obj_id, uic, main_code, secondary_code, name, is_passenger_station, secondary_name) + SELECT op.id, $1, op.obj_id, uic, main_code, secondary_code, name, is_passenger_station, secondary_name FROM search_operational_point JOIN infra_object_operational_point AS op ON search_operational_point.obj_id = op.obj_id and op.infra_id = $1 WHERE search_operational_point.infra_id = $2") .bind::(cloned_infra.id) diff --git a/editoast/editoast_models/src/infra_objects.rs b/editoast/editoast_models/src/infra_objects.rs index 6f4032ebf55..4e8cf6ef006 100644 --- a/editoast/editoast_models/src/infra_objects.rs +++ b/editoast/editoast_models/src/infra_objects.rs @@ -282,10 +282,7 @@ impl OperationalPointModel { Ok(dsl::infra_object_operational_point .filter(dsl::infra_id.eq(infra_id)) - .filter( - sql::>("(data->'extensions'->'identifier'->'uic')::int") - .eq_any(uic), - ) + .filter(sql::>("(data->'uic')::int").eq_any(uic)) .load(&mut conn.write().await) .await? .into_iter() @@ -306,9 +303,7 @@ impl OperationalPointModel { Ok(dsl::infra_object_operational_point .filter(dsl::infra_id.eq(infra_id)) - .filter( - sql::>("data->'extensions'->'sncf'->>'trigram'").eq_any(trigrams), - ) + .filter(sql::>("data->>'main_code'").eq_any(trigrams)) .load(&mut conn.write().await) .await? .into_iter() diff --git a/editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/down.sql b/editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/down.sql new file mode 100644 index 00000000000..c98f23099a5 --- /dev/null +++ b/editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/down.sql @@ -0,0 +1,31 @@ +-- This file should undo anything in `up.sql` +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions}', '{}'::jsonb); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, identifier}', '{}'::jsonb); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, sncf}', '{}'::jsonb); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, identifier, name}', data->'name'); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, identifier, uic}', data->'uic'); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, sncf, trigram}', data->'main_code'); + +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, sncf, ch}', + CASE + WHEN (data->>'is_passenger_station')::boolean THEN '"BV"'::jsonb + ELSE COALESCE(NULLIF(data->'secondary_code', 'null'::jsonb), '""'::jsonb) + END +); + +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, sncf, ch_long_label}', COALESCE(NULLIF(data->'secondary_name', 'null'::jsonb), '""'::jsonb)); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, sncf, ci}', '0'::jsonb); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{extensions, sncf, ch_short_label}', '""'::jsonb); +UPDATE infra_object_operational_point +SET data = data - 'name' - 'uic' - 'main_code' - 'secondary_code' - 'secondary_name' - 'country_code' - 'is_passenger_station' ; +UPDATE infra SET railjson_version = '3.5.2' diff --git a/editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/up.sql b/editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/up.sql new file mode 100644 index 00000000000..e53910e4d1c --- /dev/null +++ b/editoast/migrations/2026-05-05-133055-0000_rename_operational_point_fields/up.sql @@ -0,0 +1,20 @@ +-- Your SQL goes here +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{name}', COALESCE(data->'extensions'->'identifier'->'name', '"name"'::jsonb)); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{uic}', COALESCE(data->'extensions'->'identifier'->'uic', 'null'::jsonb)); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{main_code}', COALESCE(data->'extensions'->'sncf'->'trigram', '"main_code"'::jsonb)); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{secondary_code}', COALESCE(data->'extensions'->'sncf'->'ch', 'null'::jsonb)); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{secondary_name}', COALESCE(data->'extensions'->'sncf'->'ch_long_label', 'null'::jsonb)); +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{country_code}', '"FR"'::jsonb); + +UPDATE infra_object_operational_point +SET data = jsonb_set(data, '{is_passenger_station}', to_jsonb(data->'extensions'->'sncf'->>'ch' = 'BV' OR data->'extensions'->'sncf'->>'ch' = '00')); + +UPDATE infra_object_operational_point +SET data = data - 'extensions'; +UPDATE infra SET railjson_version = '3.5.3' diff --git a/editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/down.sql b/editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/down.sql new file mode 100644 index 00000000000..ef3f892f02e --- /dev/null +++ b/editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/down.sql @@ -0,0 +1,7 @@ +-- DO NOT EDIT THIS FILE MANUALLY! + +DROP TABLE IF EXISTS "search_operational_point"; +DROP TRIGGER IF EXISTS search_operational_point__ins_trig ON "infra_object_operational_point"; +DROP TRIGGER IF EXISTS search_operational_point__upd_trig ON "infra_object_operational_point"; +DROP FUNCTION IF EXISTS search_operational_point__ins_trig_fun; +DROP FUNCTION IF EXISTS search_operational_point__upd_trig_fun; diff --git a/editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/up.sql b/editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/up.sql new file mode 100644 index 00000000000..71807c5a86b --- /dev/null +++ b/editoast/migrations/2026-05-11-140835-0000_search_op_rename_fields/up.sql @@ -0,0 +1,90 @@ +-- DO NOT EDIT THIS FILE MANUALLY! +-- To change the migration's content, use `editoast search make-migration`. +-- To add custom SQL code, check out `#[derive(Search)]` attributes `prepend_sql` and `append_sql`. + +DROP TABLE IF EXISTS "search_operational_point"; + +CREATE TABLE "search_operational_point" ( + id BIGINT PRIMARY KEY REFERENCES "infra_object_operational_point"("id") ON UPDATE CASCADE ON DELETE CASCADE, + "obj_id" varchar(255), + "infra_id" integer, + "uic" integer, + "main_code" varchar(255), + "secondary_code" text, + "name" text, + "is_passenger_station" boolean, + "secondary_name" text +); + +CREATE INDEX "search_operational_point_obj_id" ON "search_operational_point" ("obj_id"); +CREATE INDEX "search_operational_point_infra_id" ON "search_operational_point" ("infra_id"); +CREATE INDEX "search_operational_point_uic" ON "search_operational_point" ("uic"); +CREATE INDEX "search_operational_point_main_code" ON "search_operational_point" ("main_code"); +CREATE INDEX "search_operational_point_secondary_code" ON "search_operational_point" ("secondary_code"); +CREATE INDEX "search_operational_point_name" ON "search_operational_point" USING gin ("name" gin_trgm_ops); +CREATE INDEX "search_operational_point_is_passenger_station" ON "search_operational_point" ("is_passenger_station"); +CREATE INDEX "search_operational_point_secondary_name" ON "search_operational_point" ("secondary_name"); + +CREATE OR REPLACE FUNCTION search_operational_point__ins_trig_fun() + RETURNS TRIGGER + LANGUAGE plpgsql +AS $$ +BEGIN + INSERT INTO "search_operational_point" (id, obj_id, infra_id, uic, main_code, secondary_code, name, is_passenger_station, secondary_name) + SELECT "infra_object_operational_point".id AS id, (infra_object_operational_point.obj_id) AS obj_id, + (infra_object_operational_point.infra_id) AS infra_id, + ((infra_object_operational_point.data->>'uic')::integer) AS uic, + (infra_object_operational_point.data->>'main_code') AS main_code, + (infra_object_operational_point.data->>'secondary_code') AS secondary_code, + osrd_prepare_for_search(infra_object_operational_point.data->>'name') AS name, + ((infra_object_operational_point.data->>'is_passenger_station')::boolean) AS is_passenger_station, + (infra_object_operational_point.data->>'secondary_name') AS secondary_name + FROM (SELECT NEW.*) AS "infra_object_operational_point" + ; + RETURN NEW; +END; +$$; +CREATE OR REPLACE TRIGGER search_operational_point__ins_trig +AFTER INSERT ON "infra_object_operational_point" +FOR EACH ROW EXECUTE FUNCTION search_operational_point__ins_trig_fun(); + + +CREATE OR REPLACE FUNCTION search_operational_point__upd_trig_fun() + RETURNS TRIGGER + LANGUAGE plpgsql +AS $$ +BEGIN + UPDATE "search_operational_point" + SET "obj_id" = (infra_object_operational_point.obj_id), + "infra_id" = (infra_object_operational_point.infra_id), + "uic" = ((infra_object_operational_point.data->>'uic')::integer), + "main_code" = (infra_object_operational_point.data->>'main_code'), + "secondary_code" = (infra_object_operational_point.data->>'secondary_code'), + "name" = osrd_prepare_for_search(infra_object_operational_point.data->>'name'), + "is_passenger_station" = ((infra_object_operational_point.data->>'is_passenger_station')::boolean), + "secondary_name" = (infra_object_operational_point.data->>'secondary_name') + FROM (SELECT NEW.*) AS "infra_object_operational_point" + + WHERE "infra_object_operational_point".id = "search_operational_point".id; + RETURN NEW; +END; +$$; +CREATE OR REPLACE TRIGGER search_operational_point__upd_trig +AFTER UPDATE ON "infra_object_operational_point" +FOR EACH ROW EXECUTE FUNCTION search_operational_point__upd_trig_fun(); + + + +INSERT INTO "search_operational_point" (id, "obj_id", "infra_id", "uic", "main_code", "secondary_code", "name", "is_passenger_station", "secondary_name") +SELECT + "infra_object_operational_point"."id" AS id, + (infra_object_operational_point.obj_id) AS obj_id +, (infra_object_operational_point.infra_id) AS infra_id +, ((infra_object_operational_point.data->>'uic')::integer) AS uic +, (infra_object_operational_point.data->>'main_code') AS main_code +, (infra_object_operational_point.data->>'secondary_code') AS secondary_code +, osrd_prepare_for_search(infra_object_operational_point.data->>'name') AS name +, ((infra_object_operational_point.data->>'is_passenger_station')::boolean) AS is_passenger_station +, (infra_object_operational_point.data->>'secondary_name') AS secondary_name +FROM "infra_object_operational_point" + ; diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml index 354462c4069..8266e719787 100644 --- a/editoast/openapi.yaml +++ b/editoast/openapi.yaml @@ -4288,9 +4288,10 @@ paths: - type properties: secondary_code: - type: - - string - - 'null' + oneOf: + - type: 'null' + - type: string + minLength: 1 description: An optional secondary code to identify a more specific location trigram: oneOf: @@ -4308,9 +4309,10 @@ paths: - type properties: secondary_code: - type: - - string - - 'null' + oneOf: + - type: 'null' + - type: string + minLength: 1 description: An optional secondary code to identify a more specific location type: type: string @@ -11476,13 +11478,26 @@ components: required: - id - parts + - name + - country_code + - main_code + - is_passenger_station properties: - extensions: - $ref: '#/components/schemas/OperationalPointExtensions' + country_code: + type: string + minLength: 1 id: type: string maxLength: 255 minLength: 1 + is_passenger_station: + type: boolean + main_code: + type: string + minLength: 1 + name: + type: string + minLength: 1 parts: type: array items: @@ -11490,38 +11505,29 @@ components: plc: oneOf: - type: 'null' - - $ref: '#/components/schemas/NonBlankString' - description: 'Primary Location Code : https://rne.eu/it/products/ccs/crd/' - weight: - type: - - integer - - 'null' - format: int32 - minimum: 0 - additionalProperties: false - OperationalPointExtensions: - type: object - properties: - identifier: + - type: string + minLength: 1 + description: 'Primary Location Code : https://rne.eu/it/products/ccs/crd/' + secondary_code: oneOf: - type: 'null' - - $ref: '#/components/schemas/OperationalPointIdentifierExtension' - sncf: + - type: string + minLength: 1 + secondary_name: oneOf: - type: 'null' - - $ref: '#/components/schemas/OperationalPointSncfExtension' - additionalProperties: false - OperationalPointIdentifierExtension: - type: object - required: - - name - - uic - properties: - name: - type: string - minLength: 1 + - type: string + minLength: 1 uic: - type: integer + type: + - integer + - 'null' + format: int32 + minimum: 0 + weight: + type: + - integer + - 'null' format: int32 minimum: 0 additionalProperties: false @@ -11598,9 +11604,10 @@ components: - type properties: secondary_code: - type: - - string - - 'null' + oneOf: + - type: 'null' + - type: string + minLength: 1 description: An optional secondary code to identify a more specific location trigram: oneOf: @@ -11618,9 +11625,10 @@ components: - type properties: secondary_code: - type: - - string - - 'null' + oneOf: + - type: 'null' + - type: string + minLength: 1 description: An optional secondary code to identify a more specific location type: type: string @@ -11631,29 +11639,6 @@ components: format: int32 description: The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point minimum: 0 - OperationalPointSncfExtension: - type: object - required: - - ci - - ch - - ch_short_label - - ch_long_label - - trigram - properties: - ch: - type: string - ch_long_label: - type: string - minLength: 1 - ch_short_label: - type: string - minLength: 1 - ci: - type: integer - format: int64 - trigram: - type: string - additionalProperties: false OptionsChangeGroup: type: object required: @@ -12027,7 +12012,72 @@ components: operational_points: type: array items: - $ref: '#/components/schemas/CoreOperationalPointOnPath' + type: object + description: Operational point along a path. + required: + - id + - part + - position + - weight + - name + - uic + - country_code + - main_code + - is_passenger_station + properties: + country_code: + type: string + minLength: 1 + id: + oneOf: + - type: string + maxLength: 255 + minLength: 1 + description: Id of the operational point + is_passenger_station: + type: boolean + main_code: + type: string + minLength: 1 + name: + type: string + minLength: 1 + part: + $ref: '#/components/schemas/OperationalPointPart' + description: The part along the path + plc: + oneOf: + - type: 'null' + - type: string + minLength: 1 + description: 'Primary Location Code : https://rne.eu/it/products/ccs/crd/' + position: + type: integer + format: int64 + description: Distance from the beginning of the path in mm + minimum: 0 + secondary_code: + oneOf: + - type: 'null' + - type: string + minLength: 1 + secondary_name: + oneOf: + - type: 'null' + - type: string + minLength: 1 + uic: + type: integer + format: int32 + minimum: 0 + weight: + type: + - integer + - 'null' + format: int32 + description: Importance of the operational point + maximum: 100 + minimum: 0 description: Operational points along the path slopes: oneOf: @@ -12608,9 +12658,14 @@ components: required: - id - parts + - name + - country_code + - main_code + - is_passenger_station properties: - extensions: - $ref: '#/components/schemas/OperationalPointExtensions' + country_code: + type: string + minLength: 1 geo: oneOf: - type: 'null' @@ -12619,10 +12674,39 @@ components: type: string maxLength: 255 minLength: 1 + is_passenger_station: + type: boolean + main_code: + type: string + minLength: 1 + name: + type: string + minLength: 1 parts: type: array items: $ref: '#/components/schemas/RelatedOperationalPointPart' + plc: + oneOf: + - type: 'null' + - type: string + minLength: 1 + secondary_code: + oneOf: + - type: 'null' + - type: string + minLength: 1 + secondary_name: + oneOf: + - type: 'null' + - type: string + minLength: 1 + uic: + type: + - integer + - 'null' + format: int32 + minimum: 0 weight: type: - integer @@ -13452,34 +13536,44 @@ components: - obj_id - infra_id - uic + - main_code + - secondary_code - name - - trigram - - ch - - ci + - is_passenger_station + - secondary_name - geographic - track_sections properties: - ch: - type: string - ci: - type: integer - format: int64 - minimum: 0 geographic: $ref: '#/components/schemas/GeoJsonPoint' infra_id: type: integer format: int64 + is_passenger_station: + type: boolean + main_code: + type: string name: type: string obj_id: type: string + secondary_code: + type: string + secondary_name: + type: string track_sections: type: array items: - $ref: '#/components/schemas/SearchResultItemOperationalPointTrackSections' - trigram: - type: string + type: object + required: + - track + - position + properties: + position: + type: number + format: double + track: + type: string uic: type: integer format: int64 diff --git a/editoast/osm_to_railjson/src/osm_to_railjson.rs b/editoast/osm_to_railjson/src/osm_to_railjson.rs index 2a5c2cc0c01..7b9d3a7bd8c 100644 --- a/editoast/osm_to_railjson/src/osm_to_railjson.rs +++ b/editoast/osm_to_railjson/src/osm_to_railjson.rs @@ -311,10 +311,8 @@ mod tests { assert_eq!(1, rj.operational_points.len()); let op = &rj.operational_points[0]; assert_eq!(2, op.parts.len()); - let identifier_ext = op.extensions.identifier.as_ref().unwrap(); - assert_eq!("atlantis", identifier_ext.name); - assert_eq!(1234, identifier_ext.uic); - let sncf_ext = op.extensions.sncf.as_ref().unwrap(); - assert_eq!("TRI", sncf_ext.trigram); + assert_eq!("atlantis", op.name); + assert_eq!(Some(1234), op.uic); + assert_eq!("TRI", op.main_code); } } diff --git a/editoast/osm_to_railjson/src/utils.rs b/editoast/osm_to_railjson/src/utils.rs index 0ffdfaa0a0a..d1c6d2dacbb 100644 --- a/editoast/osm_to_railjson/src/utils.rs +++ b/editoast/osm_to_railjson/src/utils.rs @@ -13,10 +13,7 @@ use schemas::infra::Electrification; use schemas::infra::Endpoint; use schemas::infra::LogicalSignal; use schemas::infra::OperationalPoint; -use schemas::infra::OperationalPointExtensions; -use schemas::infra::OperationalPointIdentifierExtension; use schemas::infra::OperationalPointPart; -use schemas::infra::OperationalPointSncfExtension; use schemas::infra::Side; use schemas::infra::Signal; use schemas::infra::SignalExtensions; @@ -527,7 +524,7 @@ pub fn operational_points( .collect(); // Get operational point trigram // Look through the nodes member of the relation and find one that has a "railway:ref" tag - let trigram = rel + let main_code = rel .refs .iter() .filter_map(|r| match r.member { @@ -543,22 +540,21 @@ pub fn operational_points( if parts.is_empty() { None } else { + let (identifier_name, identifier_uic) = identifier(&rel.tags); Some(OperationalPoint { id: rel.id.0.to_string().into(), parts, - extensions: OperationalPointExtensions { - identifier: identifier(&rel.tags), - sncf: Some(OperationalPointSncfExtension { - ci: 0, - ch: String::from("BV"), - ch_short_label: NonBlankString::from("BV"), - ch_long_label: NonBlankString::from("BV"), - trigram - }), - }, weight: None, + name: identifier_name, + uic: Some(identifier_uic), plc: None, + country_code: "FR".into(), + main_code: main_code.into(), + secondary_code: Some("BV".into()), + is_passenger_station: true, + secondary_name: Some("BV".into()), }) + } }) .collect() @@ -568,9 +564,7 @@ pub fn operational_points( // The front crashes when this function return None. // This function will probably be changed when the data model will change. // The necessity of a fake UIC and name should be re-evaluated at that time. -fn identifier( - tags: &osm4routing::osmpbfreader::Tags, -) -> Option { +fn identifier(tags: &osm4routing::osmpbfreader::Tags) -> (NonBlankString, u32) { let uic = tags .get("uic_ref") .and_then(|uic| match u32::from_str(uic.as_str()) { @@ -586,16 +580,11 @@ fn identifier( 11_00000 + UIC_COUNTER.fetch_add(1, Ordering::Relaxed) }); - tags.get("name") - .map(|name| OperationalPointIdentifierExtension { - name: name.as_str().into(), - uic, - }) - .or(Some(OperationalPointIdentifierExtension { - // Generate a fake name from the UIC - name: format!("op_{}", uic).into(), - uic, - })) + tags.get("name").map_or( + // Generate a fake name from the UIC + (format!("op_{}", uic).into(), uic), + |name| (name.as_str().into(), uic), + ) } #[cfg(test)] diff --git a/editoast/schemas/src/infra.rs b/editoast/schemas/src/infra.rs index 7a81fc1189f..865802208e8 100644 --- a/editoast/schemas/src/infra.rs +++ b/editoast/schemas/src/infra.rs @@ -51,11 +51,8 @@ pub use level_crossing::LevelCrossingPart; pub use loading_gauge_limit::LoadingGaugeLimit; pub use neutral_section::NeutralSection; pub use operational_point::OperationalPoint; -pub use operational_point::OperationalPointExtensions; -pub use operational_point::OperationalPointIdentifierExtension; pub use operational_point::OperationalPointPart; pub use operational_point::OperationalPointPartExtension; -pub use operational_point::OperationalPointSncfExtension; pub use railjson::RAILJSON_VERSION; pub use railjson::RailJson; pub use railjson::major_version; diff --git a/editoast/schemas/src/infra/operational_point.rs b/editoast/schemas/src/infra/operational_point.rs index 85415529a74..ee19fd01900 100644 --- a/editoast/schemas/src/infra/operational_point.rs +++ b/editoast/schemas/src/infra/operational_point.rs @@ -17,11 +17,22 @@ pub struct OperationalPoint { pub id: Identifier, pub parts: Vec, #[serde(default)] - pub extensions: OperationalPointExtensions, - #[serde(default)] pub weight: Option, + #[schema(inline)] + pub name: NonBlankString, + pub uic: Option, /// Primary Location Code : https://rne.eu/it/products/ccs/crd/ + #[schema(inline)] pub plc: Option, + #[schema(inline)] + pub country_code: NonBlankString, + #[schema(inline)] + pub main_code: NonBlankString, + #[schema(inline)] + pub secondary_code: Option, + pub is_passenger_station: bool, + #[schema(inline)] + pub secondary_name: Option, } #[derive(Debug, Educe, Clone, PartialEq, Serialize, Deserialize, ToSchema)] @@ -50,45 +61,6 @@ pub struct OperationalPointPartSncfExtension { pub kp: String, } -#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq, ToSchema)] -#[serde(deny_unknown_fields)] -pub struct OperationalPointExtensions { - pub sncf: Option, - pub identifier: Option, -} - -#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq, ToSchema)] -#[serde(deny_unknown_fields)] -pub struct OperationalPointSncfExtension { - pub ci: i64, - pub ch: String, - #[schema(inline)] - pub ch_short_label: NonBlankString, - #[schema(inline)] - pub ch_long_label: NonBlankString, - pub trigram: String, -} - -impl OperationalPointSncfExtension { - pub fn new(ci: i64, ch: &str, trigram: &str) -> Self { - Self { - ci, - ch: ch.into(), - ch_short_label: ch.into(), - ch_long_label: ch.into(), - trigram: trigram.into(), - } - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, ToSchema)] -#[serde(deny_unknown_fields)] -pub struct OperationalPointIdentifierExtension { - #[schema(inline)] - pub name: NonBlankString, - pub uic: u32, -} - impl OSRDTyped for OperationalPoint { fn get_type() -> ObjectType { ObjectType::OperationalPoint @@ -123,15 +95,3 @@ impl OperationalPoint { .collect() } } - -#[cfg(test)] -mod tests { - use serde_json::from_str; - - use super::OperationalPointExtensions; - - #[test] - fn test_op_extensions_deserialization() { - from_str::(r#"{}"#).unwrap(); - } -} diff --git a/editoast/schemas/src/infra/railjson.rs b/editoast/schemas/src/infra/railjson.rs index 4f087af16e0..27c70f4ac45 100644 --- a/editoast/schemas/src/infra/railjson.rs +++ b/editoast/schemas/src/infra/railjson.rs @@ -16,7 +16,7 @@ use super::Switch; use super::SwitchType; use super::TrackSection; -pub const RAILJSON_VERSION: &str = "3.5.2"; +pub const RAILJSON_VERSION: &str = "3.5.3"; /// An infrastructure description in the RailJson format #[derive(Deserialize, Educe, Serialize, Clone, Debug, ToSchema)] diff --git a/editoast/schemas/src/train_schedule.rs b/editoast/schemas/src/train_schedule.rs index 7d9e56f6dac..395bcaa79fb 100644 --- a/editoast/schemas/src/train_schedule.rs +++ b/editoast/schemas/src/train_schedule.rs @@ -240,7 +240,7 @@ impl TrainOccurrence { OperationalPointPartReference { operational_point: OperationalPointReference::Uic { uic: 8711, - secondary_code: Some("BV".to_string()), + secondary_code: Some("BV".into()), }, local_track_name: None, }, @@ -259,7 +259,7 @@ impl TrainOccurrence { OperationalPointPartReference { operational_point: OperationalPointReference::Trigram { trigram: NonBlankString::from("MWS"), - secondary_code: Some("BV".to_string()), + secondary_code: Some("BV".into()), }, local_track_name: None, }, diff --git a/editoast/schemas/src/train_schedule/path_item.rs b/editoast/schemas/src/train_schedule/path_item.rs index c062a66b098..bd8948aada0 100644 --- a/editoast/schemas/src/train_schedule/path_item.rs +++ b/editoast/schemas/src/train_schedule/path_item.rs @@ -68,14 +68,16 @@ pub enum OperationalPointReference { #[schema(inline)] trigram: NonBlankString, /// An optional secondary code to identify a more specific location - secondary_code: Option, + #[schema(inline)] + secondary_code: Option, }, #[schema(title = "OperationalPointReferenceUic")] Uic { /// The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point uic: u32, /// An optional secondary code to identify a more specific location - secondary_code: Option, + #[schema(inline)] + secondary_code: Option, }, } diff --git a/editoast/src/views/infra/mod.rs b/editoast/src/views/infra/mod.rs index 57ccc68bcc3..db94992752c 100644 --- a/editoast/src/views/infra/mod.rs +++ b/editoast/src/views/infra/mod.rs @@ -27,6 +27,7 @@ use geos::Geom; use itertools::Itertools; use schemas::infra::SwitchType; use schemas::primitives::Identifier; +use schemas::primitives::NonBlankString; use serde::Deserialize; use serde::Serialize; use std::collections::HashSet; @@ -53,7 +54,6 @@ use authz::Role; use editoast_models::Infra; use editoast_models::SwitchTypeModel; use schemas::infra::OperationalPoint; -use schemas::infra::OperationalPointExtensions; use schemas::infra::OperationalPointPart; use schemas::infra::builtin_node_types_list; use schemas::train_schedule::OperationalPointReference; @@ -681,11 +681,23 @@ struct RelatedOperationalPoint { id: Identifier, parts: Vec, #[serde(default)] - extensions: OperationalPointExtensions, - #[serde(default)] weight: Option, #[schema(value_type = Option)] geo: Option, + #[schema(inline)] + pub name: NonBlankString, + pub uic: Option, + #[schema(inline)] + pub plc: Option, + #[schema(inline)] + pub country_code: NonBlankString, + #[schema(inline)] + pub main_code: NonBlankString, + #[schema(inline)] + pub secondary_code: Option, + pub is_passenger_station: bool, + #[schema(inline)] + pub secondary_name: Option, } #[derive(Serialize, ToSchema)] @@ -782,9 +794,16 @@ fn build_related_operational_point( geo: geo_points.and_then(|points| points.get(i).cloned()), }) .collect(), - extensions: op.extensions.clone(), weight: op.weight, geo: geo_points.and_then(|points| compute_operational_point_geo(points)), + name: op.name.clone(), + uic: op.uic, + plc: op.plc.clone(), + country_code: op.country_code.clone(), + main_code: op.main_code.clone(), + secondary_code: op.secondary_code.clone(), + is_passenger_station: op.is_passenger_station, + secondary_name: op.secondary_name.clone(), } } diff --git a/editoast/src/views/path/operational_point_cache.rs b/editoast/src/views/path/operational_point_cache.rs index 864075842b2..28d620c0bb0 100644 --- a/editoast/src/views/path/operational_point_cache.rs +++ b/editoast/src/views/path/operational_point_cache.rs @@ -29,7 +29,7 @@ pub struct OperationalPointCache { /// Maps UIC code to indices in the ops Vec uic_to_indices: HashMap>, /// Maps trigram to indices in the ops Vec - trigram_to_indices: HashMap>, + trigram_to_indices: HashMap>, /// Maps obj_id to index in the ops Vec obj_id_to_index: HashMap, track_ids: HashSet, @@ -138,7 +138,7 @@ impl OperationalPointCache { // Step 3: Build index maps from the ops vector let mut obj_id_to_index: HashMap = HashMap::new(); let mut uic_to_indices: HashMap> = HashMap::new(); - let mut trigram_to_indices: HashMap> = HashMap::new(); + let mut trigram_to_indices: HashMap> = HashMap::new(); let track_ids_to_local_track_name: HashMap = HashMap::new(); let track_ids: HashSet = HashSet::new(); @@ -147,20 +147,15 @@ impl OperationalPointCache { obj_id_to_index.insert(op.obj_id.clone(), index); // Build UIC index if present - if let Some(identifier) = &op.extensions.identifier { - uic_to_indices - .entry(identifier.uic) - .or_default() - .push(index); + if let Some(op_uic) = op.uic { + uic_to_indices.entry(op_uic).or_default().push(index); } // Build trigram index if present - if let Some(sncf) = &op.extensions.sncf { - trigram_to_indices - .entry(sncf.trigram.clone()) - .or_default() - .push(index); - } + trigram_to_indices + .entry(op.main_code.clone()) + .or_default() + .push(index); } Ok(OperationalPointCache { @@ -347,7 +342,7 @@ impl OperationalPointCache { pub(crate) fn new( ops: Vec, uic_to_indices: HashMap>, - trigram_to_indices: HashMap>, + trigram_to_indices: HashMap>, obj_id_to_index: HashMap, track_ids: HashSet, track_ids_to_local_track_name: HashMap, @@ -453,47 +448,36 @@ async fn retrieve_op_from_ids( /// If secondary_code is None, searches for an OP without sncf extension. /// If secondary_code is Some, searches for an OP whose sncf extension matches the given code. fn find_op_by_secondary_code<'a>( - secondary_code: Option<&String>, + secondary_code: Option<&NonBlankString>, ops: Vec<&'a OperationalPointModel>, ) -> Option<&'a OperationalPointModel> { ops.into_iter() - .find(|op| secondary_code == op.extensions.sncf.as_ref().map(|sncf| &sncf.ch)) + .find(|op| secondary_code == op.secondary_code.as_ref()) } #[cfg(test)] mod tests { use database::DbConnectionPoolV2; use schemas::infra::OperationalPoint; - use schemas::infra::OperationalPointExtensions; - use schemas::infra::OperationalPointIdentifierExtension; - use schemas::infra::OperationalPointSncfExtension; use schemas::primitives::Identifier; use super::*; use crate::fixtures::create_empty_infra; use crate::fixtures::create_infra_object; - fn create_op(obj_id: &str, trigram: Option<&str>, uic: Option) -> OperationalPoint { - let extensions = OperationalPointExtensions { - sncf: trigram.map(|t| OperationalPointSncfExtension { - ci: 0, - ch: "00".to_string(), - ch_short_label: "Test".into(), - ch_long_label: "Test OP".into(), - trigram: t.to_string(), - }), - identifier: uic.map(|u| OperationalPointIdentifierExtension { - name: "Test OP".into(), - uic: u, - }), - }; - + fn create_op(obj_id: &str, main_code: &str, uic: u32) -> OperationalPoint { OperationalPoint { id: Identifier::from(obj_id), parts: vec![], - extensions, weight: None, + name: "Test OP".into(), + uic: Some(uic), plc: None, + country_code: "FR".into(), + main_code: main_code.into(), + secondary_code: Some("00".into()), + is_passenger_station: false, + secondary_name: Some("Test OP".into()), } } @@ -504,9 +488,9 @@ mod tests { let infra = create_empty_infra(&mut conn).await; // Create three operational points with different identifier combinations - let op1 = create_op("op_1", Some("ABC"), Some(1234)); - let op2 = create_op("op_2", Some("DEF"), None); // No UIC - let op3 = create_op("op_3", None, Some(5678)); // No trigram + let op1 = create_op("op_1", "ABC", 1234); + let op2 = create_op("op_2", "DEF", 91011); // UIC not revelant + let op3 = create_op("op_3", "HIJ", 5678); // trigram not revelant // Insert OPs into the database create_infra_object(&mut conn, infra.id, op1).await; diff --git a/editoast/src/views/projection.rs b/editoast/src/views/projection.rs index 3144ee02ad5..8bdcadbdd47 100644 --- a/editoast/src/views/projection.rs +++ b/editoast/src/views/projection.rs @@ -1147,7 +1147,7 @@ mod tests { fn create_path_item_from_trigram(trigram: &str) -> OperationalPointReference { OperationalPointReference::Trigram { trigram: trigram.into(), - secondary_code: Some("BV".to_string()), + secondary_code: Some("BV".into()), } } diff --git a/editoast/src/views/search.rs b/editoast/src/views/search.rs index d0d2235ae1a..5fac3140b2a 100644 --- a/editoast/src/views/search.rs +++ b/editoast/src/views/search.rs @@ -445,28 +445,33 @@ pub(super) struct SearchResultItemTrack { column( name = "uic", data_type = "integer", - sql = "(infra_object_operational_point.data->'extensions'->'identifier'->>'uic')::integer", + sql = "(infra_object_operational_point.data->>'uic')::integer", ), column( - name = "trigram", - data_type = "varchar(3)", - sql = "infra_object_operational_point.data->'extensions'->'sncf'->>'trigram'", - ), - column( - name = "ci", - data_type = "integer", - sql = "(infra_object_operational_point.data->'extensions'->'sncf'->>'ci')::integer", + name = "main_code", + data_type = "varchar(255)", + sql = "infra_object_operational_point.data->>'main_code'", ), column( - name = "ch", + name = "secondary_code", data_type = "text", - sql = "infra_object_operational_point.data->'extensions'->'sncf'->>'ch'", + sql = "infra_object_operational_point.data->>'secondary_code'", ), column( name = "name", data_type = "text", - sql = "infra_object_operational_point.data->'extensions'->'identifier'->>'name'", + sql = "infra_object_operational_point.data->>'name'", textual_search, + ), + column( + name = "is_passenger_station", + data_type = "boolean", + sql = "(infra_object_operational_point.data->>'is_passenger_station')::boolean", + ), + column( + name = "secondary_name", + data_type = "text", + sql = "infra_object_operational_point.data->>'secondary_name'", ) )] /// A search result item for a query with `object = "operationalpoint"` @@ -477,16 +482,18 @@ pub(super) struct SearchResultItemOperationalPoint { obj_id: String, #[search(sql = "OP.infra_id")] infra_id: i64, - #[search(sql = "OP.data->'extensions'->'identifier'->'uic'")] + #[search(sql = "OP.data->'uic'")] uic: i64, - #[search(sql = "OP.data#>>'{extensions,identifier,name}'")] + #[search(sql = "OP.data#>>'{main_code}'")] + main_code: String, + #[search(sql = "OP.data#>>'{secondary_code}'")] + secondary_code: String, + #[search(sql = "OP.data#>>'{name}'")] name: String, - #[search(sql = "OP.data#>>'{extensions,sncf,trigram}'")] - trigram: String, - #[search(sql = "OP.data#>>'{extensions,sncf,ch}'")] - ch: String, - #[search(sql = "OP.data#>>'{extensions,sncf,ci}'")] - ci: u64, + #[search(sql = "OP.data->'is_passenger_station'")] + is_passenger_station: bool, + #[search(sql = "OP.data#>>'{secondary_name}'")] + secondary_name: String, #[search(sql = "ST_AsGeoJSON(ST_Transform(lay.geographic, 4326))::json")] #[schema(value_type = GeoJsonPoint)] geographic: Geometry, diff --git a/editoast/src/views/timetable/stdcm.rs b/editoast/src/views/timetable/stdcm.rs index d2d4f670346..e34d2ac17c7 100644 --- a/editoast/src/views/timetable/stdcm.rs +++ b/editoast/src/views/timetable/stdcm.rs @@ -630,7 +630,7 @@ mod tests { OperationalPointPartReference { operational_point: OperationalPointReference::Trigram { trigram: "WS".into(), - secondary_code: Some("BV".to_string()), + secondary_code: Some("BV".into()), }, local_track_name: None, }, @@ -648,7 +648,7 @@ mod tests { OperationalPointPartReference { operational_point: OperationalPointReference::Trigram { trigram: "MWS".into(), - secondary_code: Some("BV".to_string()), + secondary_code: Some("BV".into()), }, local_track_name: None, }, @@ -702,7 +702,7 @@ mod tests { OperationalPointPartReference { operational_point: OperationalPointReference::Trigram { trigram: trigram.into(), - secondary_code: Some("BV".to_string()), + secondary_code: Some("BV".into()), }, local_track_name: None, }, diff --git a/editoast/src/views/timetable/train_schedule.rs b/editoast/src/views/timetable/train_schedule.rs index b663054ed37..091e0012d6c 100644 --- a/editoast/src/views/timetable/train_schedule.rs +++ b/editoast/src/views/timetable/train_schedule.rs @@ -1854,7 +1854,7 @@ mod tests { pub fn new_op_with_trigram_and_local_track_name( id: &str, trigram: &str, - secondary_code: Option, + secondary_code: Option, local_track_name: Option, ) -> PathItem { PathItem { diff --git a/front/public/locales/en/infraEditor.json b/front/public/locales/en/infraEditor.json index 159c60816d6..61d02beda84 100644 --- a/front/public/locales/en/infraEditor.json +++ b/front/public/locales/en/infraEditor.json @@ -411,10 +411,26 @@ "OperationalPoint": { "description": "This class describes the operational points of the corresponding infra.", "properties": { + "country_code": { + "description": "Country code of the operational point (E.g: FR for France)", + "title": "Country code" + }, "id": { "description": "Unique identifier of the object", "title": "Id" }, + "is_passenger_station": { + "description": "Whether or not the operational point is a passenger station", + "title": "Is passenger station" + }, + "main_code": { + "description": "Unique code of the operational point (E.g : trigram for SNCF)", + "title": "Main code" + }, + "name": { + "description": "Name of the operational point", + "title": "Name" + }, "parts": { "title": "Parts" }, @@ -422,28 +438,24 @@ "description": "Primary Location Code : https://rne.eu/it/products/ccs/crd/", "title": "Plc" }, - "weight": { - "description": "represents the significance of a PR", - "title": "Weight" - } - }, - "title": "Operational point" - }, - "OperationalPointExtensions": { - "title": "Operational point extensions" - }, - "OperationalPointIdentifierExtension": { - "properties": { - "name": { - "description": "Name of the operational point", - "title": "Name" + "secondary_code": { + "description": "THOR site code of the operational point", + "title": "Secondary code" + }, + "secondary_name": { + "description": "THOR site code long label of the operational point", + "title": "Secondary name" }, "uic": { "description": "International Union of Railways code of the operational point", "title": "Uic" + }, + "weight": { + "description": "represents the significance of a PR", + "title": "Weight" } }, - "title": "Operational point identifier extension" + "title": "Operational point" }, "OperationalPointPart": { "description": "Operational point part is a single point on the infrastructure. It's linked to an operational point.", @@ -475,31 +487,6 @@ }, "title": "Operational point part sncf extension" }, - "OperationalPointSncfExtension": { - "properties": { - "ch": { - "description": "THOR site code of the operational point", - "title": "Ch" - }, - "ch_long_label": { - "description": "THOR site code long label of the operational point", - "title": "Ch long label" - }, - "ch_short_label": { - "description": "THOR site code short label of the operational point", - "title": "Ch short label" - }, - "ci": { - "description": "THOR immutable code of the operational point", - "title": "Ci" - }, - "trigram": { - "description": "Unique SNCF trigram of the operational point", - "title": "Trigram" - } - }, - "title": "Operational point sncf extension" - }, "Route": { "description": "This class is used to describe routes on the infrastructure.", "properties": { diff --git a/front/src/common/api/generatedEditoastApi.ts b/front/src/common/api/generatedEditoastApi.ts index 4f96141b9b8..f0f7008f4eb 100644 --- a/front/src/common/api/generatedEditoastApi.ts +++ b/front/src/common/api/generatedEditoastApi.ts @@ -2673,14 +2673,14 @@ export type PostTrainSchedulesProjectPathOpApiArg = { } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; /** The operational point trigram */ trigram: string; type: 'trigram'; } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; type: 'uic'; /** The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point */ uic: number; @@ -3029,21 +3029,6 @@ export type NeutralSection = { lower_pantograph: boolean; track_ranges: DirectionalTrackRange[]; }; -export type OperationalPointIdentifierExtension = { - name: string; - uic: number; -}; -export type OperationalPointSncfExtension = { - ch: string; - ch_long_label: string; - ch_short_label: string; - ci: number; - trigram: string; -}; -export type OperationalPointExtensions = { - identifier?: null | OperationalPointIdentifierExtension; - sncf?: null | OperationalPointSncfExtension; -}; export type OperationalPointPartSncfExtension = { kp: string; }; @@ -3059,10 +3044,17 @@ export type OperationalPointPart = { track: string; }; export type OperationalPoint = { - extensions?: OperationalPointExtensions; + country_code: string; id: string; + is_passenger_station: boolean; + main_code: string; + name: string; parts: OperationalPointPart[]; - plc?: null | NonBlankString; + /** Primary Location Code : https://rne.eu/it/products/ccs/crd/ */ + plc?: null | string; + secondary_code?: null | string; + secondary_name?: null | string; + uic?: number | null; weight?: number | null; }; export type Waypoint = @@ -3466,10 +3458,17 @@ export type RelatedOperationalPointPart = OperationalPointPart & { geo?: null | GeoJsonPoint; }; export type RelatedOperationalPoint = { - extensions?: OperationalPointExtensions; + country_code: string; geo?: null | GeoJsonPoint; id: string; + is_passenger_station: boolean; + main_code: string; + name: string; parts: RelatedOperationalPointPart[]; + plc?: null | string; + secondary_code?: null | string; + secondary_name?: null | string; + uic?: number | null; weight?: number | null; }; export type OperationalPointReference = @@ -3480,14 +3479,14 @@ export type OperationalPointReference = } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; /** The operational point trigram */ trigram: string; type: 'trigram'; } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; type: 'uic'; /** The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point */ uic: number; @@ -3568,7 +3567,25 @@ export type PathProperties = { /** Geometry of the path */ geometry: GeoJsonLineString; /** Operational points along the path */ - operational_points: CoreOperationalPointOnPath[]; + operational_points: { + country_code: string; + /** Id of the operational point */ + id: string; + is_passenger_station: boolean; + main_code: string; + name: string; + /** The part along the path */ + part: OperationalPointPart; + /** Primary Location Code : https://rne.eu/it/products/ccs/crd/ */ + plc?: null | string; + /** Distance from the beginning of the path in mm */ + position: number; + secondary_code?: null | string; + secondary_name?: null | string; + uic: number; + /** Importance of the operational point */ + weight: number | null; + }[]; /** Slopes along the path */ slopes: { /** List of `n` boundaries of the ranges. @@ -4222,14 +4239,18 @@ export type SearchResultItemOperationalPointTrackSections = { track: string; }; export type SearchResultItemOperationalPoint = { - ch: string; - ci: number; geographic: GeoJsonPoint; infra_id: number; + is_passenger_station: boolean; + main_code: string; name: string; obj_id: string; - track_sections: SearchResultItemOperationalPointTrackSections[]; - trigram: string; + secondary_code: string; + secondary_name: string; + track_sections: { + position: number; + track: string; + }[]; uic: number; }; export type SearchResultItemSignal = { diff --git a/front/src/common/api/osrdRailwayManagerApi.ts b/front/src/common/api/osrdRailwayManagerApi.ts index 38109ae8d86..a9495a2cc7e 100644 --- a/front/src/common/api/osrdRailwayManagerApi.ts +++ b/front/src/common/api/osrdRailwayManagerApi.ts @@ -101,14 +101,14 @@ export type Items = { } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; /** The operational point trigram */ trigram: string; type: 'trigram'; } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; type: 'uic'; /** The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point */ uic: number; @@ -206,14 +206,14 @@ export type TransformTimetableResponse = { } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; /** The operational point trigram */ trigram: string; type: 'trigram'; } | { /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; + secondary_code?: null | string; type: 'uic'; /** The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point */ uic: number; diff --git a/front/src/reducers/osrdconf/infra_schema.json b/front/src/reducers/osrdconf/infra_schema.json index 4357e52866d..3ce6b4af298 100644 --- a/front/src/reducers/osrdconf/infra_schema.json +++ b/front/src/reducers/osrdconf/infra_schema.json @@ -898,9 +898,11 @@ "OperationalPoint": { "description": "This class describes the operational points of the corresponding infra.", "properties": { - "extensions": { - "$ref": "#/$defs/OperationalPointExtensions", - "default": null + "country_code": { + "description": "Country code of the operational point (E.g: FR for France)", + "minLength": 1, + "title": "Country Code", + "type": "string" }, "id": { "description": "Unique identifier of the object", @@ -909,6 +911,24 @@ "title": "Id", "type": "string" }, + "is_passenger_station": { + "description": "Whether or not the operational point is a passenger station", + "title": "Is Passenger Station", + "type": "boolean" + }, + "main_code": { + "description": "Unique code of the operational point (E.g : trigram for SNCF)", + "maxLength": 255, + "minLength": 1, + "title": "Main Code", + "type": "string" + }, + "name": { + "description": "Name of the operational point", + "minLength": 1, + "title": "Name", + "type": "string" + }, "parts": { "items": { "$ref": "#/$defs/OperationalPointPart" @@ -929,6 +949,45 @@ "description": "Primary Location Code : https://rne.eu/it/products/ccs/crd/", "title": "Plc" }, + "secondary_code": { + "anyOf": [ + { + "maxLength": 255, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "THOR site code of the operational point", + "title": "Secondary Code" + }, + "secondary_name": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "THOR site code long label of the operational point", + "title": "Secondary Name" + }, + "uic": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "International Union of Railways code of the operational point", + "title": "Uic" + }, "weight": { "anyOf": [ { @@ -947,44 +1006,16 @@ "required": [ "id", "parts", - "plc" - ], - "title": "OperationalPoint", - "type": "object" - }, - "OperationalPointExtensions": { - "properties": { - "identifier": { - "$ref": "#/$defs/OperationalPointIdentifierExtension", - "default": null - }, - "sncf": { - "$ref": "#/$defs/OperationalPointSncfExtension", - "default": null - } - }, - "title": "OperationalPointExtensions", - "type": "object" - }, - "OperationalPointIdentifierExtension": { - "properties": { - "name": { - "description": "Name of the operational point", - "minLength": 1, - "title": "Name", - "type": "string" - }, - "uic": { - "description": "International Union of Railways code of the operational point", - "title": "Uic", - "type": "integer" - } - }, - "required": [ "name", - "uic" + "uic", + "plc", + "country_code", + "main_code", + "secondary_code", + "is_passenger_station", + "secondary_name" ], - "title": "OperationalPointIdentifierExtension", + "title": "OperationalPoint", "type": "object" }, "OperationalPointPart": { @@ -1046,50 +1077,6 @@ "title": "OperationalPointPartSncfExtension", "type": "object" }, - "OperationalPointSncfExtension": { - "properties": { - "ch": { - "description": "THOR site code of the operational point", - "maxLength": 2, - "minLength": 1, - "title": "Ch", - "type": "string" - }, - "ch_long_label": { - "description": "THOR site code long label of the operational point", - "minLength": 1, - "title": "Ch Long Label", - "type": "string" - }, - "ch_short_label": { - "description": "THOR site code short label of the operational point", - "minLength": 1, - "title": "Ch Short Label", - "type": "string" - }, - "ci": { - "description": "THOR immutable code of the operational point", - "title": "Ci", - "type": "integer" - }, - "trigram": { - "description": "Unique SNCF trigram of the operational point", - "maxLength": 3, - "minLength": 1, - "title": "Trigram", - "type": "string" - } - }, - "required": [ - "ci", - "ch", - "ch_short_label", - "ch_long_label", - "trigram" - ], - "title": "OperationalPointSncfExtension", - "type": "object" - }, "Route": { "description": "This class is used to describe routes on the infrastructure.", "properties": { @@ -2167,8 +2154,8 @@ "type": "array" }, "version": { - "const": "3.5.2", - "default": "3.5.2", + "const": "3.5.3", + "default": "3.5.3", "description": "Version of the schema", "title": "Version", "type": "string" diff --git a/osrd_schemas_auto/osrd_schemas_auto/models.py b/osrd_schemas_auto/osrd_schemas_auto/models.py index d3e55fccc81..ca689c8ed1e 100644 --- a/osrd_schemas_auto/osrd_schemas_auto/models.py +++ b/osrd_schemas_auto/osrd_schemas_auto/models.py @@ -2557,10 +2557,6 @@ class NewDocumentResponse(BaseModel): document_key: int -class NonBlankString(RootModel[str]): - root: Annotated[str, Field(min_length=1)] - - class ObjectType(Enum): TrackSection = "TrackSection" Signal = "Signal" @@ -2597,12 +2593,19 @@ class OperationDelete(BaseModel): operation_type: Literal["DELETE"] -class OperationalPointIdentifierExtension(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - name: Annotated[str, Field(min_length=1)] - uic: Annotated[int, Field(ge=0)] +class Plc(RootModel[str]): + root: Annotated[str, Field(min_length=1)] + """ + Primary Location Code : https://rne.eu/it/products/ccs/crd/ + """ + + +class SecondaryCode(RootModel[str]): + root: Annotated[str, Field(min_length=1)] + + +class SecondaryName(RootModel[str]): + root: Annotated[str, Field(min_length=1)] class LocalTrackName(RootModel[str]): @@ -2624,8 +2627,15 @@ class OperationalPointReferenceId(BaseModel): type: Literal["id"] +class SecondaryCode1(RootModel[str]): + root: Annotated[str, Field(min_length=1)] + """ + An optional secondary code to identify a more specific location + """ + + class OperationalPointReferenceTrigram(BaseModel): - secondary_code: str | None = None + secondary_code: SecondaryCode1 | None = None """ An optional secondary code to identify a more specific location """ @@ -2637,7 +2647,7 @@ class OperationalPointReferenceTrigram(BaseModel): class OperationalPointReferenceUic(BaseModel): - secondary_code: str | None = None + secondary_code: SecondaryCode1 | None = None """ An optional secondary code to identify a more specific location """ @@ -2648,17 +2658,6 @@ class OperationalPointReferenceUic(BaseModel): """ -class OperationalPointSncfExtension(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - ch: str - ch_long_label: Annotated[str, Field(min_length=1)] - ch_short_label: Annotated[str, Field(min_length=1)] - ci: int - trigram: str - - class PaginationStats(BaseModel): """ Statistics about a paginated editoast response @@ -2796,6 +2795,10 @@ class Electrifications(BaseModel): """ +class SecondaryCode3(RootModel[str]): + root: Annotated[str, Field(min_length=1)] + + class Slopes(BaseModel): """ Property f64 values along a path. Each value is associated to a range of the path. @@ -2911,6 +2914,10 @@ class RefillLaw(BaseModel): tau: Annotated[float, Field(ge=0.0)] +class Plc2(RootModel[str]): + root: Annotated[str, Field(min_length=1)] + + class RemoveOperation(BaseModel): """ JSON Patch 'remove' operation representation @@ -5097,14 +5104,15 @@ class SearchResultItemOperationalPoint(BaseModel): """ - ch: str - ci: Annotated[int, Field(ge=0)] geographic: GeoJsonPoint infra_id: int + is_passenger_station: bool + main_code: str name: str obj_id: str track_sections: list[SearchResultItemOperationalPointTrackSections] - trigram: str + secondary_code: str + secondary_name: str uic: int @@ -5722,6 +5730,71 @@ class PathItem(BaseModel): """ +class OperationalPoint2(BaseModel): + """ + Operational point along a path. + """ + + country_code: Annotated[str, Field(min_length=1)] + id: str + """ + Id of the operational point + """ + is_passenger_station: bool + main_code: Annotated[str, Field(min_length=1)] + name: Annotated[str, Field(min_length=1)] + part: OperationalPointPart + """ + The part along the path + """ + plc: Plc | None = None + """ + Primary Location Code : https://rne.eu/it/products/ccs/crd/ + """ + position: Annotated[int, Field(ge=0)] + """ + Distance from the beginning of the path in mm + """ + secondary_code: SecondaryCode3 | None = None + secondary_name: SecondaryName | None = None + uic: Annotated[int, Field(ge=0)] + weight: Annotated[int | None, Field(ge=0, le=100)] = None + """ + Importance of the operational point + """ + + +class PathProperties(BaseModel): + """ + Properties along a path. Each property is optional since it depends on what the user requests. + """ + + curves: Curves + """ + Curves along the path + """ + electrifications: Electrifications + """ + Electrification modes and neutral section along the path + """ + geometry: GeoJsonLineString + """ + Geometry of the path + """ + operational_points: list[OperationalPoint2] + """ + Operational points along the path + """ + slopes: Slopes + """ + Slopes along the path + """ + zones: Zones + """ + Zones along the path + """ + + class PathfindingFailurePathfindingInputError(BaseModel): failed_status: Literal["pathfinding_input_error"] @@ -6097,10 +6170,19 @@ class OperationalPoint(BaseModel): model_config = ConfigDict( extra="forbid", ) - extensions: OperationalPointExtensions | None = None + country_code: Annotated[str, Field(min_length=1)] id: Annotated[str, Field(max_length=255, min_length=1)] + is_passenger_station: bool + main_code: Annotated[str, Field(min_length=1)] + name: Annotated[str, Field(min_length=1)] parts: list[OperationalPointPart] - plc: NonBlankString | None = None + plc: Plc | None = None + """ + Primary Location Code : https://rne.eu/it/products/ccs/crd/ + """ + secondary_code: SecondaryCode | None = None + secondary_name: SecondaryName | None = None + uic: Annotated[int | None, Field(ge=0)] = None weight: Annotated[int | None, Field(ge=0)] = None @@ -6217,10 +6299,17 @@ class RailJson(BaseModel): class RelatedOperationalPoint(BaseModel): - extensions: OperationalPointExtensions | None = None + country_code: Annotated[str, Field(min_length=1)] geo: GeoJsonPoint | None = None id: Annotated[str, Field(max_length=255, min_length=1)] + is_passenger_station: bool + main_code: Annotated[str, Field(min_length=1)] + name: Annotated[str, Field(min_length=1)] parts: list[RelatedOperationalPointPart] + plc: Plc2 | None = None + secondary_code: SecondaryCode3 | None = None + secondary_name: SecondaryName | None = None + uic: Annotated[int | None, Field(ge=0)] = None weight: Annotated[int | None, Field(ge=0)] = None diff --git a/python/osrd_schemas/osrd_schemas/infra.py b/python/osrd_schemas/osrd_schemas/infra.py index 2b5f58c11e1..3a2c8ec07dd 100755 --- a/python/osrd_schemas/osrd_schemas/infra.py +++ b/python/osrd_schemas/osrd_schemas/infra.py @@ -8,7 +8,7 @@ ALL_OBJECT_TYPES = [] -RAILJSON_INFRA_VERSION_TYPE = Literal["3.5.2"] +RAILJSON_INFRA_VERSION_TYPE = Literal["3.5.3"] RAILJSON_INFRA_VERSION = get_args(RAILJSON_INFRA_VERSION_TYPE)[0] # Traits @@ -221,9 +221,32 @@ class OperationalPoint(BaseObjectTrait): weight: Optional[int] = Field( description="represents the significance of a PR", ge=0, default=None ) + name: NonBlankStr = Field(description="Name of the operational point") + uic: Optional[int] = Field( + description="International Union of Railways code of the operational point" + ) plc: Optional[NonBlankStr] = Field( description="Primary Location Code : https://rne.eu/it/products/ccs/crd/" ) + country_code: NonBlankStr = Field( + description="Country code of the operational point (E.g: FR for France)" + ) + main_code: NonBlankStr = Field( + description="Unique code of the operational point (E.g : trigram for SNCF)", + min_length=1, + max_length=255, + ) + secondary_code: Optional[NonBlankStr] = Field( + description="THOR site code of the operational point", + min_length=1, + max_length=255, + ) + is_passenger_station: bool = Field( + description="Whether or not the operational point is a passenger station" + ) + secondary_name: Optional[NonBlankStr] = Field( + description="THOR site code long label of the operational point" + ) class LevelCrossingPart(TrackLocationTrait): @@ -701,40 +724,11 @@ class TrackSectionSourceExtension(BaseModel): id: str = Field(description="ID used for the line in the source") -@register_extension(object=OperationalPoint, name="sncf") -class OperationalPointSncfExtension(BaseModel): - ci: int = Field(description="THOR immutable code of the operational point") - ch: str = Field( - description="THOR site code of the operational point", - min_length=1, - max_length=2, - ) - ch_short_label: NonBlankStr = Field( - description="THOR site code short label of the operational point" - ) - ch_long_label: NonBlankStr = Field( - description="THOR site code long label of the operational point" - ) - trigram: str = Field( - description="Unique SNCF trigram of the operational point", - min_length=1, - max_length=3, - ) - - @register_extension(object=OperationalPointPart, name="sncf") class OperationalPointPartSncfExtension(BaseModel): kp: str = Field(description="Kilometric point of the operational point part") -@register_extension(object=OperationalPoint, name="identifier") -class OperationalPointIdentifierExtension(BaseModel): - name: NonBlankStr = Field(description="Name of the operational point") - uic: int = Field( - description="International Union of Railways code of the operational point" - ) - - @register_extension(object=Switch, name="sncf") class SwitchSncfExtension(BaseModel): label: NonBlankStr = Field(description="Identifier of the switch") diff --git a/python/osrd_schemas/pyproject.toml b/python/osrd_schemas/pyproject.toml index dc1dcf65d9f..6ffe2a52e8a 100644 --- a/python/osrd_schemas/pyproject.toml +++ b/python/osrd_schemas/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "osrd_schemas" -version = "0.11.1" +version = "0.11.2" description = "" authors = [{ name = "OSRD Contributors", email = "contact@osrd.fr" }] requires-python = ">= 3.11" diff --git a/python/osrd_schemas/uv.lock b/python/osrd_schemas/uv.lock index d5a459dc2a8..d97a3d72736 100644 --- a/python/osrd_schemas/uv.lock +++ b/python/osrd_schemas/uv.lock @@ -34,7 +34,7 @@ wheels = [ [[package]] name = "osrd-schemas" -version = "0.11.1" +version = "0.11.2" source = { editable = "." } dependencies = [ { name = "geojson-pydantic" }, diff --git a/python/railjson_generator/railjson_generator/schema/infra/infra.py b/python/railjson_generator/railjson_generator/schema/infra/infra.py index 8e51f749987..4cb69f9c734 100644 --- a/python/railjson_generator/railjson_generator/schema/infra/infra.py +++ b/python/railjson_generator/railjson_generator/schema/infra/infra.py @@ -26,7 +26,7 @@ class Infra: electrifications: List[Electrification] = field(default_factory=list) neutral_sections: List[NeutralSection] = field(default_factory=list) - VERSION = "3.5.2" + VERSION = "3.5.3" def add_route(self, *args, **kwargs): self.routes.append(Route(*args, **kwargs)) @@ -86,21 +86,15 @@ def make_rjs_operational_points(self): new_op = models.OperationalPoint( id=op.id, parts=parts_per_op[op.id], - extensions=models.OperationalPointExtensions( - sncf=models.OperationalPointSncfExtension( - ci=int(str(op.uic)[2:]), # remove two first digits of UIC code - ch_short_label=op.ch, - ch=op.ch, - ch_long_label="0", - trigram=op.trigram, - ), - identifier=models.OperationalPointIdentifierExtension( - uic=op.uic, - name=op.label, - ), - ), weight=op.weight, + name=op.label, + uic=op.uic, plc=models.NonBlankString(op.plc) if op.plc is not None else None, + country_code=op.country_code, + main_code=op.main_code, + secondary_code=op.secondary_code, + is_passenger_station=op.is_passenger_station, + secondary_name="0", ) ops.append(new_op) return ops diff --git a/python/railjson_generator/railjson_generator/schema/infra/operational_point.py b/python/railjson_generator/railjson_generator/schema/infra/operational_point.py index 60f27ff064f..4fb377e78b3 100644 --- a/python/railjson_generator/railjson_generator/schema/infra/operational_point.py +++ b/python/railjson_generator/railjson_generator/schema/infra/operational_point.py @@ -10,33 +10,39 @@ @dataclass class OperationalPoint: - label: str - trigram: str + label: NonBlankStr + id: str parts: List weight: Optional[int] - uic: int - ch: str - id: str + uic: Optional[int] plc: Optional[NonBlankStr] + country_code: NonBlankStr + main_code: NonBlankStr + secondary_code: Optional[NonBlankStr] + is_passenger_station: bool def __init__( self, label: str, id: Optional[str] = None, - trigram: Optional[str] = None, - uic: int = 8700, - weight: Optional[int] = None, - ch: str = "BV", + main_code: Optional[NonBlankStr] = None, + uic: Optional[int] = 8700, plc: Optional[NonBlankStr] = None, + weight: Optional[int] = None, + secondary_code: Optional[NonBlankStr] = "BV", + country_code: NonBlankStr = "FR", + is_passenger_station: bool = True, ): self.label = label - self.trigram = trigram or label[:3].upper() + self.main_code = main_code or label[:3].upper() self.parts = list() self.uic = uic self.weight = weight self.id = id or label - self.ch = ch + self.secondary_code = secondary_code self.plc = plc + self.country_code = country_code + self.is_passenger_station = is_passenger_station def add_part(self, track, offset, local_track_name): op_part = OperationalPointPart(self, offset, local_track_name) diff --git a/python/railjson_generator/uv.lock b/python/railjson_generator/uv.lock index be29a71eebe..4c8553bcb95 100644 --- a/python/railjson_generator/uv.lock +++ b/python/railjson_generator/uv.lock @@ -382,7 +382,7 @@ wheels = [ [[package]] name = "osrd-schemas" -version = "0.11.1" +version = "0.11.2" source = { editable = "../osrd_schemas" } dependencies = [ { name = "geojson-pydantic" }, diff --git a/tests/data/infras/etcs_infra/infra.json b/tests/data/infras/etcs_infra/infra.json index 297d9975fa3..e5d2dd8b750 100644 --- a/tests/data/infras/etcs_infra/infra.json +++ b/tests/data/infras/etcs_infra/infra.json @@ -827,19 +827,6 @@ ], "operational_points": [ { - "extensions": { - "identifier": { - "name": "West_station", - "uic": 8722 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 22, - "trigram": "WS" - } - }, "id": "West_station", "parts": [ { @@ -858,23 +845,17 @@ "track": "TA2" } ], + "weight": null, + "name": "West_station", + "uic": 8722, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "WS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_West_station", - "uic": 8711 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 11, - "trigram": "SWS" - } - }, "id": "South_West_station", "parts": [ { @@ -883,23 +864,17 @@ "track": "TB0" } ], + "weight": null, + "name": "South_West_station", + "uic": 8711, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SWS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "Mid_West_station", - "uic": 8733 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 33, - "trigram": "MWS" - } - }, "id": "Mid_West_station", "parts": [ { @@ -923,23 +898,17 @@ "track": "TC3" } ], + "weight": null, + "name": "Mid_West_station", + "uic": 8733, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "MWS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "Mid_East_station", - "uic": 8744 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 44, - "trigram": "MES" - } - }, "id": "Mid_East_station", "parts": [ { @@ -953,23 +922,17 @@ "track": "TD1" } ], + "weight": null, + "name": "Mid_East_station", + "uic": 8744, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "MES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "North_station", - "uic": 8755 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 55, - "trigram": "NS" - } - }, "id": "North_station", "parts": [ { @@ -983,23 +946,17 @@ "track": "TE2" } ], + "weight": null, + "name": "North_station", + "uic": 8755, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "NS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_station", - "uic": 8766 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 66, - "trigram": "SS" - } - }, "id": "South_station", "parts": [ { @@ -1008,23 +965,17 @@ "track": "TF1" } ], + "weight": null, + "name": "South_station", + "uic": 8766, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "North_East_station", - "uic": 8777 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 77, - "trigram": "NES" - } - }, "id": "North_East_station", "parts": [ { @@ -1038,23 +989,17 @@ "track": "TG5" } ], + "weight": null, + "name": "North_East_station", + "uic": 8777, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "NES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_East_station", - "uic": 8788 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 88, - "trigram": "SES" - } - }, "id": "South_East_station", "parts": [ { @@ -1063,8 +1008,15 @@ "track": "TH1" } ], + "weight": null, + "name": "South_East_station", + "uic": 8788, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" } ], "routes": [ @@ -6666,5 +6618,5 @@ "slopes": [] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/data/infras/example_script/infra.json b/tests/data/infras/example_script/infra.json index 07d0e398aaf..da7aae3a8c0 100644 --- a/tests/data/infras/example_script/infra.json +++ b/tests/data/infras/example_script/infra.json @@ -79,19 +79,6 @@ "neutral_sections": [], "operational_points": [ { - "extensions": { - "identifier": { - "name": "my-op", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "MY-" - } - }, "id": "my-op", "parts": [ { @@ -105,8 +92,15 @@ "track": "track.1" } ], + "weight": null, + "name": "my-op", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "MY-", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" } ], "routes": [ @@ -1260,5 +1254,5 @@ "slopes": [] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/data/infras/medium_infra/infra.json b/tests/data/infras/medium_infra/infra.json index 4b2910e90a0..4f6852d9b4b 100644 --- a/tests/data/infras/medium_infra/infra.json +++ b/tests/data/infras/medium_infra/infra.json @@ -836,19 +836,6 @@ ], "operational_points": [ { - "extensions": { - "identifier": { - "name": "North_West_station", - "uic": 8799 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 99, - "trigram": "NWS" - } - }, "id": "North_West_station", "parts": [ { @@ -857,23 +844,17 @@ "track": "TI0" } ], + "weight": null, + "name": "North_West_station", + "uic": 8799, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "NWS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "North_West_station", - "uic": 8799 - }, - "sncf": { - "ch": "BC", - "ch_long_label": "0", - "ch_short_label": "BC", - "ci": 99, - "trigram": "NWS" - } - }, "id": "North_West_station_1", "parts": [ { @@ -882,23 +863,17 @@ "track": "TI1" } ], + "weight": null, + "name": "North_West_station", + "uic": 8799, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "NWS", + "secondary_code": "BC", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "West_station", - "uic": 8722 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 22, - "trigram": "WS" - } - }, "id": "West_station", "parts": [ { @@ -917,23 +892,17 @@ "track": "TA2" } ], + "weight": null, + "name": "West_station", + "uic": 8722, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "WS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_West_station", - "uic": 8711 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 11, - "trigram": "SWS" - } - }, "id": "South_West_station", "parts": [ { @@ -942,23 +911,17 @@ "track": "TB0" } ], + "weight": null, + "name": "South_West_station", + "uic": 8711, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SWS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "Mid_West_station", - "uic": 8733 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 33, - "trigram": "MWS" - } - }, "id": "Mid_West_station", "parts": [ { @@ -982,23 +945,17 @@ "track": "TC3" } ], + "weight": null, + "name": "Mid_West_station", + "uic": 8733, "plc": null, - "weight": 4 + "country_code": "FR", + "main_code": "MWS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "Mid_East_station", - "uic": 8744 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 44, - "trigram": "MES" - } - }, "id": "Mid_East_station", "parts": [ { @@ -1012,23 +969,17 @@ "track": "TD1" } ], + "weight": null, + "name": "Mid_East_station", + "uic": 8744, "plc": null, - "weight": 10 + "country_code": "FR", + "main_code": "MES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "North_station", - "uic": 8755 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 55, - "trigram": "NS" - } - }, "id": "North_station", "parts": [ { @@ -1042,23 +993,17 @@ "track": "TE2" } ], + "weight": null, + "name": "North_station", + "uic": 8755, "plc": null, - "weight": 3 + "country_code": "FR", + "main_code": "NS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_station", - "uic": 8766 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 66, - "trigram": "SS" - } - }, "id": "South_station", "parts": [ { @@ -1067,23 +1012,17 @@ "track": "TF1" } ], + "weight": null, + "name": "South_station", + "uic": 8766, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "North_East_station", - "uic": 8777 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 77, - "trigram": "NES" - } - }, "id": "North_East_station", "parts": [ { @@ -1097,23 +1036,17 @@ "track": "TG5" } ], + "weight": null, + "name": "North_East_station", + "uic": 8777, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "NES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_East_station", - "uic": 8788 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 88, - "trigram": "SES" - } - }, "id": "South_East_station", "parts": [ { @@ -1122,8 +1055,15 @@ "track": "TH1" } ], + "weight": null, + "name": "South_East_station", + "uic": 8788, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" } ], "routes": [ @@ -7351,5 +7291,5 @@ "slopes": [] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/data/infras/nested_switches/infra.json b/tests/data/infras/nested_switches/infra.json index dbc2dc153b1..7771736cd56 100644 --- a/tests/data/infras/nested_switches/infra.json +++ b/tests/data/infras/nested_switches/infra.json @@ -932,5 +932,5 @@ "slopes": [] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/data/infras/overlapping_routes/infra.json b/tests/data/infras/overlapping_routes/infra.json index 3b2a698c657..c8752f6b96b 100644 --- a/tests/data/infras/overlapping_routes/infra.json +++ b/tests/data/infras/overlapping_routes/infra.json @@ -64,19 +64,6 @@ "neutral_sections": [], "operational_points": [ { - "extensions": { - "identifier": { - "name": "op.a1", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.a1", "parts": [ { @@ -85,23 +72,17 @@ "track": "t_a1" } ], + "weight": null, + "name": "op.a1", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "op.a2", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.a2", "parts": [ { @@ -110,23 +91,17 @@ "track": "t_a2" } ], + "weight": null, + "name": "op.a2", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "op.b1", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.b1", "parts": [ { @@ -135,23 +110,17 @@ "track": "t_b1" } ], + "weight": null, + "name": "op.b1", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "op.b2", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.b2", "parts": [ { @@ -160,8 +129,15 @@ "track": "t_b2" } ], + "weight": null, + "name": "op.b2", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" } ], "routes": [ @@ -782,5 +758,5 @@ "slopes": [] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/data/infras/small_infra/infra.json b/tests/data/infras/small_infra/infra.json index 61a85b6f132..10e041cb505 100644 --- a/tests/data/infras/small_infra/infra.json +++ b/tests/data/infras/small_infra/infra.json @@ -827,19 +827,6 @@ ], "operational_points": [ { - "extensions": { - "identifier": { - "name": "West_station", - "uic": 8722 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 22, - "trigram": "WS" - } - }, "id": "West_station", "parts": [ { @@ -858,23 +845,17 @@ "track": "TA2" } ], + "weight": null, + "name": "West_station", + "uic": 8722, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "WS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_West_station", - "uic": 8711 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 11, - "trigram": "SWS" - } - }, "id": "South_West_station", "parts": [ { @@ -883,23 +864,17 @@ "track": "TB0" } ], + "weight": null, + "name": "South_West_station", + "uic": 8711, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SWS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "Mid_West_station", - "uic": 8733 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 33, - "trigram": "MWS" - } - }, "id": "Mid_West_station", "parts": [ { @@ -923,23 +898,17 @@ "track": "TC3" } ], + "weight": null, + "name": "Mid_West_station", + "uic": 8733, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "MWS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "Mid_East_station", - "uic": 8744 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 44, - "trigram": "MES" - } - }, "id": "Mid_East_station", "parts": [ { @@ -953,23 +922,17 @@ "track": "TD1" } ], + "weight": null, + "name": "Mid_East_station", + "uic": 8744, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "MES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "North_station", - "uic": 8755 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 55, - "trigram": "NS" - } - }, "id": "North_station", "parts": [ { @@ -983,23 +946,17 @@ "track": "TE2" } ], + "weight": null, + "name": "North_station", + "uic": 8755, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "NS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_station", - "uic": 8766 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 66, - "trigram": "SS" - } - }, "id": "South_station", "parts": [ { @@ -1008,23 +965,17 @@ "track": "TF1" } ], + "weight": null, + "name": "South_station", + "uic": 8766, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SS", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "North_East_station", - "uic": 8777 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 77, - "trigram": "NES" - } - }, "id": "North_East_station", "parts": [ { @@ -1038,23 +989,17 @@ "track": "TG5" } ], + "weight": null, + "name": "North_East_station", + "uic": 8777, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "NES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "South_East_station", - "uic": 8788 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 88, - "trigram": "SES" - } - }, "id": "South_East_station", "parts": [ { @@ -1063,8 +1008,15 @@ "track": "TH1" } ], + "weight": null, + "name": "South_East_station", + "uic": 8788, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "SES", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" } ], "routes": [ @@ -6878,5 +6830,5 @@ "slopes": [] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/data/infras/tiny_infra/infra.json b/tests/data/infras/tiny_infra/infra.json index c879023711e..d3a73fb167f 100644 --- a/tests/data/infras/tiny_infra/infra.json +++ b/tests/data/infras/tiny_infra/infra.json @@ -44,19 +44,6 @@ "neutral_sections": [], "operational_points": [ { - "extensions": { - "identifier": { - "name": "op.station_foo", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.station_foo", "parts": [ { @@ -70,23 +57,17 @@ "track": "ne.micro.foo_b" } ], + "weight": null, + "name": "op.station_foo", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "op.station_bar", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.station_bar", "parts": [ { @@ -95,8 +76,15 @@ "track": "ne.micro.bar_a" } ], + "weight": null, + "name": "op.station_bar", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" } ], "routes": [ @@ -577,5 +565,5 @@ ] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/data/infras/y_infra/infra.json b/tests/data/infras/y_infra/infra.json index 3e49dc228d7..835a41356d6 100644 --- a/tests/data/infras/y_infra/infra.json +++ b/tests/data/infras/y_infra/infra.json @@ -79,19 +79,6 @@ "neutral_sections": [], "operational_points": [ { - "extensions": { - "identifier": { - "name": "op.a", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.a", "parts": [ { @@ -100,8 +87,15 @@ "track": "t_a" } ], + "weight": null, + "name": "op.a", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { "extensions": { @@ -125,23 +119,17 @@ "track": "t_b" } ], + "weight": null, + "name": "op.b", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" }, { - "extensions": { - "identifier": { - "name": "op.c", - "uic": 8700 - }, - "sncf": { - "ch": "BV", - "ch_long_label": "0", - "ch_short_label": "BV", - "ci": 0, - "trigram": "OP." - } - }, "id": "op.c", "parts": [ { @@ -150,8 +138,15 @@ "track": "t_center" } ], + "weight": null, + "name": "op.c", + "uic": 8700, "plc": null, - "weight": null + "country_code": "FR", + "main_code": "OP.", + "secondary_code": "BV", + "is_passenger_station": true, + "secondary_name": "0" } ], "routes": [ @@ -813,5 +808,5 @@ "slopes": [] } ], - "version": "3.5.2" + "version": "3.5.3" } diff --git a/tests/infra-scripts/medium_infra.py b/tests/infra-scripts/medium_infra.py index 735d89ace6b..90fcceab803 100644 --- a/tests/infra-scripts/medium_infra.py +++ b/tests/infra-scripts/medium_infra.py @@ -130,12 +130,12 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: pi1.set_coords(-0.37, LAT_0) north_west = builder.add_operational_point( - label="North_West_station", trigram="NWS", uic=8799 + label="North_West_station", main_code="NWS", uic=8799 ) north_west_1 = builder.add_operational_point( label="North_West_station", - trigram="NWS", - ch="BC", + main_code="NWS", + secondary_code="BC", uic=8799, id="North_West_station_1", ) @@ -192,7 +192,7 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: ta7, "A7", signaling_system, Direction.STOP_TO_START, 200.0, -200.0 ) # Station - west = builder.add_operational_point(label="West_station", trigram="WS", uic=8722) + west = builder.add_operational_point(label="West_station", main_code="WS", uic=8722) west.add_part(ta0, 699.99959, "V1") # To be rounded to 700 west.add_part(ta1, 500, "V2") west.add_part(ta2, 500, "A") @@ -220,7 +220,7 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: tb0.set_remaining_coords([(-0.4, 49.49), (-0.373, 49.49), (-0.37, 49.492)]) south_west = builder.add_operational_point( label="South_West_station", - trigram="SWS", + main_code="SWS", uic=8711, ) south_west.add_part(tb0, 500, "A") @@ -323,7 +323,7 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: ) # Station mid_west = builder.add_operational_point( - label="Mid_West_station", trigram="MWS", uic=8733, weight=4 + label="Mid_West_station", main_code="MWS", uic=8733, weight=4 ) mid_west.add_part(tc0, 550, "V1bis") mid_west.add_part(tc1, 550, "V1") @@ -385,7 +385,7 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: ) # Station mid_east = builder.add_operational_point( - label="Mid_East_station", trigram="MES", uic=8744, weight=10 + label="Mid_East_station", main_code="MES", uic=8744, weight=10 ) mid_east.add_part(td0, 14000, "V1") mid_east.add_part(td1, 14000, "V2") @@ -479,7 +479,7 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: te3.set_remaining_coords([(-0.145, LAT_0 + 0.002), (-0.145, LAT_3 - 0.002)]) # Station north = builder.add_operational_point( - label="North_station", trigram="NS", uic=8755, weight=3 + label="North_station", main_code="NS", uic=8755, weight=3 ) north.add_part(te1, 1000, "V1bis") north.add_part(te2, 1025, "V1") @@ -496,7 +496,9 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: # Around station F: South # ================================ tf1.set_remaining_coords([(-0.172, 49.47), (-0.167, 49.466), (-0.135, 49.466)]) - south = builder.add_operational_point(label="South_station", trigram="SS", uic=8766) + south = builder.add_operational_point( + label="South_station", main_code="SS", uic=8766 + ) south.add_part(tf1, 4300, "V1") place_regular_signals_detectors( tf1, "F1", signaling_system, min_offset=200.0, max_offset=4300.0 @@ -542,7 +544,7 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: tg5.set_remaining_coords([(-0.09, LAT_4 - LAT_LINE_SPACE)]) tg3.add_detector(label="DG7", position=tg3.length / 2) north_east = builder.add_operational_point( - label="North_East_station", trigram="NES", uic=8777 + label="North_East_station", main_code="NES", uic=8777 ) north_east.add_part(tg4, 1550, "V1") north_east.add_part(tg5, 1500, "V2") @@ -618,7 +620,7 @@ def create_medium_infra(signaling_system: str) -> ScenarioData: ) # Station south_east = builder.add_operational_point( - label="South_East_station", trigram="SES", uic=8788 + label="South_East_station", main_code="SES", uic=8788 ) south_east.add_part(th1, 4400, "V1") # ================================ diff --git a/tests/infra-scripts/small_infra_creator/__init__.py b/tests/infra-scripts/small_infra_creator/__init__.py index b25a157e358..6f343015774 100755 --- a/tests/infra-scripts/small_infra_creator/__init__.py +++ b/tests/infra-scripts/small_infra_creator/__init__.py @@ -197,7 +197,7 @@ def create_small_infra(signaling_system: str) -> ScenarioData: ta7, "A7", signaling_system, Direction.STOP_TO_START, 200.0, -200.0 ) # Station - west = builder.add_operational_point(label="West_station", trigram="WS", uic=8722) + west = builder.add_operational_point(label="West_station", main_code="WS", uic=8722) west.add_part(ta0, 699.99959, "V1") # To be rounded to 700 west.add_part(ta1, 500, "V2") west.add_part(ta2, 500, "V3") @@ -224,7 +224,7 @@ def create_small_infra(signaling_system: str) -> ScenarioData: tb0.set_remaining_coords([(-0.4, 49.49), (-0.373, 49.49), (-0.37, 49.492)]) south_west = builder.add_operational_point( label="South_West_station", - trigram="SWS", + main_code="SWS", uic=8711, ) south_west.add_part(tb0, 500, "V1") @@ -328,7 +328,7 @@ def create_small_infra(signaling_system: str) -> ScenarioData: ) # Station mid_west = builder.add_operational_point( - label="Mid_West_station", trigram="MWS", uic=8733 + label="Mid_West_station", main_code="MWS", uic=8733 ) mid_west.add_part(tc0, 550, "V1") mid_west.add_part(tc1, 550, "V2") @@ -390,7 +390,7 @@ def create_small_infra(signaling_system: str) -> ScenarioData: ) # Station mid_east = builder.add_operational_point( - label="Mid_East_station", trigram="MES", uic=8744 + label="Mid_East_station", main_code="MES", uic=8744 ) mid_east.add_part(td0, 14000, "V1") mid_east.add_part(td1, 14000, "V2") @@ -483,7 +483,9 @@ def create_small_infra(signaling_system: str) -> ScenarioData: ) te3.set_remaining_coords([(-0.145, LAT_0 + 0.002), (-0.145, LAT_3 - 0.002)]) # Station - north = builder.add_operational_point(label="North_station", trigram="NS", uic=8755) + north = builder.add_operational_point( + label="North_station", main_code="NS", uic=8755 + ) north.add_part(te1, 1000, "V1") north.add_part(te2, 1025, "V2") # Curves @@ -499,7 +501,9 @@ def create_small_infra(signaling_system: str) -> ScenarioData: # Around station F: South # ================================ tf1.set_remaining_coords([(-0.172, 49.47), (-0.167, 49.466), (-0.135, 49.466)]) - south = builder.add_operational_point(label="South_station", trigram="SS", uic=8766) + south = builder.add_operational_point( + label="South_station", main_code="SS", uic=8766 + ) south.add_part(tf1, 4300, "V1") place_regular_signals_detectors( tf1, "F1", signaling_system, min_offset=200.0, max_offset=4300.0 @@ -545,7 +549,7 @@ def create_small_infra(signaling_system: str) -> ScenarioData: tg5.set_remaining_coords([(-0.09, LAT_4 - LAT_LINE_SPACE)]) tg3.add_detector(label="DG7", position=tg3.length / 2) north_east = builder.add_operational_point( - label="North_East_station", trigram="NES", uic=8777 + label="North_East_station", main_code="NES", uic=8777 ) north_east.add_part(tg4, 1550, "V1") north_east.add_part(tg5, 1500, "V2") @@ -621,7 +625,7 @@ def create_small_infra(signaling_system: str) -> ScenarioData: ) # Station south_east = builder.add_operational_point( - label="South_East_station", trigram="SES", uic=8788 + label="South_East_station", main_code="SES", uic=8788 ) south_east.add_part(th1, 4400, "V1") # ================================ diff --git a/tests/tests/test_pathfinding.py b/tests/tests/test_pathfinding.py index 310774a683c..5b8f9af89ec 100644 --- a/tests/tests/test_pathfinding.py +++ b/tests/tests/test_pathfinding.py @@ -263,18 +263,16 @@ def test_start_ws_v1_path(session: Session, small_infra: Infra): "sncf": None, }, }, - "extensions": { - "sncf": { - "ci": 22, - "ch": "BV", - "ch_short_label": "BV", - "ch_long_label": "0", - "trigram": "WS", - }, - "identifier": {"name": "West_station", "uic": 8722}, - }, - "position": 0, "weight": None, + "name": "West_station", + "uic": 8722, + "plc": None, + "country_code": "FR", + "main_code": "WS", + "secondary_code": "BV", + "is_passenger_station": True, + "secondary_name": "0", + "position": 0, } ], "zones": { diff --git a/tests/uv.lock b/tests/uv.lock index 37cde0346a2..cf1f45782cf 100644 --- a/tests/uv.lock +++ b/tests/uv.lock @@ -489,7 +489,7 @@ wheels = [ [[package]] name = "osrd-schemas" -version = "0.11.1" +version = "0.11.2" source = { editable = "../python/osrd_schemas" } dependencies = [ { name = "geojson-pydantic" }, From aaf8bad604bb1deb9351282d1aedbeca4e9149b4 Mon Sep 17 00:00:00 2001 From: Duc Nguyen Date: Tue, 5 May 2026 12:13:51 +0200 Subject: [PATCH 02/13] front: rename operational point fields Previous fields : `trigram` is now `main_code` `ch` is now `secondary_code` `ch_long_label` is now `secondary_name` New fields : `country_code` : "FR" as example for the France `is_passenger_station` as a boolean Signed-off-by: Duc Nguyen front: rename operational point fields Previous fields : `trigram` is now `main_code` `ch` is now `secondary_code` `ch_long_label` is now `secondary_name` New fields : `country_code` : "FR" as example for the France `is_passenger_station` as a boolean Signed-off-by: Duc Nguyen --- .../locales/de/operational-studies.json | 4 +- .../locales/en/operational-studies.json | 4 +- .../locales/fr/operational-studies.json | 4 +- ...ertMapWaypointsInOperationalPoints.spec.ts | 154 ++++++++---------- .../helpers/rankingSuggestions.ts | 6 +- .../helpers/searchPayload.ts | 12 +- .../helpers/suggestionMatchers.ts | 6 +- .../upsertMapWaypointsInOperationalPoints.ts | 15 +- .../hooks/useOperationalPointSearch.ts | 2 +- .../hooks/usePathProjection.ts | 27 ++- .../applications/operationalStudies/utils.ts | 8 +- .../MacroEditor/MacroEditorState.ts | 8 +- .../components/MacroEditor/ngeToOsrd/node.ts | 16 +- .../components/MacroEditor/osrdToNge.ts | 6 +- .../Scenario/components/MacroEditor/utils.ts | 6 +- .../ListElementComponent.tsx | 4 +- .../Itinerary/ItineraryModal.tsx | 4 +- .../Itinerary/hooks/usePathStepsMetadata.ts | 6 +- .../ManageTrainSchedule/Itinerary/utils.ts | 12 +- .../AddPathStepPopup.tsx | 6 +- .../OperationalPointPopupDetails.tsx | 6 +- .../helpers/buildOpSuggestion.ts | 15 +- .../Scenario/components/RoundTrips/utils.ts | 4 +- .../SimulationResultsExport/utils.ts | 10 +- .../SimulationResultsMap.tsx | 4 +- .../DebugView/DebugSpaceTimeChart.tsx | 4 +- .../StdcmForm/StdcmLinkedTrainResults.tsx | 2 +- .../StdcmForm/StdcmOperationalPoint.tsx | 16 +- .../components/StdcmResults/StdcmResults.tsx | 6 +- .../StdcmResults/StdcmResultsTable.tsx | 4 +- .../stdcm/hooks/useLinkedTrainSearch.ts | 2 +- front/src/applications/stdcm/types.ts | 6 +- .../__tests__/filterMissingFields.spec.ts | 4 +- .../utils/addSecondaryCodesToSimilarTrains.ts | 4 +- front/src/applications/stdcm/utils/index.ts | 2 +- .../stdcm/utils/simulationOutputUtils.ts | 2 +- .../InfraObjectLayers/OperationalPoints.tsx | 14 +- .../Map/Search/MapSearchOperationalPoint.tsx | 27 ++- .../__tests__/sortOperationalPoints.spec.ts | 91 ++++++----- .../Map/Search/sortOperationalPoints.ts | 32 ++-- .../Map/Search/useSearchOperationalPoint.tsx | 56 ++++--- front/src/common/api/osrdRailwayManagerApi.ts | 8 +- .../utils/formatSimulationReportSheet.ts | 2 +- .../Itinerary/ModalSuggestedVias.tsx | 4 +- .../components/Pathfinding/TypeAndPath.tsx | 73 ++++----- .../pathfinding/hooks/usePathfinding.ts | 10 +- front/src/modules/pathfinding/utils.ts | 43 +++-- .../SpaceTimeChartWrapper.tsx | 4 +- .../SpaceTimeChartWrapper/WaypointsPanel.tsx | 6 +- .../useGetProjectedTrainOperationalPoints.ts | 5 +- .../useTrackOccupancy.ts | 18 +- .../__tests__/helpers.spec.ts | 20 +-- .../SpeedDistanceDiagram/helpers.ts | 4 +- .../helpers/__tests__/utils.spec.ts | 124 +++++++------- front/src/modules/timesStops/helpers/utils.ts | 8 +- .../timesStops/hooks/useOutputTableData.ts | 12 +- .../timesStops/hooks/useTimesStopsColumns.tsx | 2 +- .../hooks/useTimesStopsTableData.ts | 14 +- front/src/modules/timesStops/types.ts | 4 +- front/src/modules/trainSchedule/types.ts | 4 +- front/src/reducers/osrdconf/helpers.ts | 2 +- .../src/reducers/osrdconf/stdcmConf/index.ts | 7 +- .../stdcmConf/stdcmConfReducers.spec.ts | 10 +- front/src/reducers/osrdconf/types.ts | 4 +- .../operationalStudies/_waypointsPanel.scss | 2 +- .../styles/scss/common/map/_mapSearch.scss | 4 +- front/src/utils/inputManipulation.ts | 2 +- .../001-paced-train-management.spec.ts | 4 +- ...003-paced-train-occurrence-edition.spec.ts | 4 +- .../002-op-route-tab.spec.ts | 22 +-- .../003-op-times-and-stops-tab.spec.ts | 19 +++ .../004-op-simulation-settings-tab.spec.ts | 19 +++ .../get-manchette-component.ts | 4 +- .../pages/operational-studies/route-tab.ts | 48 +++--- .../ListElementComponent.tsx | 4 +- .../ComboBoxCustomSuggestions.stories.tsx | 34 ++-- front/ui/ui-charts/src/manchette/types.ts | 2 +- 77 files changed, 606 insertions(+), 571 deletions(-) diff --git a/front/public/locales/de/operational-studies.json b/front/public/locales/de/operational-studies.json index 7eeabd93159..f958386a656 100644 --- a/front/public/locales/de/operational-studies.json +++ b/front/public/locales/de/operational-studies.json @@ -413,8 +413,8 @@ "title_on": "{{count}} von {{total}} verletzten Beschränkungen" }, "infraLoading": "Infrastruktur wird geladen…", - "inputOPTrigrams": "Geben Sie die Kürzel der zu durchfahrenden Betriebsstellen ein, getrennt durch Leerzeichen.", - "inputOPTrigramsExample": "Bsp.: HHA HGÖ FKS", + "inputOPMainCodes": "Geben Sie die Kürzel der zu durchfahrenden Betriebsstellen ein, getrennt durch Leerzeichen.", + "inputOPMainCodesExample": "Bsp.: HHA HGÖ FKS", "invalidTrainScheduleStep": "Mindestens ein Wegepunkt konnte nicht erkannt werden.", "inverseOD": "Route umkehren", "itineraryModal": { diff --git a/front/public/locales/en/operational-studies.json b/front/public/locales/en/operational-studies.json index fa23d7a344b..1504fe2a024 100644 --- a/front/public/locales/en/operational-studies.json +++ b/front/public/locales/en/operational-studies.json @@ -407,8 +407,8 @@ "title_on": "{{count}} on {{total}} incompatible constraints" }, "infraLoading": "Infrastructure is loading…", - "inputOPTrigrams": "Enter the trigrams of operational points you want to the path to go through, separated by a space.", - "inputOPTrigramsExample": "E.g., LSN CIG CCS", + "inputOPMainCodes": "Enter the trigrams of operational points you want to the path to go through, separated by a space.", + "inputOPMainCodesExample": "E.g., LSN CIG CCS", "invalidTrainScheduleStep": "At least one of the waypoints could not be recognized", "inverseOD": "Reverse itinerary", "itineraryModal": { diff --git a/front/public/locales/fr/operational-studies.json b/front/public/locales/fr/operational-studies.json index 5a92e2db08e..dab813b9b91 100644 --- a/front/public/locales/fr/operational-studies.json +++ b/front/public/locales/fr/operational-studies.json @@ -407,8 +407,8 @@ "title_on": "{{count}} sur {{total}} contraintes incompatibles" }, "infraLoading": "Infra en cours de chargement…", - "inputOPTrigrams": "Entrez la liste des trigrammes des points remarquables composant l'itinéraire souhaité.", - "inputOPTrigramsExample": "Ex : LSN CIG CCS", + "inputOPMainCodes": "Entrez la liste des trigrammes des points remarquables composant l'itinéraire souhaité.", + "inputOPMainCodesExample": "Ex : LSN CIG CCS", "invalidTrainScheduleStep": "Au moins un des points de passage n'a pas été reconnu", "inverseOD": "Inverser l'itinéraire", "itineraryModal": { diff --git a/front/src/applications/operationalStudies/__tests__/upsertMapWaypointsInOperationalPoints.spec.ts b/front/src/applications/operationalStudies/__tests__/upsertMapWaypointsInOperationalPoints.spec.ts index 4d5f0271223..96366c47021 100644 --- a/front/src/applications/operationalStudies/__tests__/upsertMapWaypointsInOperationalPoints.spec.ts +++ b/front/src/applications/operationalStudies/__tests__/upsertMapWaypointsInOperationalPoints.spec.ts @@ -22,17 +22,16 @@ type Op = { const getOperationalPoints = (inputs: Op[]): NonNullable => inputs.map((op) => ({ id: op.name, + name: op.name, + uic: op.uic, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: op.track, position: op.positionOnTrack, local_track_name: 'V1', }, - extensions: { - identifier: { - name: op.name, - uic: op.uic, - }, - }, position: op.positionOnPath, weight: null, })); @@ -108,28 +107,26 @@ describe('upsertMapWaypointsInOperationalPoints', () => { expect(operationalPointsWithAllWaypoints).toEqual([ { id: 'West_station', + name: 'West_station', + uic: 2, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TA1', position: 500, local_track_name: 'V1', }, - extensions: { - identifier: { - name: 'West_station', - uic: 2, - }, - }, position: 0, weight: null, }, { id: '2', - extensions: { - identifier: { - name: 't_requestedPoint', - uic: 0, - }, - }, + name: 't_requestedPoint', + uic: 0, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TA6', position: 7746000, @@ -140,33 +137,31 @@ describe('upsertMapWaypointsInOperationalPoints', () => { }, { id: 'Mid_West_station', + name: 'Mid_West_station', + uic: 3, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TC1', position: 550, local_track_name: 'V1', }, - extensions: { - identifier: { - name: 'Mid_West_station', - uic: 3, - }, - }, position: 12050000, weight: null, }, { id: 'Mid_East_station', + name: 'Mid_East_station', + uic: 4, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TD0', position: 14000, local_track_name: 'V1', }, - extensions: { - identifier: { - name: 'Mid_East_station', - uic: 4, - }, - }, position: 26500000, weight: null, }, @@ -221,12 +216,11 @@ describe('upsertMapWaypointsInOperationalPoints', () => { expect(operationalPointsWithAllWaypoints).toEqual([ { id: '1', - extensions: { - identifier: { - name: 't_requestedOrigin', - uic: 0, - }, - }, + name: 't_requestedOrigin', + uic: 0, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TA6', position: 6481000, @@ -237,28 +231,26 @@ describe('upsertMapWaypointsInOperationalPoints', () => { }, { id: 'Mid_West_station', + name: 'Mid_West_station', + uic: 3, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TC0', position: 550, local_track_name: 'V1', }, - extensions: { - identifier: { - name: 'Mid_West_station', - uic: 3, - }, - }, position: 4069000, weight: null, }, { id: '2', - extensions: { - identifier: { - name: 't_requestedPoint', - uic: 0, - }, - }, + name: 't_requestedPoint', + uic: 0, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TC0', position: 679000, @@ -269,12 +261,11 @@ describe('upsertMapWaypointsInOperationalPoints', () => { }, { id: '3', - extensions: { - identifier: { - name: 't_requestedDestination', - uic: 0, - }, - }, + name: 't_requestedDestination', + uic: 0, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TC0', position: 883000, @@ -318,12 +309,11 @@ describe('upsertMapWaypointsInOperationalPoints', () => { expect(operationalPointsWithAllWaypoints).toEqual([ { id: '1', - extensions: { - identifier: { - name: 't_requestedOrigin', - uic: 0, - }, - }, + name: 't_requestedOrigin', + uic: 0, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TA6', position: 6481000, @@ -334,12 +324,11 @@ describe('upsertMapWaypointsInOperationalPoints', () => { }, { id: '2', - extensions: { - identifier: { - name: 't_requestedDestination', - uic: 0, - }, - }, + name: 't_requestedDestination', + uic: 0, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TA6', position: 4733000, @@ -400,49 +389,46 @@ describe('upsertMapWaypointsInOperationalPoints', () => { expect(operationalPointsWithAllWaypoints).toEqual([ { id: 'West_station', + name: 'West_station', + uic: 2, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TA1', position: 500, local_track_name: 'V1', }, - extensions: { - identifier: { - name: 'West_station', - uic: 2, - }, - }, position: 0, weight: null, }, { id: 'Mid_West_station', + name: 'Mid_West_station', + uic: 3, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TC1', position: 550, local_track_name: 'V1', }, - extensions: { - identifier: { - name: 'Mid_West_station', - uic: 3, - }, - }, position: 12050000, weight: null, }, { id: 'Mid_East_station', + name: 'Mid_East_station', + uic: 4, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: 'TD0', position: 14000, local_track_name: 'V1', }, - extensions: { - identifier: { - name: 'Mid_East_station', - uic: 4, - }, - }, position: 26500000, weight: null, }, diff --git a/front/src/applications/operationalStudies/helpers/rankingSuggestions.ts b/front/src/applications/operationalStudies/helpers/rankingSuggestions.ts index 3b7374928d6..211ff752c3f 100644 --- a/front/src/applications/operationalStudies/helpers/rankingSuggestions.ts +++ b/front/src/applications/operationalStudies/helpers/rankingSuggestions.ts @@ -28,7 +28,7 @@ export const rankSingleTokenSuggestions = ( const exactNames = suggestions.filter((s) => normalizeName(s.name) === tokenNormalized); - const trigramExact = suggestions.filter((s) => toUpper(s.trigram) === tokenUpper); + const trigramExact = suggestions.filter((s) => toUpper(s.mainCode) === tokenUpper); if (trigramExact.length && endWithSpace) return uniqBy(trigramExact, 'id'); const trigramStarts: OperationalPointSuggestion[] = []; @@ -41,7 +41,7 @@ export const rankSingleTokenSuggestions = ( for (const s of suggestions) { const nameNorm = normalizeName(s.name); - const trigramUpper = toUpper(s.trigram); + const trigramUpper = toUpper(s.mainCode); if (trigramUpper.startsWith(tokenUpper)) trigramStarts.push(s); if (nameNorm.startsWith(tokenNormalized)) nameStarts.push(s); if (trigramUpper.includes(tokenUpper)) trigramIncludes.push(s); @@ -111,7 +111,7 @@ export const rankMultiTokenSuggestions = ( for (const s of sortingBase) { const nameNorm = normalizeName(s.name); - const trigramUpper = toUpper(s.trigram); + const trigramUpper = toUpper(s.mainCode); const hasSecondaryCodePrefix = secondaryCodeStarts(s, lastTokenUpper); // Trigram pinned diff --git a/front/src/applications/operationalStudies/helpers/searchPayload.ts b/front/src/applications/operationalStudies/helpers/searchPayload.ts index a44d9906743..6e0220ab578 100644 --- a/front/src/applications/operationalStudies/helpers/searchPayload.ts +++ b/front/src/applications/operationalStudies/helpers/searchPayload.ts @@ -2,10 +2,10 @@ import { toUpper } from 'utils/strings'; export const tokenClause = (token: string) => [ 'or', - ['=', ['trigram'], toUpper(token)], + ['=', ['main_code'], toUpper(token)], ['search', ['name'], token], - ['search', ['trigram'], token], - ['search', ['ch'], token], + ['search', ['main_code'], token], + ['search', ['secondary_code'], token], ]; export const buildMultiTokenQuery = (tokens: string[]) => ['and', ...tokens.map(tokenClause)]; @@ -13,8 +13,8 @@ export const buildMultiTokenQuery = (tokens: string[]) => ['and', ...tokens.map( export const searchQuery = (debouncedTrimmedInput: string) => [ 'or', ['search', ['name'], debouncedTrimmedInput], - ['search', ['trigram'], debouncedTrimmedInput], - ['search', ['ch'], debouncedTrimmedInput], + ['search', ['main_code'], debouncedTrimmedInput], + ['search', ['secondary_code'], debouncedTrimmedInput], ]; export const largePayload = (infraId: number | undefined, debouncedTrimmedInput: string) => ({ @@ -30,7 +30,7 @@ export const exactTrigramPayload = (infraId: number | undefined, firstTokenUpper object: 'operationalpoint', query: [ 'and', - ['=', ['trigram'], firstTokenUpper], + ['=', ['main_code'], firstTokenUpper], infraId !== undefined ? ['=', ['infra_id'], infraId] : true, ], }); diff --git a/front/src/applications/operationalStudies/helpers/suggestionMatchers.ts b/front/src/applications/operationalStudies/helpers/suggestionMatchers.ts index b119700bb86..2b49406ac6c 100644 --- a/front/src/applications/operationalStudies/helpers/suggestionMatchers.ts +++ b/front/src/applications/operationalStudies/helpers/suggestionMatchers.ts @@ -34,14 +34,16 @@ export const hasChPrefix = (s: OperationalPointSuggestion, chTokenUpper: string) export const tokenMatchesIncludesNoCh = (s: OperationalPointSuggestion, token: string) => { const tokenNormalized = normalizeName(token); const tokenUpper = toUpper(token); - return normalizeName(s.name).includes(tokenNormalized) || toUpper(s.trigram).includes(tokenUpper); + return ( + normalizeName(s.name).includes(tokenNormalized) || toUpper(s.mainCode).includes(tokenUpper) + ); }; export const tokenMatchesStartNoCh = (s: OperationalPointSuggestion, token: string) => { const tokenNormalized = normalizeName(token); const tokenUpper = toUpper(token); return ( - normalizeName(s.name).startsWith(tokenNormalized) || toUpper(s.trigram).startsWith(tokenUpper) + normalizeName(s.name).startsWith(tokenNormalized) || toUpper(s.mainCode).startsWith(tokenUpper) ); }; diff --git a/front/src/applications/operationalStudies/helpers/upsertMapWaypointsInOperationalPoints.ts b/front/src/applications/operationalStudies/helpers/upsertMapWaypointsInOperationalPoints.ts index 0083f272b8c..81e2bdeb46d 100644 --- a/front/src/applications/operationalStudies/helpers/upsertMapWaypointsInOperationalPoints.ts +++ b/front/src/applications/operationalStudies/helpers/upsertMapWaypointsInOperationalPoints.ts @@ -48,12 +48,11 @@ export function upsertMapWaypointsInOperationalPoints( } const baseFormattedStep = { - extensions: { - identifier: { - name: stepName, - uic: 0, - }, - }, + name: stepName, + uic: 0, + country_code: '', + is_passenger_station: false, + main_code: '', part: { track: location.track, position: location.offset, local_track_name: 'V1' }, position: positionOnPath, weight: HIGHEST_PRIORITY_WEIGHT, @@ -84,8 +83,8 @@ export function upsertMapWaypointsInOperationalPoints( const matchedIndex = operationalPointsWithAllWaypoints.findIndex( (op) => location.operational_point.type === 'uic' && - location.operational_point.uic === op.extensions?.identifier?.uic && - location.operational_point.secondary_code === op.extensions?.sncf?.ch + location.operational_point.uic === op.uic && + location.operational_point.secondary_code === op.secondary_code ); if (matchedIndex !== -1) { diff --git a/front/src/applications/operationalStudies/hooks/useOperationalPointSearch.ts b/front/src/applications/operationalStudies/hooks/useOperationalPointSearch.ts index b3eccbc7662..f173baa1b57 100644 --- a/front/src/applications/operationalStudies/hooks/useOperationalPointSearch.ts +++ b/front/src/applications/operationalStudies/hooks/useOperationalPointSearch.ts @@ -137,7 +137,7 @@ export const useOperationalPointSearch = ({ // 2) We try to lock trigram from the "large" call if (firstTokenUpper) { const keptFromLarge = suggestionsLarge.filter( - (s) => toUpper(s.trigram) === firstTokenUpper && shouldKeepTrigramLock(s, tokens) + (s) => toUpper(s.mainCode) === firstTokenUpper && shouldKeepTrigramLock(s, tokens) ); if (keptFromLarge.length > 0) { diff --git a/front/src/applications/operationalStudies/hooks/usePathProjection.ts b/front/src/applications/operationalStudies/hooks/usePathProjection.ts index 895d290234b..fa65e6f7ea1 100644 --- a/front/src/applications/operationalStudies/hooks/usePathProjection.ts +++ b/front/src/applications/operationalStudies/hooks/usePathProjection.ts @@ -19,7 +19,6 @@ import { getTrainIdUsedForProjection, } from 'reducers/simulationResults/selectors'; import { useAppDispatch } from 'store'; -import { formatUicToCi } from 'utils/strings'; import { extractEditoastIdFromPacedTrainId, extractPacedTrainIdFromOccurrenceId, @@ -66,21 +65,14 @@ const createVirtualOp = ( return { id: virtualId, - extensions: { - identifier: { - name: virtualName, - uic: opRef.type === 'uic' ? opRef.uic : 0, - }, - sncf: { - ch: (opRef.type !== 'id' && opRef.secondary_code) || '', - ch_long_label: '', - ch_short_label: '', - ci: opRef.type === 'uic' ? Number(formatUicToCi(opRef.uic)) : 0, - trigram: opRef.type === 'trigram' ? opRef.trigram : '', - }, - }, + name: virtualName, + uic: opRef.type === 'uic' ? opRef.uic : 0, + secondary_code: (opRef.type !== 'id' && opRef.secondary_code) || '', + main_code: opRef.type === 'trigram' ? opRef.trigram : '', position, weight, + country_code: '', + is_passenger_station: false, }; }; @@ -241,9 +233,14 @@ const usePathProjection = ( if (matchedOp) { // MATCHED: Point exists in infrastructure normalizedOps.push({ + country_code: matchedOp.country_code, id: matchedOp.id, - extensions: matchedOp.extensions, + is_passenger_station: matchedOp.is_passenger_station, + main_code: matchedOp.main_code, + name: matchedOp.name, position, + secondary_code: matchedOp.secondary_code, + uic: matchedOp.uic ?? NaN, weight, }); } else { diff --git a/front/src/applications/operationalStudies/utils.ts b/front/src/applications/operationalStudies/utils.ts index c4b8b34359f..edc15741d5d 100644 --- a/front/src/applications/operationalStudies/utils.ts +++ b/front/src/applications/operationalStudies/utils.ts @@ -416,12 +416,12 @@ export const matchOpRefAndOp = ( } if (location.operational_point.type === 'uic') { return ( - location.operational_point.uic === op.extensions?.identifier?.uic && - location.operational_point.secondary_code === op.extensions?.sncf?.ch + location.operational_point.uic === op.uic && + location.operational_point.secondary_code === op.secondary_code ); } return ( - location.operational_point.trigram === op.extensions?.sncf?.trigram && - location.operational_point.secondary_code === op.extensions?.sncf?.ch + location.operational_point.trigram === op.main_code && + location.operational_point.secondary_code === op.secondary_code ); }; diff --git a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/MacroEditorState.ts b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/MacroEditorState.ts index 60565749a05..d09b8ad9a17 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/MacroEditorState.ts +++ b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/MacroEditorState.ts @@ -258,13 +258,13 @@ export default class MacroEditorState { * Given a search result item, returns all possible pathKeys, ordered by weight. */ static getPathKeys(op: OperationalPoint): string[] { - const { uic } = op.extensions?.identifier ?? {}; - const { trigram, ch } = op.extensions?.sncf ?? {}; + const { uic } = op ?? {}; + const { main_code, secondary_code } = op ?? {}; const result = []; result.push(`op_id:${op.id}`); - if (trigram) result.push(`trigram:${trigram}${ch ? `/${ch}` : ''}`); - if (uic) result.push(`uic:${uic}${ch ? `/${ch}` : ''}`); + if (main_code) result.push(`trigram:${main_code}${secondary_code ? `/${secondary_code}` : ''}`); + if (uic) result.push(`uic:${uic}${secondary_code ? `/${secondary_code}` : ''}`); for (const opPart of op.parts) { result.push(`track_offset:${opPart.track}+${opPart.position}`); } diff --git a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/ngeToOsrd/node.ts b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/ngeToOsrd/node.ts index 6c7e9c51270..ca8b5ce7c85 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/ngeToOsrd/node.ts +++ b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/ngeToOsrd/node.ts @@ -62,26 +62,26 @@ export const handleNodeOperation = async ({ case 'update': { if (indexNode) { if (indexNode.dbId) { - // Update the key if trigram has changed and key is based on it + // Update the key if mainCode has changed and key is based on it let nodeKey = indexNode.path_item_key; - let trigram = node.betriebspunktName; - if (nodeKey.startsWith('trigram:') && indexNode.trigram !== trigram) { - if (!trigram.includes('/')) { + let mainCode = node.betriebspunktName; + if (nodeKey.startsWith('trigram:') && indexNode.trigram !== mainCode) { + if (!mainCode.includes('/')) { const secondaryCode = await fetchStationSecondaryCode( - trigram, + mainCode, state.infraId, dispatch ); if (secondaryCode) { - trigram = `${trigram}/${secondaryCode}`; + mainCode = `${mainCode}/${secondaryCode}`; } } - nodeKey = `trigram:${trigram}`; + nodeKey = `trigram:${mainCode}`; } await updateMacroNode(state, dispatch, { ...indexNode, ...castNgeNode(node, netzgrafikDto.labels), - trigram, + trigram: mainCode, dbId: indexNode.dbId, path_item_key: nodeKey, }); diff --git a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/osrdToNge.ts b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/osrdToNge.ts index 48d94ff00e6..180e3588dcc 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/osrdToNge.ts +++ b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/osrdToNge.ts @@ -325,11 +325,11 @@ export const loadAndIndexNge = async ( .flatMap((trainSchedule) => trainSchedule.pathOps) .filter((op) => op !== null); for (const op of pathOps) { - const { trigram, ch } = op.extensions?.sncf ?? {}; + const { main_code, secondary_code } = op ?? {}; for (const pathKey of MacroEditorState.getPathKeys(op)) { state.updateNodeDataByKey(pathKey, { - full_name: op.extensions?.identifier?.name, - trigram: trigram ? trigram + (ch ? `/${ch}` : '') : null, + full_name: op.name, + trigram: main_code ? main_code + (secondary_code ? `/${secondary_code}` : '') : null, geocoord: op.geo ? { lng: op.geo.coordinates[0], lat: op.geo.coordinates[1] } : undefined, }); } diff --git a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/utils.ts b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/utils.ts index 7481af5d42f..1b72ca9f3a2 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/utils.ts +++ b/front/src/applications/operationalStudies/views/Scenario/components/MacroEditor/utils.ts @@ -270,7 +270,7 @@ export const fetchStationSecondaryCode = async ( ) => { const searchPayload = { object: 'operationalpoint', - query: ['and', ['=', ['infra_id'], infraId], ['=', ['trigram'], trigram]], + query: ['and', ['=', ['infra_id'], infraId], ['=', ['main_code'], trigram]], }; const searchResults = (await dispatch( osrdEditoastApi.endpoints.postSearch.initiate({ @@ -278,6 +278,6 @@ export const fetchStationSecondaryCode = async ( }) ).unwrap()) as SearchResultItemOperationalPoint[]; - const stationOp = searchResults.find((op) => op.ch === 'BV' || op.ch === '00'); - return stationOp?.ch; + const stationOp = searchResults.find((op) => op.is_passenger_station); + return stationOp?.secondary_code; }; diff --git a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ComboBoxCustomList/ListElementComponent.tsx b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ComboBoxCustomList/ListElementComponent.tsx index 8b63e3934ff..ea67692c4e8 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ComboBoxCustomList/ListElementComponent.tsx +++ b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ComboBoxCustomList/ListElementComponent.tsx @@ -13,7 +13,7 @@ export type OpSecondaryCode = { export type OperationalPointSuggestion = { id: string; - trigram: string; + mainCode: string; uic: number; name: string; secondaryCodeList: OpSecondaryCode[]; @@ -51,7 +51,7 @@ export const ListElementComponent = ({ onSelect?.(suggestion, defaultSecondaryCode); }} > - {suggestion.trigram} + {suggestion.mainCode} { - const ch = op.extensions?.sncf?.ch; - const uic = op.extensions?.identifier?.uic; + const ch = op.secondary_code; + const uic = op.uic; if (uic != null) return { type: 'uic', uic, secondary_code: ch, }; - const trigram = op.extensions?.sncf?.trigram; + const trigram = op.main_code; if (trigram) return { type: 'trigram', @@ -50,7 +50,7 @@ export const buildOpRef = (op: OperationalPoint): OperationalPointReference => { }; export const buildOpDisplayName = (op: OperationalPoint): string => { - const name = op.extensions?.identifier?.name ?? op.extensions?.sncf?.trigram ?? ''; - const ch = op.extensions?.sncf?.ch; - return ch ? `${name} ${ch}` : name; + const name = op.name ?? op.main_code ?? ''; + const secondaryCode = op.secondary_code; + return secondaryCode ? `${name} ${secondaryCode}` : name; }; diff --git a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/AddPathStepPopup.tsx b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/AddPathStepPopup.tsx index 2595492be35..db4703ca113 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/AddPathStepPopup.tsx +++ b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/AddPathStepPopup.tsx @@ -120,16 +120,16 @@ const AddPathStepPopup = ({ }); let opRef: OperationalPointReference; - const uic = operationalPoint.extensions?.identifier?.uic; + const uic = operationalPoint.uic; if (uic) { - opRef = { type: 'uic', uic, secondary_code: operationalPoint.extensions?.sncf?.ch }; + opRef = { type: 'uic', uic, secondary_code: operationalPoint.secondary_code }; } else { opRef = { type: 'id', operational_point: operationalPoint.id }; } setClickedOp({ id: uuidV4(), - name: operationalPoint.extensions?.identifier?.name, + name: operationalPoint.name, location: { type: 'operational_point_part_reference', operational_point: opRef }, tracks: trackPartCoordinates, }); diff --git a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/OperationalPointPopupDetails.tsx b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/OperationalPointPopupDetails.tsx index 0c84fbb53a0..a6261d47d87 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/OperationalPointPopupDetails.tsx +++ b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/ManageTrainScheduleMap/OperationalPointPopupDetails.tsx @@ -40,9 +40,9 @@ const OperationalPointPopupDetails = ({ {operationalPoint.feature.properties!.extensions_sncf_line_code}
- {operationalPoint.feature.properties!.extensions_identifier_name}
- {operationalPoint.feature.properties!.extensions_sncf_trigram}{' '} - {operationalPoint.feature.properties!.extensions_sncf_ch} + {operationalPoint.feature.properties!.name}
+ {operationalPoint.feature.properties!.main_code}{' '} + {operationalPoint.feature.properties!.secondary_code}