From 4ebac0ee4cbc9319c510777e90f03f115f2f66d2 Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Wed, 3 Jun 2026 10:12:28 +0200 Subject: [PATCH] feat: add 'Reset to deployed' action on draft-loaded toast --- .../src/lib/components/ResourceEditor.svelte | 25 ++++++++++- .../src/lib/components/VariableEditor.svelte | 28 +++++++++++- .../azure/AzureTriggerEditorInner.svelte | 10 ++++- .../email/EmailTriggerEditorInner.svelte | 10 ++++- .../triggers/gcp/GcpTriggerEditorInner.svelte | 10 ++++- .../triggers/http/RouteEditorInner.svelte | 10 ++++- .../kafka/KafkaTriggerEditorInner.svelte | 10 ++++- .../mqtt/MqttTriggerEditorInner.svelte | 10 ++++- .../nats/NatsTriggerEditorInner.svelte | 10 ++++- .../PostgresTriggerEditorInner.svelte | 10 ++++- .../schedules/ScheduleEditorInner.svelte | 19 +++++++- .../triggers/sqs/SqsTriggerEditorInner.svelte | 10 ++++- .../WebsocketTriggerEditorInner.svelte | 10 ++++- frontend/src/lib/userDraftToast.ts | 44 +++++++++++++++++++ .../(logged)/apps/edit/[...path]/+page.svelte | 13 +++++- .../apps_raw/edit/[...path]/+page.svelte | 12 ++++- .../flows/edit/[...path]/+page.svelte | 12 ++++- .../scripts/edit/[...path]/+page.svelte | 16 ++++++- 18 files changed, 247 insertions(+), 22 deletions(-) diff --git a/frontend/src/lib/components/ResourceEditor.svelte b/frontend/src/lib/components/ResourceEditor.svelte index 4acf693dfd..339dfadfc8 100644 --- a/frontend/src/lib/components/ResourceEditor.svelte +++ b/frontend/src/lib/components/ResourceEditor.svelte @@ -5,6 +5,7 @@ import { createEventDispatcher, untrack } from 'svelte' import { userStore, workspaceStore } from '$lib/stores' import { sendUserToast } from '$lib/toast' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { clearJsonSchemaResourceCache } from './schema/jsonSchemaResource.svelte' import ResourceForm from './ResourceForm.svelte' import { invalidateWorkspacePaths } from './PathNameAutocomplete.svelte' @@ -254,7 +255,29 @@ getUserExt(ws) ]).then(([r, user]) => { if (r.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: ws, + itemKind: 'resource', + path: initialPath ?? '', + onResetToDeployed: async () => { + const fresh = await ResourceService.getResource({ + workspace: ws, + path: initialPath ?? '' + }) + const deployed: ResourceState = { + path: fresh.path, + description: fresh.description ?? '', + args: (fresh.value ?? {}) as any, + labels: fresh.labels ?? undefined, + wsSpecific: fresh.ws_specific ?? false + } + fetchedResources[ws] = fresh + fetchedRev[ws] = fresh.edited_at + initialStates[ws] = structuredClone(deployed) + const handle = states[ws] + if (handle) handle.setDraftAndMeta(undefined, { remoteRev: fresh.edited_at }) + } + }) } fetchedResources[ws] = r fetchedRev[ws] = r.edited_at diff --git a/frontend/src/lib/components/VariableEditor.svelte b/frontend/src/lib/components/VariableEditor.svelte index 3a6403c6e5..aa0f59c18f 100644 --- a/frontend/src/lib/components/VariableEditor.svelte +++ b/frontend/src/lib/components/VariableEditor.svelte @@ -7,6 +7,7 @@ import DrawerContent from './common/drawer/DrawerContent.svelte' import Alert from './common/alert/Alert.svelte' import { sendUserToast } from '$lib/toast' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { canWrite } from '$lib/utils' import { Save } from 'lucide-svelte' import VariableForm from './VariableForm.svelte' @@ -168,7 +169,32 @@ getUserExt(ws) ]).then(([v, user]) => { if (v.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: ws, + itemKind: 'variable', + path: p, + onResetToDeployed: async () => { + const fresh = await VariableService.getVariable({ + workspace: ws, + path: p, + decryptSecret: false + }) + const deployed: VariableState = { + path: fresh.path, + variable: { + value: fresh.value ?? '', + is_secret: fresh.is_secret, + description: fresh.description ?? '' + }, + labels: fresh.labels ?? undefined, + wsSpecific: fresh.ws_specific ?? false + } + fetchedRev[ws] = fresh.edited_at + initialStates[ws] = structuredClone(deployed) + const handle = states[ws] + if (handle) handle.setDraftAndMeta(undefined, { remoteRev: fresh.edited_at }) + } + }) } fetchedRev[ws] = v.edited_at const s: VariableState = { diff --git a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte index 463ed01021..8994e37b2f 100644 --- a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte @@ -5,6 +5,7 @@ import Path from '$lib/components/Path.svelte' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import { Loader2 } from 'lucide-svelte' import Label from '$lib/components/Label.svelte' @@ -196,7 +197,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_azure', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) } catch (error) { diff --git a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte index 13c026fef3..a6948976a2 100644 --- a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte @@ -15,6 +15,7 @@ } from '$lib/gen' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import Section from '$lib/components/Section.svelte' import { Loader2 } from 'lucide-svelte' import Label from '$lib/components/Label.svelte' @@ -217,7 +218,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_email', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte index 478844616f..dbf0f92572 100644 --- a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte @@ -5,6 +5,7 @@ import Path from '$lib/components/Path.svelte' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import { Loader2 } from 'lucide-svelte' import Label from '$lib/components/Label.svelte' @@ -200,7 +201,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_gcp', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) } catch (error) { diff --git a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte index 9b4622497f..bb6bae0c41 100644 --- a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte +++ b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte @@ -23,6 +23,7 @@ generateRandomString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import Section from '$lib/components/Section.svelte' import { Loader2, Pipette, Plus } from 'lucide-svelte' import Label from '$lib/components/Label.svelte' @@ -350,7 +351,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_http', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) diff --git a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte index 5136302a53..c94fcebd9e 100644 --- a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte @@ -9,6 +9,7 @@ import { KafkaTriggerService, type ErrorHandler, type Retry, type TriggerMode } from '$lib/gen' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import Section from '$lib/components/Section.svelte' import { Loader2, RotateCcw } from 'lucide-svelte' @@ -256,7 +257,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_kafka', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) } diff --git a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte index a55b112ad8..24083be733 100644 --- a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte @@ -8,6 +8,7 @@ import ScriptPicker from '$lib/components/ScriptPicker.svelte' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import Section from '$lib/components/Section.svelte' import { Loader2 } from 'lucide-svelte' @@ -256,7 +257,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_mqtt', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) } diff --git a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte index 15e78694e1..504623f688 100644 --- a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte @@ -8,6 +8,7 @@ import { NatsTriggerService, type ErrorHandler, type Retry, type TriggerMode } from '$lib/gen' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import Section from '$lib/components/Section.svelte' import { Loader2 } from 'lucide-svelte' @@ -238,7 +239,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_nats', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) } diff --git a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte index 403a929e93..e121e2aac7 100644 --- a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte @@ -15,6 +15,7 @@ } from '$lib/gen' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, emptyString, emptyStringTrimmed, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import Section from '$lib/components/Section.svelte' import { Loader2 } from 'lucide-svelte' @@ -382,7 +383,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_postgres', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } const publication_data = await PostgresTriggerService.getPostgresPublication({ diff --git a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte index e807301046..d830b82089 100644 --- a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte +++ b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte @@ -25,6 +25,7 @@ } from '$lib/gen' import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores' import { canWrite, emptyString, formatCron, sendUserToast, cronV1toV2 } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { base } from '$lib/base' import Section from '$lib/components/Section.svelte' import { List, Loader2, Save, AlertTriangle } from 'lucide-svelte' @@ -292,7 +293,14 @@ getDraft: true }) if (resp.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_schedule', + path: schedule_path, + onResetToDeployed: async () => { + await openNew(nis_flow, initial_script_path, defaultValues, schedule_path) + } + }) } s = resp initNewPath = true @@ -466,7 +474,14 @@ getDraft: true }) if (s.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_schedule', + path: initialPath, + onResetToDeployed: async () => { + await loadSchedule() + } + }) } await loadScheduleCfg(s) } catch (err) { diff --git a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte index 02cc4e057f..1d63505c85 100644 --- a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte @@ -5,6 +5,7 @@ import Path from '$lib/components/Path.svelte' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import { Loader2 } from 'lucide-svelte' import Label from '$lib/components/Label.svelte' @@ -233,7 +234,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_sqs', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) } diff --git a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte index e63c87071f..dd41794923 100644 --- a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte @@ -21,6 +21,7 @@ } from '$lib/gen' import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores' import { canWrite, emptySchema, emptyString, sendUserToast } from '$lib/utils' + import { notifyDraftLoaded } from '$lib/userDraftToast' import { withForkConflictRetry } from '$lib/utils/forkConflict' import Section from '$lib/components/Section.svelte' import { Loader2, X, Plus } from 'lucide-svelte' @@ -313,7 +314,14 @@ getDraft: true }) if (s?.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'trigger_websocket', + path: initialPath, + onResetToDeployed: async () => { + await loadTrigger() + } + }) } loadTriggerConfig(s) } diff --git a/frontend/src/lib/userDraftToast.ts b/frontend/src/lib/userDraftToast.ts index 7e3e48d211..89d16c9295 100644 --- a/frontend/src/lib/userDraftToast.ts +++ b/frontend/src/lib/userDraftToast.ts @@ -5,6 +5,8 @@ * site (route-specific state). */ import { sendUserToast } from '$lib/toast' +import { UserDraftDbSyncer } from '$lib/userDraftDbSyncer.svelte' +import type { UserDraftItemKind } from '$lib/gen' export type RestoreFromLocalActions = { /** Drop the local autosave, apply the backend DB draft. Offered when `hasBackendDraft`. */ @@ -29,3 +31,45 @@ export function notifyRestoredFromLocal( if (actions.length === 0) return sendUserToast('Restored from local storage', false, actions) } + +/** + * Shown when an editor mounts on a per-user draft fetched from the server + * (the `get_draft=true` overlay returned `is_draft: true`). Offers a + * "Reset to deployed" action that: + * 1. POSTs `value: null` to delete the user's draft for this entity, and + * 2. invokes `onResetToDeployed` so the editor can re-fetch without the + * overlay and apply the pure deployed version. + * + * Failures in either step surface a follow-up toast and leave the editor + * state untouched. + */ +export function notifyDraftLoaded(opts: { + workspace: string + itemKind: UserDraftItemKind + path: string + onResetToDeployed: () => void | Promise +}): void { + sendUserToast('Loaded your saved draft', false, [ + { + label: 'Reset to deployed', + callback: async () => { + try { + await UserDraftDbSyncer.save({ + workspace: opts.workspace, + itemKind: opts.itemKind, + path: opts.path, + value: null + }) + } catch (e: any) { + sendUserToast(`Could not delete draft: ${e?.body ?? e}`, true) + return + } + try { + await opts.onResetToDeployed() + } catch (e: any) { + sendUserToast(`Could not reset to deployed: ${e?.body ?? e}`, true) + } + } + } + ]) +} 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 68ac5e088a..383e648cbd 100644 --- a/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte @@ -15,7 +15,7 @@ import { untrack } from 'svelte' import { page } from '$app/state' import { UserDraft, checkStaleness, type UserDraftMeta } from '$lib/userDraft.svelte' - import { notifyRestoredFromLocal } from '$lib/userDraftToast' + import { notifyDraftLoaded, notifyRestoredFromLocal } from '$lib/userDraftToast' let app = $state(undefined as (AppWithLastVersion & { value: any }) | undefined) let savedApp: @@ -119,7 +119,16 @@ }) if (tok !== loadAppToken) return if (backendApp.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'app', + path: page.params.path ?? '', + onResetToDeployed: async () => { + UserDraft.remove('app', path) + await loadApp() + redraw++ + } + }) } const backendApp_ = structuredClone(stateSnapshot(backendApp)) savedApp = { diff --git a/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte index 15c029fe06..33e75dc80d 100644 --- a/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte @@ -19,7 +19,7 @@ localDraftDiffers, type UserDraftMeta } from '$lib/userDraft.svelte' - import { notifyRestoredFromLocal } from '$lib/userDraftToast' + import { notifyDraftLoaded, notifyRestoredFromLocal } from '$lib/userDraftToast' import LocalDraftStaleModal from '$lib/components/common/confirmationModal/LocalDraftStaleModal.svelte' import OtherUsersDraftsModal from '$lib/components/common/confirmationModal/OtherUsersDraftsModal.svelte' @@ -199,7 +199,15 @@ })) as any if (tok !== loadAppToken) return if (backendApp.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'raw_app', + path: page.params.path ?? '', + onResetToDeployed: async () => { + draftHandle.setDraftAndMeta(undefined, {}) + await loadApp() + } + }) } // When the backend falls back to `fetch_draft_only` (no deployed // row at this path, only a per-user draft), the response's inner 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 28dbd2e3f3..6e34f7d0fc 100644 --- a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte @@ -29,7 +29,7 @@ type UserDraftMeta, type UserDraftHandle } from '$lib/userDraft.svelte' - import { notifyRestoredFromLocal } from '$lib/userDraftToast' + import { notifyDraftLoaded, notifyRestoredFromLocal } from '$lib/userDraftToast' let version: undefined | number = $state(undefined) @@ -218,7 +218,15 @@ }) if (tok !== loadFlowToken) return if (backendFlow.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'flow', + path: page.params.path ?? '', + onResetToDeployed: async () => { + flowHandle.setDraftAndMeta(undefined, {}) + await loadFlow() + } + }) } savedFlow = structuredClone($state.snapshot(backendFlow)) as Flow 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 fac2acc044..c540b1efea 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte @@ -21,7 +21,7 @@ type UserDraftMeta, type UserDraftHandle } from '$lib/userDraft.svelte' - import { notifyRestoredFromLocal } from '$lib/userDraftToast' + import { notifyDraftLoaded, notifyRestoredFromLocal } from '$lib/userDraftToast' type EditableScript = NewScript & { draft_triggers?: Trigger[] } @@ -183,7 +183,19 @@ }) if (tok !== loadScriptToken) return if (backendScript.is_draft) { - sendUserToast('Loaded your saved draft') + notifyDraftLoaded({ + workspace: $workspaceStore!, + itemKind: 'script', + path: page.params.path ?? '', + onResetToDeployed: async () => { + // Drop the in-memory draft so loadScript's no-localDraft + // branch fires; the next fetch with `getDraft: true` will + // return pure deployed because we just deleted the draft + // row server-side. + scriptHandle.setDraftAndMeta(undefined, {}) + await loadScript() + } + }) } savedScript = structuredClone($state.snapshot(backendScript))