diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml index 32e31f7af38..173ff46f20d 100644 --- a/editoast/openapi.yaml +++ b/editoast/openapi.yaml @@ -3095,7 +3095,18 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/WorkScheduleCreateForm' + type: object + description: This structure is used by the post endpoint to create a work schedule + required: + - work_schedule_group_name + - work_schedules + properties: + work_schedule_group_name: + type: string + work_schedules: + type: array + items: + $ref: '#/components/schemas/WorkScheduleItemForm' required: true responses: '201': @@ -3103,7 +3114,151 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/WorkScheduleCreateResponse' + type: object + required: + - work_schedule_group_id + properties: + work_schedule_group_id: + type: integer + format: int64 + /work_schedules/group: + get: + tags: + - work_schedules + responses: + '201': + description: The existing work schedule group ids + content: + application/json: + schema: + type: array + items: + type: integer + format: int64 + post: + tags: + - work_schedules + requestBody: + content: + application/json: + schema: + type: object + properties: + work_schedule_group_name: + type: string + nullable: true + required: true + responses: + '200': + description: The id of the created work schedule group + content: + application/json: + schema: + type: object + required: + - work_schedule_group_id + properties: + work_schedule_group_id: + type: integer + format: int64 + /work_schedules/group/{id}: + get: + tags: + - work_schedules + parameters: + - name: page + in: query + required: false + schema: + type: integer + format: int64 + default: 1 + minimum: 1 + - name: page_size + in: query + required: false + schema: + type: integer + format: int64 + default: 25 + nullable: true + minimum: 1 + - name: id + in: path + description: A work schedule group ID + required: true + schema: + type: integer + format: int64 + - name: ordering + in: query + required: false + schema: + $ref: '#/components/schemas/Ordering' + responses: + '200': + description: The work schedules in the group + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/PaginationStats' + - type: object + required: + - results + properties: + results: + type: array + items: + $ref: '#/components/schemas/WorkSchedule' + '404': + description: Work schedule group not found + put: + tags: + - work_schedules + parameters: + - name: id + in: path + description: A work schedule group ID + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/WorkScheduleItemForm' + required: true + responses: + '200': + description: The work schedules have been created + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/WorkSchedule' + '404': + description: Work schedule group not found + delete: + tags: + - work_schedules + parameters: + - name: id + in: path + description: A work schedule group ID + required: true + schema: + type: integer + format: int64 + responses: + '204': + description: The work schedule group has been deleted + '404': + description: The work schedule group does not exist /work_schedules/project_path: post: tags: @@ -4375,6 +4530,7 @@ components: - $ref: '#/components/schemas/EditoastTrainScheduleErrorInfraNotFound' - $ref: '#/components/schemas/EditoastTrainScheduleErrorNotFound' - $ref: '#/components/schemas/EditoastWorkScheduleErrorNameAlreadyUsed' + - $ref: '#/components/schemas/EditoastWorkScheduleErrorWorkScheduleGroupNotFound' description: Generated error type for Editoast discriminator: propertyName: type @@ -5793,6 +5949,30 @@ components: type: string enum: - editoast:work_schedule:NameAlreadyUsed + EditoastWorkScheduleErrorWorkScheduleGroupNotFound: + type: object + required: + - type + - status + - message + properties: + context: + type: object + required: + - id + properties: + id: + type: integer + message: + type: string + status: + type: integer + enum: + - 404 + type: + type: string + enum: + - editoast:work_schedule:WorkScheduleGroupNotFound EffortCurve: type: object required: @@ -10873,27 +11053,37 @@ components: type: string enum: - Detector - WorkScheduleCreateForm: + WorkSchedule: type: object - description: This structure is used by the post endpoint to create a work schedule required: - - work_schedule_group_name - - work_schedules + - id + - start_date_time + - end_date_time + - track_ranges + - obj_id + - work_schedule_type + - work_schedule_group_id properties: - work_schedule_group_name: + end_date_time: + type: string + format: date-time + id: + type: integer + format: int64 + obj_id: + type: string + start_date_time: type: string - work_schedules: + format: date-time + track_ranges: type: array items: - $ref: '#/components/schemas/WorkScheduleItemForm' - WorkScheduleCreateResponse: - type: object - required: - - work_schedule_group_id - properties: + $ref: '#/components/schemas/TrackRange' work_schedule_group_id: type: integer format: int64 + work_schedule_type: + $ref: '#/components/schemas/WorkScheduleType' WorkScheduleItemForm: type: object required: @@ -10920,6 +11110,11 @@ components: enum: - CATENARY - TRACK + WorkScheduleType: + type: string + enum: + - CATENARY + - TRACK ZoneUpdate: type: object required: diff --git a/editoast/src/models/work_schedules.rs b/editoast/src/models/work_schedules.rs index 80da485fc51..a8aa31c4317 100644 --- a/editoast/src/models/work_schedules.rs +++ b/editoast/src/models/work_schedules.rs @@ -29,9 +29,9 @@ pub enum WorkScheduleType { Track, } -#[derive(Debug, Default, Clone, Model)] +#[derive(Debug, Default, Clone, Model, Serialize, Deserialize, ToSchema)] #[model(table = editoast_models::tables::work_schedule)] -#[model(gen(batch_ops = c, list))] +#[model(gen(batch_ops = cd, list))] pub struct WorkSchedule { pub id: i64, pub start_date_time: DateTime<Utc>, diff --git a/editoast/src/views/operational_studies.rs b/editoast/src/views/operational_studies.rs index 871be4e8e1a..3c287931483 100644 --- a/editoast/src/views/operational_studies.rs +++ b/editoast/src/views/operational_studies.rs @@ -1,4 +1,5 @@ use crate::models::prelude::*; +use crate::models::work_schedules::WorkSchedule; use crate::models::Project; use crate::models::Scenario; use crate::models::Study; @@ -58,4 +59,12 @@ impl Ordering { Ordering::LastModifiedDesc => Scenario::LAST_MODIFICATION.desc(), } } + + pub fn as_work_schedule_ordering(&self) -> SortSetting<WorkSchedule> { + match *self { + Ordering::NameAsc => WorkSchedule::OBJ_ID.asc(), + Ordering::NameDesc => WorkSchedule::OBJ_ID.desc(), + _ => WorkSchedule::OBJ_ID.asc(), + } + } } diff --git a/editoast/src/views/work_schedules.rs b/editoast/src/views/work_schedules.rs index 0f7f116daf2..6c555edf8ce 100644 --- a/editoast/src/views/work_schedules.rs +++ b/editoast/src/views/work_schedules.rs @@ -1,5 +1,23 @@ +use super::pagination::PaginatedList; +use crate::core::pathfinding::TrackRange as CoreTrackRange; +use crate::error::InternalError; +use crate::error::Result; +use crate::models::prelude::*; +use crate::models::work_schedules::WorkSchedule; +use crate::models::work_schedules::WorkScheduleGroup; +use crate::models::work_schedules::WorkScheduleType; +use crate::views::operational_studies::Ordering; +use crate::views::pagination::PaginationQueryParam; +use crate::views::pagination::PaginationStats; +use crate::views::path::projection::Intersection; +use crate::views::path::projection::PathProjection; +use crate::views::AuthenticationExt; +use crate::views::AuthorizationError; use axum::extract::Json; +use axum::extract::Path; +use axum::extract::Query; use axum::extract::State; +use axum::response::IntoResponse; use axum::Extension; use chrono::DateTime; use chrono::Utc; @@ -7,38 +25,43 @@ use derivative::Derivative; use editoast_authz::BuiltinRole; use editoast_derive::EditoastError; use editoast_models::DbConnectionPoolV2; +use editoast_schemas::infra::Direction; +use editoast_schemas::infra::TrackRange; use serde::de::Error as SerdeError; use serde::Deserialize; use serde::Serialize; use std::result::Result as StdResult; use thiserror::Error; +use utoipa::IntoParams; use utoipa::ToSchema; - -use crate::core::pathfinding::TrackRange as CoreTrackRange; -use crate::error::InternalError; -use crate::error::Result; -use crate::models::prelude::*; -use crate::models::work_schedules::WorkSchedule; -use crate::models::work_schedules::WorkScheduleGroup; -use crate::models::work_schedules::WorkScheduleType; -use crate::views::path::projection::Intersection; -use crate::views::path::projection::PathProjection; -use crate::views::AuthenticationExt; -use crate::views::AuthorizationError; -use crate::AppState; -use editoast_schemas::infra::{Direction, TrackRange}; +use uuid::Uuid; crate::routes! { "/work_schedules" => { create, "/project_path" => project_path, + "/group" => { + create_group, + list_groups, + "/{id}" => { + delete_group, + get_group, + put_in_group, + }, + }, }, } editoast_common::schemas! { - WorkScheduleCreateForm, - WorkScheduleCreateResponse, + WorkSchedule, WorkScheduleItemForm, + WorkScheduleType, +} + +#[derive(IntoParams, Deserialize)] +struct WorkScheduleGroupIdParam { + /// A work schedule group ID + id: i64, } #[derive(Debug, Error, EditoastError)] @@ -47,6 +70,9 @@ enum WorkScheduleError { #[error("Name '{name}' already used")] #[editoast_error(status = 400)] NameAlreadyUsed { name: String }, + #[error("Work schedule group '{id}' not found")] + #[editoast_error(status = 404)] + WorkScheduleGroupNotFound { id: i64 }, } pub fn map_diesel_error(e: InternalError, name: impl AsRef<str>) -> InternalError { @@ -136,49 +162,43 @@ struct WorkScheduleCreateResponse { #[utoipa::path( post, path = "", tag = "work_schedules", - request_body = WorkScheduleCreateForm, + request_body = inline(WorkScheduleCreateForm), responses( - (status = 201, body = WorkScheduleCreateResponse, description = "The id of the created work schedule group"), + (status = 201, body = inline(WorkScheduleCreateResponse), description = "The id of the created work schedule group"), ) )] async fn create( - State(app_state): State<AppState>, + State(db_pool): State<DbConnectionPoolV2>, Extension(auth): AuthenticationExt, Json(WorkScheduleCreateForm { work_schedule_group_name, work_schedules, }): Json<WorkScheduleCreateForm>, ) -> Result<Json<WorkScheduleCreateResponse>> { - let authorized = auth - .check_roles([BuiltinRole::WorkScheduleWrite].into()) - .await - .map_err(AuthorizationError::AuthError)?; - if !authorized { - return Err(AuthorizationError::Unauthorized.into()); - } + // Create the group (using the method for the create group endpoint) + let work_schedule_group = create_group( + State(db_pool.clone()), + Extension(auth), + Json(WorkScheduleGroupCreateForm { + work_schedule_group_name: Some(work_schedule_group_name), + }), + ) + .await?; - let db_pool = app_state.db_pool_v2.clone(); let conn = &mut db_pool.get().await?; - // Create the work_schedule_group - let work_schedule_group = WorkScheduleGroup::changeset() - .name(work_schedule_group_name.clone()) - .creation_date(Utc::now()) - .create(conn) - .await; - let work_schedule_group = - work_schedule_group.map_err(|e| map_diesel_error(e, work_schedule_group_name))?; - // Create work schedules let work_schedules_changesets = work_schedules .into_iter() - .map(|work_schedule| work_schedule.into_work_schedule_changeset(work_schedule_group.id)) + .map(|work_schedule| { + work_schedule.into_work_schedule_changeset(work_schedule_group.work_schedule_group_id) + }) .collect::<Vec<_>>(); let _work_schedules: Vec<_> = WorkSchedule::create_batch(conn, work_schedules_changesets).await?; Ok(Json(WorkScheduleCreateResponse { - work_schedule_group_id: work_schedule_group.id, + work_schedule_group_id: work_schedule_group.work_schedule_group_id, })) } @@ -275,6 +295,227 @@ async fn project_path( Ok(Json(projections)) } +#[derive(Serialize, Deserialize, ToSchema)] +struct WorkScheduleGroupCreateForm { + work_schedule_group_name: Option<String>, +} + +#[derive(Serialize, Deserialize, ToSchema)] +struct WorkScheduleGroupCreateResponse { + work_schedule_group_id: i64, +} + +#[utoipa::path( + post, path = "", + tag = "work_schedules", + request_body = inline(WorkScheduleGroupCreateForm), + responses( + (status = 200, body = inline(WorkScheduleGroupCreateResponse), description = "The id of the created work schedule group"), + ) +)] +async fn create_group( + State(db_pool): State<DbConnectionPoolV2>, + Extension(auth): AuthenticationExt, + Json(WorkScheduleGroupCreateForm { + work_schedule_group_name, + }): Json<WorkScheduleGroupCreateForm>, +) -> Result<Json<WorkScheduleGroupCreateResponse>> { + let authorized = auth + .check_roles([BuiltinRole::WorkScheduleWrite].into()) + .await + .map_err(AuthorizationError::AuthError)?; + if !authorized { + return Err(AuthorizationError::Unauthorized.into()); + } + + let conn = &mut db_pool.get().await?; + let group_name = work_schedule_group_name.unwrap_or(Uuid::new_v4().to_string()); + + // Create the work_schedule_group + let work_schedule_group = WorkScheduleGroup::changeset() + .name(group_name.clone()) + .creation_date(Utc::now()) + .create(conn) + .await; + let work_schedule_group = work_schedule_group.map_err(|e| map_diesel_error(e, group_name))?; + Ok(Json(WorkScheduleGroupCreateResponse { + work_schedule_group_id: work_schedule_group.id, + })) +} + +#[utoipa::path( + delete, path = "", + tag = "work_schedules", + params(WorkScheduleGroupIdParam), + responses( + (status = 204, description = "The work schedule group has been deleted"), + (status = 404, description = "The work schedule group does not exist"), + ) +)] +async fn delete_group( + State(db_pool): State<DbConnectionPoolV2>, + Extension(auth): AuthenticationExt, + Path(WorkScheduleGroupIdParam { id: group_id }): Path<WorkScheduleGroupIdParam>, +) -> Result<impl IntoResponse> { + let authorized = auth + .check_roles([BuiltinRole::WorkScheduleWrite].into()) + .await + .map_err(AuthorizationError::AuthError)?; + if !authorized { + return Err(AuthorizationError::Unauthorized.into()); + } + + let conn = &mut db_pool.get().await?; + WorkScheduleGroup::delete_static_or_fail(conn, group_id, || { + WorkScheduleError::WorkScheduleGroupNotFound { id: group_id } + }) + .await?; + + Ok(axum::http::StatusCode::NO_CONTENT) +} + +#[utoipa::path( + get, path = "", + tag = "work_schedules", + responses( + (status = 201, body = Vec<i64>, description = "The existing work schedule group ids"), + ) +)] +async fn list_groups( + State(db_pool): State<DbConnectionPoolV2>, + Extension(auth): AuthenticationExt, +) -> Result<Json<Vec<i64>>> { + let authorized = auth + .check_roles([BuiltinRole::WorkScheduleRead].into()) + .await + .map_err(AuthorizationError::AuthError)?; + if !authorized { + return Err(AuthorizationError::Unauthorized.into()); + } + + let conn = &mut db_pool.get().await?; + + let selection_setting = SelectionSettings::new(); + let work_schedule_group_ids = WorkScheduleGroup::list(conn, selection_setting) + .await? + .iter() + .map(|group| group.id) + .collect::<Vec<i64>>(); + + Ok(Json(work_schedule_group_ids)) +} + +#[utoipa::path( + put, path = "", + tag = "work_schedules", + request_body = Vec<WorkScheduleItemForm>, + params(WorkScheduleGroupIdParam), + responses( + (status = 200, description = "The work schedules have been created", body = Vec<WorkSchedule>), + (status = 404, description = "Work schedule group not found"), + ) +)] +async fn put_in_group( + State(db_pool): State<DbConnectionPoolV2>, + Extension(auth): AuthenticationExt, + Path(WorkScheduleGroupIdParam { id: group_id }): Path<WorkScheduleGroupIdParam>, + Json(work_schedules): Json<Vec<WorkScheduleItemForm>>, +) -> Result<Json<Vec<WorkSchedule>>> { + let authorized = auth + .check_roles([BuiltinRole::WorkScheduleWrite].into()) + .await + .map_err(AuthorizationError::AuthError)?; + if !authorized { + return Err(AuthorizationError::Unauthorized.into()); + } + + let conn = &mut db_pool.get().await?; + + conn.transaction(|conn| { + Box::pin(async move { + // Check that the group exists + WorkScheduleGroup::retrieve_or_fail(&mut conn.clone(), group_id, || { + WorkScheduleError::WorkScheduleGroupNotFound { id: group_id } + }) + .await?; + + // Create work schedules + let work_schedules_changesets = work_schedules + .into_iter() + .map(|work_schedule| work_schedule.into_work_schedule_changeset(group_id)) + .collect::<Vec<_>>(); + let work_schedules = + WorkSchedule::create_batch(&mut conn.clone(), work_schedules_changesets).await?; + + Ok(Json(work_schedules)) + }) + }) + .await +} + +#[derive(Serialize, ToSchema)] +#[cfg_attr(test, derive(Deserialize))] +struct GroupContentResponse { + #[schema(value_type = Vec<WorkSchedule>)] + results: Vec<WorkSchedule>, + #[serde(flatten)] + stats: PaginationStats, +} + +#[derive(Debug, Clone, serde::Deserialize, utoipa::IntoParams)] +#[into_params(parameter_in = Query)] +pub struct WorkScheduleOrderingParam { + #[serde(default)] + pub ordering: Ordering, +} + +#[utoipa::path( + get, path = "", + tag = "work_schedules", + params(PaginationQueryParam, WorkScheduleGroupIdParam, WorkScheduleOrderingParam), + responses( + (status = 200, description = "The work schedules in the group", body = inline(GroupContentResponse)), + (status = 404, description = "Work schedule group not found"), + ) +)] +async fn get_group( + State(db_pool): State<DbConnectionPoolV2>, + Extension(auth): AuthenticationExt, + Path(WorkScheduleGroupIdParam { id: group_id }): Path<WorkScheduleGroupIdParam>, + Query(pagination_params): Query<PaginationQueryParam>, + Query(ordering_params): Query<WorkScheduleOrderingParam>, +) -> Result<Json<GroupContentResponse>> { + let authorized = auth + .check_roles([BuiltinRole::WorkScheduleRead].into()) + .await + .map_err(AuthorizationError::AuthError)?; + if !authorized { + return Err(AuthorizationError::Unauthorized.into()); + } + + let ordering = ordering_params.ordering; + let settings = pagination_params + .validate(100)? + .into_selection_settings() + .filter(move || WorkSchedule::WORK_SCHEDULE_GROUP_ID.eq(group_id)) + .order_by(move || ordering.as_work_schedule_ordering()); + + let conn = &mut db_pool.get().await?; + + // Check that the group exists + WorkScheduleGroup::retrieve_or_fail(conn, group_id, || { + WorkScheduleError::WorkScheduleGroupNotFound { id: group_id } + }) + .await?; + + let (work_schedules, stats) = WorkSchedule::list_paginated(conn, settings).await?; + + Ok(Json(GroupContentResponse { + results: work_schedules, + stats, + })) +} + #[cfg(test)] pub mod tests { use axum::http::StatusCode; @@ -510,4 +751,48 @@ pub mod tests { assert_eq!(work_schedule_project_response, expected); } + + #[rstest] + async fn work_schedule_endpoints_workflow() { + let app = TestAppBuilder::default_app(); + + // Create a new group + let create_group_request = app.post("/work_schedules/group").json(&json!({})); + let group_creation_response = app + .fetch(create_group_request) + .assert_status(StatusCode::OK) + .json_into::<WorkScheduleGroupCreateResponse>(); + let group_id = group_creation_response.work_schedule_group_id; + let work_schedule_url = format!("/work_schedules/group/{group_id}"); + + // Add a work schedule + let ref_obj_id = Uuid::new_v4().to_string(); + let request = app.put(&work_schedule_url).json(&json!([{ + "start_date_time": "2024-01-01T08:00:00Z", + "end_date_time": "2024-01-01T09:00:00Z", + "track_ranges": [], + "obj_id": ref_obj_id, + "work_schedule_type": "CATENARY" + }] + )); + app.fetch(request).assert_status(StatusCode::OK); + + // Get the content of the group + let request = app.get(&work_schedule_url); + let response = app + .fetch(request) + .assert_status(StatusCode::OK) + .json_into::<GroupContentResponse>(); + let work_schedules = response.results; + assert_eq!(1, work_schedules.len()); + assert_eq!(ref_obj_id, work_schedules[0].obj_id); + + // Delete it + let request = app.delete(&work_schedule_url); + app.fetch(request).assert_status(StatusCode::NO_CONTENT); + + // Try to access it + let request = app.get(&work_schedule_url); + app.fetch(request).assert_status(StatusCode::NOT_FOUND); + } } diff --git a/front/public/locales/en/errors.json b/front/public/locales/en/errors.json index 37a96754166..f576f310332 100644 --- a/front/public/locales/en/errors.json +++ b/front/public/locales/en/errors.json @@ -220,7 +220,8 @@ "InvalidUrl": "Invalid url '{{url}}'" }, "work_schedule": { - "NameAlreadyUsed": "A group of work schedules with '{{name}}' already exists" + "NameAlreadyUsed": "A group of work schedules with '{{name}}' already exists", + "WorkScheduleGroupNotFound": "No such work schedule group with id '{{id}}'" }, "temporary_speed_limit": { "NameAlreadyUsed": "A group of temporary speed limits with '{{name}}' already exists" diff --git a/front/public/locales/fr/errors.json b/front/public/locales/fr/errors.json index c0a3ccaaa58..18ab7faa678 100644 --- a/front/public/locales/fr/errors.json +++ b/front/public/locales/fr/errors.json @@ -217,7 +217,8 @@ "InvalidUrl": "Url invalide '{{url}}'" }, "work_schedule": { - "NameAlreadyUsed": "Un groupe de planches travaux avec le nom '{{name}}' existe déjà" + "NameAlreadyUsed": "Un groupe de planches travaux avec le nom '{{name}}' existe déjà", + "WorkScheduleGroupNotFound": "Le groupe de planche travaux avec l'id {{id}} n'existe pas" }, "temporary_speed_limit": { "NameAlreadyUsed": "Un groupe de limites temporaires de vitesse avec le nom '{{name}} existe déjà" diff --git a/front/src/common/api/generatedEditoastApi.ts b/front/src/common/api/generatedEditoastApi.ts index ad017ddfc5c..30f89a0b3bf 100644 --- a/front/src/common/api/generatedEditoastApi.ts +++ b/front/src/common/api/generatedEditoastApi.ts @@ -911,13 +911,59 @@ const injectedRtkApi = api query: () => ({ url: `/version/core` }), }), postWorkSchedules: build.mutation<PostWorkSchedulesApiResponse, PostWorkSchedulesApiArg>({ + query: (queryArg) => ({ url: `/work_schedules`, method: 'POST', body: queryArg.body }), + invalidatesTags: ['work_schedules'], + }), + getWorkSchedulesGroup: build.query< + GetWorkSchedulesGroupApiResponse, + GetWorkSchedulesGroupApiArg + >({ + query: () => ({ url: `/work_schedules/group` }), + providesTags: ['work_schedules'], + }), + postWorkSchedulesGroup: build.mutation< + PostWorkSchedulesGroupApiResponse, + PostWorkSchedulesGroupApiArg + >({ query: (queryArg) => ({ - url: `/work_schedules`, + url: `/work_schedules/group`, method: 'POST', - body: queryArg.workScheduleCreateForm, + body: queryArg.body, }), invalidatesTags: ['work_schedules'], }), + getWorkSchedulesGroupById: build.query< + GetWorkSchedulesGroupByIdApiResponse, + GetWorkSchedulesGroupByIdApiArg + >({ + query: (queryArg) => ({ + url: `/work_schedules/group/${queryArg.id}`, + params: { + page: queryArg.page, + page_size: queryArg.pageSize, + ordering: queryArg.ordering, + }, + }), + providesTags: ['work_schedules'], + }), + putWorkSchedulesGroupById: build.mutation< + PutWorkSchedulesGroupByIdApiResponse, + PutWorkSchedulesGroupByIdApiArg + >({ + query: (queryArg) => ({ + url: `/work_schedules/group/${queryArg.id}`, + method: 'PUT', + body: queryArg.body, + }), + invalidatesTags: ['work_schedules'], + }), + deleteWorkSchedulesGroupById: build.mutation< + DeleteWorkSchedulesGroupByIdApiResponse, + DeleteWorkSchedulesGroupByIdApiArg + >({ + query: (queryArg) => ({ url: `/work_schedules/group/${queryArg.id}`, method: 'DELETE' }), + invalidatesTags: ['work_schedules'], + }), postWorkSchedulesProjectPath: build.query< PostWorkSchedulesProjectPathApiResponse, PostWorkSchedulesProjectPathApiArg @@ -1686,9 +1732,49 @@ export type GetVersionApiArg = void; export type GetVersionCoreApiResponse = /** status 200 Return the core service version */ Version; export type GetVersionCoreApiArg = void; export type PostWorkSchedulesApiResponse = - /** status 201 The id of the created work schedule group */ WorkScheduleCreateResponse; + /** status 201 The id of the created work schedule group */ { + work_schedule_group_id: number; + }; export type PostWorkSchedulesApiArg = { - workScheduleCreateForm: WorkScheduleCreateForm; + body: { + work_schedule_group_name: string; + work_schedules: WorkScheduleItemForm[]; + }; +}; +export type GetWorkSchedulesGroupApiResponse = + /** status 201 The existing work schedule group ids */ number[]; +export type GetWorkSchedulesGroupApiArg = void; +export type PostWorkSchedulesGroupApiResponse = + /** status 200 The id of the created work schedule group */ { + work_schedule_group_id: number; + }; +export type PostWorkSchedulesGroupApiArg = { + body: { + work_schedule_group_name?: string | null; + }; +}; +export type GetWorkSchedulesGroupByIdApiResponse = + /** status 200 The work schedules in the group */ PaginationStats & { + results: WorkSchedule[]; + }; +export type GetWorkSchedulesGroupByIdApiArg = { + page?: number; + pageSize?: number | null; + /** A work schedule group ID */ + id: number; + ordering?: Ordering; +}; +export type PutWorkSchedulesGroupByIdApiResponse = + /** status 200 The work schedules have been created */ WorkSchedule[]; +export type PutWorkSchedulesGroupByIdApiArg = { + /** A work schedule group ID */ + id: number; + body: WorkScheduleItemForm[]; +}; +export type DeleteWorkSchedulesGroupByIdApiResponse = unknown; +export type DeleteWorkSchedulesGroupByIdApiArg = { + /** A work schedule group ID */ + id: number; }; export type PostWorkSchedulesProjectPathApiResponse = /** status 201 Returns a list of work schedules whose track ranges intersect the given path */ { @@ -3389,9 +3475,6 @@ export type TrainScheduleForm = TrainScheduleBase & { export type Version = { git_describe: string | null; }; -export type WorkScheduleCreateResponse = { - work_schedule_group_id: number; -}; export type WorkScheduleItemForm = { end_date_time: string; obj_id: string; @@ -3399,9 +3482,15 @@ export type WorkScheduleItemForm = { track_ranges: TrackRange[]; work_schedule_type: 'CATENARY' | 'TRACK'; }; -export type WorkScheduleCreateForm = { - work_schedule_group_name: string; - work_schedules: WorkScheduleItemForm[]; +export type WorkScheduleType = 'CATENARY' | 'TRACK'; +export type WorkSchedule = { + end_date_time: string; + id: number; + obj_id: string; + start_date_time: string; + track_ranges: TrackRange[]; + work_schedule_group_id: number; + work_schedule_type: WorkScheduleType; }; export type Intersection = { /** Distance of the end of the intersection relative to the beginning of the path */