fix: the route's lineage follows an in-place deploy, and the raw-app editor's event type carries the head

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-09-15 16:22:51 +02:00
co-authored by Claude Opus 5
parent b95cc73857
commit 61d13cb72e
6 changed files with 34 additions and 5 deletions
@@ -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}
@@ -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')
@@ -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 = {
@@ -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. */
@@ -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)
}
}}
/>
</div>
{/if}
@@ -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
}