diff --git a/frontend/src/lib/components/DiffDrawer.svelte b/frontend/src/lib/components/DiffDrawer.svelte index 01b8c67d1d..bda1d82a89 100644 --- a/frontend/src/lib/components/DiffDrawer.svelte +++ b/frontend/src/lib/components/DiffDrawer.svelte @@ -53,6 +53,7 @@ versions?: DiffVersionOption[] onTakeLatest?: (head?: string) => void | Promise draftBase?: string + deployedHead?: string draft: DiffData | undefined current: DiffData path?: string @@ -140,16 +141,22 @@ } } - /** The version this drawer presents as the deployed head, when it has a list to say - * so. Both the action's gate and the base it adopts hang off it, so "take latest" - * means the version the reader is looking at. */ + /** The version this drawer presents as the deployed head: the one its list marks, else + * the head the editor knows. Both the action's gate and the base it adopts hang off + * it, so "take latest" means the version the reader is looking at. */ const headShown = $derived.by(() => - data?.mode === 'normal' ? data.versions?.find((v) => v.isHead)?.id : undefined + data?.mode === 'normal' + ? (data.versions?.find((v) => v.isHead)?.id ?? data.deployedHead) + : undefined ) - /** Behind as the drawer can see it: a base that is not the head on display. With no - * version list there is nothing to compare, so the editor's own gate stands. */ + /** Behind as the drawer can see it. Unknown counts as not behind: offering to adopt a + * head nobody could name would move the base to a version never shown. */ const behindShown = $derived.by( - () => data?.mode === 'normal' && (headShown == null || data.draftBase !== headShown) + () => + data?.mode === 'normal' && + data.draftBase != null && + headShown != null && + data.draftBase !== headShown ) let takingLatest = $state(false) @@ -174,6 +181,7 @@ loadVersion?: (id: string) => Promise onTakeLatest?: (head?: string) => void | Promise draftBase?: string + deployedHead?: string draft?: Value | undefined current: Value defaultDiffType?: 'deployed' | 'draft' @@ -195,6 +203,7 @@ loadVersion, onTakeLatest, draftBase, + deployedHead, draft, current, button @@ -213,6 +222,7 @@ versions, onTakeLatest, draftBase, + deployedHead, draft: draft ? prepareDiff(draft) : undefined, current: prepareDiff(current), path: draft?.path || deployed?.path, diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 668135db37..e69c61439c 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -1176,6 +1176,7 @@ versions: await deployedVersionOptions(), onTakeLatest, draftBase: draftBaseVersion, + deployedHead: version != null ? String(version) : undefined, loadVersion: async (id) => { const v = await FlowService.getFlowVersion({ workspace: opWorkspace!, diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index 91b81b2d22..61c3928a1d 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -900,6 +900,7 @@ versions: await deployedVersionOptions(headHash), onTakeLatest, draftBase: draftBaseHash, + deployedHead: headHash, loadVersion: async (hash) => { const v = await ScriptService.getScriptByHash({ workspace: opWorkspace!, hash }) return replaceFalseWithUndefined({ diff --git a/frontend/src/lib/components/diff_drawer.ts b/frontend/src/lib/components/diff_drawer.ts index fd3222f8f9..6e7c113db1 100644 --- a/frontend/src/lib/components/diff_drawer.ts +++ b/frontend/src/lib/components/diff_drawer.ts @@ -33,8 +33,12 @@ export type DiffDrawerDiff = * the base adopted is the one the reader just looked at. */ onTakeLatest?: (head?: string) => void | Promise /** The version the draft forked from. The drawer offers `onTakeLatest` only - * while it differs from the head on display. */ + * while it differs from the head, and passes that head to it. */ draftBase?: string + /** The deployed head as the editor knows it, used when no `versions` list + * loaded. Without either, the drawer cannot tell whether the draft is behind + * and offers nothing. */ + deployedHead?: string draft?: Value | undefined current: Value defaultDiffType?: 'deployed' | 'draft' diff --git a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte index 0675c2eb8a..f5e6d3d781 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte @@ -465,6 +465,7 @@ versions: await deployedVersionOptions(), onTakeLatest, draftBase: draftBaseVersion, + deployedHead: deployedVersionShown != null ? String(deployedVersionShown) : undefined, loadVersion: async (id) => { const v = await AppService.getAppByVersion({ workspace: opWorkspace!, id: Number(id) }) // Same normalization as `syncWithDeployed`, so switching versions doesn't