fix: a head nobody could name is not behind, so take latest is not offered without one

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-09-15 09:20:06 +02:00
co-authored by Claude Opus 5
parent 062adc284b
commit f5c97aae13
5 changed files with 25 additions and 8 deletions
+17 -7
View File
@@ -53,6 +53,7 @@
versions?: DiffVersionOption[]
onTakeLatest?: (head?: string) => void | Promise<void>
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<Value | undefined>
onTakeLatest?: (head?: string) => void | Promise<void>
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,
@@ -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!,
@@ -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({
+5 -1
View File
@@ -33,8 +33,12 @@ export type DiffDrawerDiff =
* the base adopted is the one the reader just looked at. */
onTakeLatest?: (head?: string) => void | Promise<void>
/** 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'
@@ -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