From 4264c3d9a75c6ec8022c904ca574115ccdf0346f Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Mon, 8 Jun 2026 15:35:25 +0200 Subject: [PATCH] refactor(drafts): type UserDraftOverlay.other_drafts_users in the OpenAPI The backend response carried other_drafts_users on every get-by-path that supports the draft overlay, but the OpenAPI schema didn't declare the field. Each route had to cast the typed response to `any` to read it (and the sibling draft_saved_at), which obscured the real shape from the type system and rotted the discoverability of the draft surface. Add it to UserDraftOverlay. Frontend casts collapse to plain property reads in the three editor routes. --- backend/windmill-api/openapi.yaml | 19 +++++++++++++++++++ .../(logged)/apps/edit/[...path]/+page.svelte | 4 ++-- .../flows/edit/[...path]/+page.svelte | 4 ++-- .../scripts/edit/[...path]/+page.svelte | 4 ++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 80cdcf5b1b..f363ea02a0 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -21049,6 +21049,25 @@ components: draft: type: object additionalProperties: true + other_drafts_users: + description: | + Other workspace users (and the legacy NULL-email row, if any) + with a saved draft at the same path. Populated only on the + authed user's "get by path" responses for kinds the editor + surfaces a fork banner for (script, flow, app, raw_app). + Empty / omitted for kinds without that UI. + type: array + items: + type: object + properties: + username: + type: string + email: + type: string + draft_saved_at: + type: string + format: date-time + required: [draft_saved_at] required: [is_draft] UserDraftItemKind: type: string diff --git a/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte index 4d03011ae4..ef8e5a56e0 100644 --- a/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte @@ -100,11 +100,11 @@ getDraft }) if (tok !== loadAppToken) return - otherDraftsUsers = ((backendApp as any).other_drafts_users ?? []) as OtherDraftUser[] + otherDraftsUsers = (backendApp.other_drafts_users ?? []) as OtherDraftUser[] if ($workspaceStore && path) { UserDraftDbSyncer.recordRemoteSync( { workspace: $workspaceStore, itemKind: 'app', path }, - (backendApp as any).draft_saved_at as string | undefined + backendApp.draft_saved_at ) } // Apply the user's saved draft to `.value`. The autosave for apps diff --git a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte index 3ae76d2732..a83709fc2c 100644 --- a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte @@ -203,11 +203,11 @@ getDraft }) if (tok !== loadFlowToken) return - otherDraftsUsers = ((backendFlow as any).other_drafts_users ?? []) as OtherDraftUser[] + otherDraftsUsers = (backendFlow.other_drafts_users ?? []) as OtherDraftUser[] if ($workspaceStore && flowDraftPath) { UserDraftDbSyncer.recordRemoteSync( { workspace: $workspaceStore, itemKind: 'flow', path: flowDraftPath }, - (backendFlow as any).draft_saved_at as string | undefined + backendFlow.draft_saved_at ) } // Re-evaluate the "new flow" signal on each load — flips to diff --git a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte index 5a31107772..333a259273 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte @@ -148,7 +148,7 @@ getDraft }) if (tok !== loadScriptToken) return - otherDraftsUsers = ((backendScript as any).other_drafts_users ?? []) as OtherDraftUser[] + otherDraftsUsers = (backendScript.other_drafts_users ?? []) as OtherDraftUser[] // Seed the per-tab `last_sync` map with the server's draft // timestamp so the next autosave attaches a matching // `last_sync` and the backend can reject stale writes. @@ -157,7 +157,7 @@ if ($workspaceStore && page.params.path) { UserDraftDbSyncer.recordRemoteSync( { workspace: $workspaceStore, itemKind: 'script', path: page.params.path }, - (backendScript as any).draft_saved_at as string | undefined + backendScript.draft_saved_at ) } if (backendScript.is_draft) {