diff --git a/frontend/src/lib/components/ResourceEditor.svelte b/frontend/src/lib/components/ResourceEditor.svelte index 19e55138c2..6827eb74f5 100644 --- a/frontend/src/lib/components/ResourceEditor.svelte +++ b/frontend/src/lib/components/ResourceEditor.svelte @@ -2,7 +2,7 @@ import type { Schema } from '$lib/common' import { ResourceService, WorkspaceService, type Resource, type ResourceType } from '$lib/gen' import { canWrite } from '$lib/utils' - import { createEventDispatcher, onDestroy, untrack } from 'svelte' + import { createEventDispatcher, untrack } from 'svelte' import { userStore, workspaceStore } from '$lib/stores' import { sendUserToast } from '$lib/toast' import { clearJsonSchemaResourceCache } from './schema/jsonSchemaResource.svelte' @@ -49,32 +49,41 @@ let effectiveWorkspace = $derived(workspace ?? $workspaceStore!) let initialPath = path - // Per-workspace handles. Each workspace's autosave lives at its own - // localStorage key (`userdraft/w/{ws}/resource/{initialPath}`) so editing - // the same path across two workspaces stays cleanly separated. - let states: Record> = $state({}) + // Per-workspace handles are driven by `useMany`. We track the workspace + // IDs (and their seeded defaults) in a parallel `$state` array; on every + // mutation `useMany` reconciles, acquiring entries for new workspaces and + // releasing them on component teardown. `states` indexes the resulting + // handles by workspace ID for ergonomic lookup downstream. + let workspaceSpecs = $state>([]) let initialStates: Record = $state({}) let existedInitially: Record = $state({}) let fetchedResources: Record = $state({}) let perWsUser: Record = $state({}) - onDestroy(() => { - for (const h of Object.values(states)) h.release() + const handlesArray = UserDraft.useMany(() => + workspaceSpecs.map((s) => ({ + itemKind: 'resource' as const, + path: initialPath ?? '', + workspace: s.ws, + defaultValue: s.defaultValue + })) + ) + const states = $derived.by(() => { + const out: Record> = {} + for (let i = 0; i < workspaceSpecs.length; i++) { + const handle = handlesArray[i] + if (handle) out[workspaceSpecs[i].ws] = handle + } + return out }) - /** Create (or reuse) a per-workspace handle. `defaultValue` is what the - * handle reports when no autosave is persisted; an existing autosave - * always wins. The default itself never round-trips to localStorage — only - * the user's first real edit triggers a write. */ - function ensureHandle(ws: string, defaultValue: ResourceState): UserDraftHandle { - if (states[ws]) return states[ws] - const h = UserDraft.use('resource', initialPath ?? '', { - workspace: ws, - defaultValue, - manualRelease: true - }) - states[ws] = h - return h + /** Register a workspace so `useMany` acquires (or reuses) its handle. + * `defaultValue` is what the handle reports when no autosave is persisted; + * an existing autosave always wins. The default itself never round-trips + * to localStorage — only the user's first real edit triggers a write. */ + function ensureHandle(ws: string, defaultValue: ResourceState): void { + if (workspaceSpecs.some((s) => s.ws === ws)) return + workspaceSpecs.push({ ws, defaultValue }) } let isValid = $state(true) diff --git a/frontend/src/lib/components/VariableEditor.svelte b/frontend/src/lib/components/VariableEditor.svelte index 5d3a9b3f06..3ab1d71fc9 100644 --- a/frontend/src/lib/components/VariableEditor.svelte +++ b/frontend/src/lib/components/VariableEditor.svelte @@ -1,6 +1,6 @@