diff --git a/client/src/features/projectsV2/api/projectV2.api.ts b/client/src/features/projectsV2/api/projectV2.api.ts index 5c6089d583..d7f955292a 100644 --- a/client/src/features/projectsV2/api/projectV2.api.ts +++ b/client/src/features/projectsV2/api/projectV2.api.ts @@ -28,6 +28,7 @@ const injectedRtkApi = api.injectEndpoints({ url: `/projects/${queryArg.projectId}`, method: "PATCH", body: queryArg.projectPatch, + headers: { "If-Match": queryArg["If-Match"] }, }), }), deleteProjectsByProjectId: build.mutation< @@ -90,6 +91,8 @@ export type PatchProjectsByProjectIdApiResponse = /** status 200 The patched project */ Project; export type PatchProjectsByProjectIdApiArg = { projectId: string; + /** If-Match header, for avoiding mid-air collisions */ + "If-Match": ETag; projectPatch: ProjectPatch; }; export type DeleteProjectsByProjectIdApiResponse = @@ -127,15 +130,17 @@ export type Repository = string; export type RepositoriesList = Repository[]; export type Visibility = "private" | "public"; export type Description = string; +export type ETag = string; export type Project = { id: Ulid; name: Name; - slug: Slug; + slug?: Slug; creation_date: CreationDate; created_by: Member; repositories?: RepositoriesList; visibility: Visibility; description?: Description; + etag?: ETag; }; export type ProjectsList = Project[]; export type ErrorResponse = { diff --git a/client/src/features/projectsV2/api/projectV2.enhanced-api.ts b/client/src/features/projectsV2/api/projectV2.enhanced-api.ts index be78289fd9..e295663d67 100644 --- a/client/src/features/projectsV2/api/projectV2.enhanced-api.ts +++ b/client/src/features/projectsV2/api/projectV2.enhanced-api.ts @@ -44,6 +44,9 @@ const injectedApi = api.injectEndpoints({ const enhancedApi = injectedApi.enhanceEndpoints({ addTagTypes: ["Project", "Members"], endpoints: { + postProjects: { + invalidatesTags: ["Project"], + }, deleteProjectsByProjectId: { invalidatesTags: ["Project"], }, diff --git a/client/src/features/projectsV2/api/projectV2.openapi.json b/client/src/features/projectsV2/api/projectV2.openapi.json index f8ad5ceae8..90143ff568 100644 --- a/client/src/features/projectsV2/api/projectV2.openapi.json +++ b/client/src/features/projectsV2/api/projectV2.openapi.json @@ -1,5 +1,5 @@ { - "openapi": "3.1.0", + "openapi": "3.0.2", "info": { "title": "Renku Project Management Service", "description": "Service that allows creating, updating, deleting, and managing Renku native projects.\nAll errors have the same format as the schema called ErrorResponse.\n", @@ -169,6 +169,9 @@ "schema": { "type": "string" } + }, + { + "$ref": "#/components/parameters/If-Match" } ], "requestBody": { @@ -395,16 +398,12 @@ }, "description": { "$ref": "#/components/schemas/Description" + }, + "etag": { + "$ref": "#/components/schemas/ETag" } }, - "required": [ - "id", - "name", - "slug", - "created_by", - "creation_date", - "visibility" - ], + "required": ["id", "name", "created_by", "creation_date", "visibility"], "example": { "id": "01AN4Z79ZS5XN0F25N3DB94T4R", "name": "Renku R Project", @@ -650,6 +649,11 @@ "description": "User email", "example": "some-user@gmail.com" }, + "ETag": { + "type": "string", + "description": "Entity Tag", + "example": "9EE498F9D565D0C41E511377425F32F3" + }, "ErrorResponse": { "type": "object", "properties": { @@ -688,6 +692,17 @@ } } } + }, + "parameters": { + "If-Match": { + "in": "header", + "name": "If-Match", + "description": "If-Match header, for avoiding mid-air collisions", + "required": true, + "schema": { + "$ref": "#/components/schemas/ETag" + } + } } } } diff --git a/client/src/features/projectsV2/show/ProjectV2EditForm.tsx b/client/src/features/projectsV2/show/ProjectV2EditForm.tsx index 3f0d0063ca..bfc085e388 100644 --- a/client/src/features/projectsV2/show/ProjectV2EditForm.tsx +++ b/client/src/features/projectsV2/show/ProjectV2EditForm.tsx @@ -49,6 +49,7 @@ import ProjectRepositoryFormField from "../fields/ProjectRepositoryFormField"; import ProjectVisibilityFormField from "../fields/ProjectVisibilityFormField"; import { SettingEditOption } from "./projectV2Show.types"; +import { RtkErrorAlert } from "../../../components/errors/RtkErrorAlert"; type ProjectV2Metadata = Omit; @@ -105,7 +106,7 @@ function ProjectDeleteConfirmation({