From 16b94ebf45557c242e1a6dd62427e45ba75e1115 Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Mon, 7 Sep 2026 19:34:07 +0200 Subject: [PATCH] fix(schedules): apply a toggle's result to the schedule it toggled, not the one on screen Same rule as the save beside it, which the last commit fixed and this path did not: the editor is reused when its drawer switches rows, so a toggle resolving after that wrote its result into the newly opened schedule's baseline and settled the toggled one's draft against the new form. The toggled schedule's baseline is now read before the request, so its draft is settled from its own value whether or not this editor still shows it, and nothing is adopted into the item that took its place. Also gates the variable editor's Save in create mode, where there is no cell to key the shared window on, and reunites the settle rationale in the test file with the block it documents. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KcyBRxE8j3ujCYkum9KrC4 --- .../src/lib/components/VariableEditor.svelte | 24 +++++++++++---- .../schedules/ScheduleEditorInner.svelte | 29 ++++++++++++------- .../src/lib/userDraftSettleAfterWrite.test.ts | 10 +++---- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/frontend/src/lib/components/VariableEditor.svelte b/frontend/src/lib/components/VariableEditor.svelte index 1c92f4350d..045778df16 100644 --- a/frontend/src/lib/components/VariableEditor.svelte +++ b/frontend/src/lib/components/VariableEditor.svelte @@ -291,6 +291,9 @@ const saveInFlight = $derived( dirtyWorkspaces.some((ws) => isDraftSaving('variable', editPath, { workspace: ws })) ) + // A create has no cell to key that on — its form is the detached handle an empty + // path gets — so the one case the shared window cannot see keeps a local flag. + let creating = $state(false) async function save(): Promise { // Everything the writes need, read before the first await. An inline host can @@ -326,6 +329,10 @@ // is in flight for this cell, so a second editor on it cannot start one — // checked before the first is opened, or this would see its own. if (payloads.some(({ ws }) => isDraftSaving('variable', from, { workspace: ws }))) return + if (!from) { + if (creating) return + creating = true + } const closeSettleWindows = from ? payloads.map(({ ws }) => beginDraftSettleWindow('variable', from, { workspace: ws })) : [] @@ -373,11 +380,10 @@ // to it via `discard` (not `remove` — blanking the cell to `undefined` reads // as dirty) and keeps an edit made mid-request. Each workspace settles // against the path its own write used, not the reported one. - // The live cell only while this editor is still on the item it saved: the - // drawer is reused, so after a re-point `states` is the next item's, and - // reading it here would take that for an edit made over this write — - // leaving this item's draft behind. Re-pointed, the cell it released - // during the write is what answers. + // The live cell only while this editor is still on the item it saved: reused + // for the next one, `states` is that one's, and reading it here would take + // it for an edit made over this write. Re-pointed, the cell released + // during the write answers instead. await settleDraftAfterWrite( 'variable', s, @@ -426,6 +432,7 @@ } } finally { for (const close of closeSettleWindows) close() + creating = false } } @@ -470,7 +477,12 @@ {/if}