From 228da1bfca3e71a71e670fc232eca65e68fdd7d9 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 14 Sep 2026 18:05:28 +0200 Subject: [PATCH] fix: follow a variable the drawer renamed and stayed open on Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_015vn1jCHUcAdaG9C4NsUehF --- .../src/lib/components/VariableEditor.svelte | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/components/VariableEditor.svelte b/frontend/src/lib/components/VariableEditor.svelte index d959278479..d5cb51da87 100644 --- a/frontend/src/lib/components/VariableEditor.svelte +++ b/frontend/src/lib/components/VariableEditor.svelte @@ -50,9 +50,11 @@ // default comes from the navigation store. let curWs = $derived(workspace ?? $workspaceStore) + /** The variable opened for editing, where it is stored: a rename the drawer outlived moves it. */ let editPath: string | undefined = $state(undefined) - /** The item open in the drawer: `editPath`, or a temporary path while creating one. */ - let itemPath: string | undefined = $state(undefined) + /** Each workspace's item in the drawer: where it is stored, or a temporary path while creating + * one. */ + let paths = $state>({}) let template: VariableState | undefined = undefined /** Bumped by every opening, so reopening an item reads it afresh. */ let session = $state(0) @@ -143,13 +145,13 @@ () => workspaces.map((ws) => ({ workspace: ws, - path: itemPath, + path: paths[ws], template, session, valid: () => isValid(items[ws]?.value), writable: () => { const perms = extraPermsOf(ws) - return !perms || canWrite(editPath ?? '', perms, acting.in(ws)) + return !perms || canWrite(paths[ws] ?? '', perms, acting.in(ws)) } })), variableAdapter @@ -171,12 +173,22 @@ // Open the selected workspace's version of the item alongside the others. $effect(() => { const ws = selected - if (!ws || !itemPath) return + if (!ws || workspaces.length === 0) return untrack(() => { - if (!workspaces.includes(ws)) workspaces.push(ws) + if (workspaces.includes(ws)) return + paths[ws] = editPath ?? paths[workspaces[0]] + workspaces.push(ws) }) }) + // The page anchor names the variable on screen, which a rename the drawer outlived moves. + $effect(() => { + const path = editPath + if (path !== undefined && untrack(() => drawer?.isOpen())) { + setPageDrawerAnchor(VARIABLES_PATH, path) + } + }) + let drawer: Drawer | undefined = $state() const deployTo = resource( @@ -251,7 +263,7 @@ closeOnSettle = false pathError = '' acting.forgetFailures() - itemPath = path + paths = { [ws]: path } workspaces = [ws] selected = ws session++ @@ -288,8 +300,19 @@ async function save(): Promise { const targets = dirtyWorkspaces.map((ws) => items[ws]) const updated = edit + const opening = session + const shown = selected closeOnSettle = true const outcomes = await saveEach(targets) + // A save the drawer outlives may have created or renamed what it shows: follow each item to + // where it is stored, keeping its handle rather than reading it afresh. + if (session === opening) { + for (const ws of workspaces) { + const at = items[ws]?.key.path + if (at && !isTemporaryPath(at) && at !== paths[ws]) paths[ws] = at + } + if (editPath !== undefined && shown && paths[shown]) editPath = paths[shown] + } const failed = outcomes.find((o) => !o.ok && !o.skipped) if (failed && !failed.ok) { sendUserToast(`Could not save variable: ${failed.error}`, true)