From a4da7d3ee6c033ec6857890a8c847dd7f3ff0fb3 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 15 Sep 2026 01:26:36 +0200 Subject: [PATCH] fix: take latest re-reads the head at click time; type the kept head as prepared diff data Co-Authored-By: Claude Opus 5 (1M context) --- frontend/src/lib/components/DiffDrawer.svelte | 9 +++++---- .../(logged)/apps_raw/edit/[...path]/+page.svelte | 10 +++++++++- .../(root)/(logged)/flows/edit/[...path]/+page.svelte | 10 +++++++++- .../(logged)/scripts/edit/[...path]/+page.svelte | 11 ++++++++++- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/components/DiffDrawer.svelte b/frontend/src/lib/components/DiffDrawer.svelte index 40df701b4d..edb8b1e9dd 100644 --- a/frontend/src/lib/components/DiffDrawer.svelte +++ b/frontend/src/lib/components/DiffDrawer.svelte @@ -94,10 +94,11 @@ let selectedVersion: string | undefined = $state(undefined) let versionLoader: ((id: string) => Promise) | undefined = $state(undefined) let headLabel: string | undefined = $state(undefined) - /** The deployed head as it was handed to `setDiff`. `data.deployed` follows the - * picker, and Restore always restores the head, so its enabled state compares - * against this rather than whichever version is on display. */ - let headDeployed: Value | undefined = $state(undefined) + /** The deployed head, prepared for diffing as `data.deployed` is: `data.deployed` + * follows the picker while Restore always restores the head, so its enabled state + * compares against this. Must hold `prepareDiff`'s output, not the raw value, or the + * comparison never matches and Restore is always enabled. */ + let headDeployed: ReturnType | undefined = $state(undefined) let loadingVersion = $state(false) /** Which version load the spinner belongs to, counted rather than keyed on the id so * re-picking the same version is still generation-safe. A response from any other 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 a60fbf9d69..203773d30b 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 @@ -629,7 +629,15 @@ deployedHeadVersion && draftBaseVersion !== deployedHeadVersion ? async () => { - const head = Number(deployedHeadVersion) + // Re-read rather than trusting the head this page loaded with; see + // /scripts/edit. + const head = + ( + await AppService.getAppLatestVersion({ + workspace: $workspaceStore!, + path: page.params.path ?? '' + }).catch(() => undefined) + )?.version ?? Number(deployedHeadVersion) parentVersion = head if (deployedBaseline) deployedBaseline = { ...deployedBaseline, parent_version: head } draftBaseVersion = String(head) 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 97b636e4b0..a97113fd12 100644 --- a/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/edit/[...path]/+page.svelte @@ -546,7 +546,15 @@ { - const head = version + // Re-read rather than trusting the head this page loaded with; see + // /scripts/edit. + const head = + ( + await FlowService.getFlowLatestVersion({ + workspace: $workspaceStore!, + path: flowDraftPath + }).catch(() => undefined) + )?.id ?? version if (!draftSync.draft || head == null || !$workspaceStore) return draftSync.draft = { ...draftSync.draft, version_id: head } draftBaseVersion = String(head) 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 f0f9546160..4757c11a21 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte @@ -527,7 +527,16 @@ userDraftPath={draftPath} onTakeLatest={draftBaseHash && deployedHeadHash && draftBaseHash !== deployedHeadHash ? async () => { - const head = deployedHeadHash + // Re-read rather than trusting the head this page loaded with: taking a + // stale one would say the draft is up to date with a version that is not + // the latest any more. + const head = + ( + await ScriptService.getScriptLatestVersion({ + workspace: $workspaceStore!, + path: draftPath + }).catch(() => undefined) + )?.script_hash ?? deployedHeadHash if (!draftSync.draft || !head || !$workspaceStore) return draftSync.draft = { ...draftSync.draft, parent_hash: head } // The baseline mirrors the draft's base so an unedited draft still