diff --git a/frontend/src/lib/components/apps/editor/AppEditor.svelte b/frontend/src/lib/components/apps/editor/AppEditor.svelte index 565ac5d5d3..073d6c3e7d 100644 --- a/frontend/src/lib/components/apps/editor/AppEditor.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditor.svelte @@ -85,7 +85,8 @@ loadedFromDraft = false, othersDraftsCount = 0, onOpenOthersDrafts, - onRestore + onRestore, + onDeploy }: AppEditorProps = $props() migrateApp(untrack(() => app)) @@ -893,6 +894,7 @@ {othersDraftsCount} {onOpenOthersDrafts} {onRestore} + {onDeploy} {policy} {fromHub} bind:this={appEditorHeader} diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index ccc22618a1..b4724805e2 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -110,6 +110,9 @@ // (not `on:restore` forwarding): forwarding a `createEventDispatcher` // event up through these runes-mode components silently drops it. onRestore?: (restoredApp: any) => void + // Fired after a successful deploy, which keeps this editor open: `version` is what + // the deploy wrote, for the next draft's fork base, and `head` what is deployed now. + onDeploy?: (e: { version?: number; head?: number }) => void } let { @@ -137,7 +140,8 @@ loadedFromDraft = false, othersDraftsCount = 0, onOpenOthersDrafts, - onRestore + onRestore, + onDeploy }: Props = $props() /** Mirror of the path the user is editing in the pen popover. Initialized @@ -410,6 +414,9 @@ // superseded base and falsely warn. parent_version is in // DRAFT_COMPARE_IGNORED_FIELDS, so this write can't spawn a spurious draft. if ($app) $app.parent_version = claimed + // The route owns the pair the out-of-date prompt reads, and this editor stays open + // across the deploy, so hand both over rather than leaving it on the old ones. + onDeploy?.({ version: claimed, head: version }) closeSaveDrawer() sendUserToast('App deployed successfully') diff --git a/frontend/src/lib/components/apps/types.ts b/frontend/src/lib/components/apps/types.ts index 960e273ac3..76e138893a 100644 --- a/frontend/src/lib/components/apps/types.ts +++ b/frontend/src/lib/components/apps/types.ts @@ -183,6 +183,10 @@ export interface AppEditorProps { // AppEditorHeader as a callback prop rather than `on:restore` forwarding, // which does not propagate through these runes-mode components. onRestore?: (restoredApp: any) => void + // Fired after a successful deploy, which keeps this editor open: `version` is what + // the deploy wrote, for the next draft's fork base, and `head` what is deployed now. + // The two differ when another deploy landed beside this one. + onDeploy?: (e: { version?: number; head?: number }) => void } export type App = { diff --git a/frontend/src/lib/components/raw_apps/RawAppEditor.svelte b/frontend/src/lib/components/raw_apps/RawAppEditor.svelte index aec049e8cf..9d8f288bbe 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditor.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditor.svelte @@ -102,9 +102,10 @@ | undefined diffDrawer?: DiffDrawer | undefined onNavigate?: (item: import('$lib/components/workspacePicker').WorkspaceItem) => void - /** Fired after a successful deploy; the session preview reloads on it and - * the route re-pins the draft's fork base to the version just written. */ - onDeploy?: (e: { path: string; version?: number }) => void + /** Fired after a successful deploy; the session preview reloads on it and the route + * re-pins the draft's fork base. `version` is what this deploy wrote and `head` + * what is deployed now: the two differ when another deploy landed beside it. */ + onDeploy?: (e: { path: string; version?: number; head?: number }) => void /** Initial collapsed state for the file/runnable sidebar. The user's * toggled preference is persisted under `sidebarStorageKey`; this prop * only seeds the very first open. */ 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 f1e309ba14..8e95a0842c 100644 --- a/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/apps/edit/[...path]/+page.svelte @@ -495,6 +495,15 @@ {loadedFromDraft} othersDraftsCount={otherDraftsUsers.length} onOpenOthersDrafts={() => (othersModalOpen = true)} + onDeploy={({ version, head }) => { + // The editor stays open across a deploy, so the pair the out-of-date prompt + // reads has to move with it: the base is what the deploy could claim it + // wrote (unknown when another landed beside it), the head what is deployed. + draftBaseVersion = version != null ? String(version) : undefined + if (head != null) { + deployedHeadVersion = String(head) + } + }} /> {/if} 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 a69c5416ec..f1f39306f0 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte @@ -578,6 +578,12 @@ onDeploy={(e) => { // "Deploy & Stay here" / lib: stay on the editor (just confirm). if (e.stay) { + // The editor is now on the version it just wrote, and so is the draft the + // builder re-pinned. Without this the prompt and the drawer keep comparing + // the pre-deploy pair, so Diff offers Take latest against a head the next + // draft is already on. + draftBaseHash = e.hash + deployedHeadHash = e.hash sendUserToast('Deployed') return }