mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 16:03:47 +00:00
refactor(drafts): UserDraft.useReactive — kill array-of-one boilerplate
The script + flow routes both wanted a handle that re-keys when the URL
path changes. UserDraft.use() can't do that (its opts getter is
untracked), so each route hand-rolled the same useMany-array-of-one +
proxy idiom:
const handles = useMany(() => [{ kind, path: reactive }])
const handle = { get draft() { return handles[0]?.draft }, ... }
Add UserDraft.useReactive(getSpec) that internally wraps useMany with a
single spec and returns the stable proxy. Callers collapse to one line.
This commit is contained in:
@@ -355,14 +355,40 @@ export const UserDraft = {
|
||||
// the getter so reactive opts (e.g. `$workspaceStore`) are
|
||||
// captured once at call time — the current contract is "the
|
||||
// handle stays bound to this workspace until the component
|
||||
// unmounts." Use `useMany` directly if you want spec changes to
|
||||
// release/acquire entries as you go.
|
||||
// unmounts." For reactive `(kind, path)` use `useReactive`.
|
||||
const handles = UserDraft.useMany<V>(() =>
|
||||
untrack(() => [{ itemKind, path, workspace: opts?.workspace }])
|
||||
)
|
||||
return handles[0]
|
||||
},
|
||||
|
||||
/**
|
||||
* Reactive single-spec variant of `use()`. `getSpec` is read inside the
|
||||
* `useMany` reconcile, so when the spec's `(workspace, kind, path)`
|
||||
* changes, the previous entry is released and a new one acquired. The
|
||||
* returned object is a stable handle proxy — its `draft` getter/setter
|
||||
* forwards to whichever underlying handle is current, so `bind:` lvalues
|
||||
* survive re-keying.
|
||||
*
|
||||
* Use this when the editor's path is reactive (`/scripts/edit/[...path]`
|
||||
* navigation between paths must re-key the autosave cell). For a
|
||||
* non-reactive path, `use()` is simpler.
|
||||
*/
|
||||
useReactive<V = unknown>(
|
||||
getSpec: () => { itemKind: UserDraftItemKind; path: string; workspace?: string }
|
||||
): UserDraftHandle<V> {
|
||||
const handles = UserDraft.useMany<V>(() => [getSpec()])
|
||||
return {
|
||||
get draft(): V | undefined {
|
||||
return handles[0]?.draft
|
||||
},
|
||||
set draft(value: V | undefined) {
|
||||
const h = handles[0]
|
||||
if (h) h.draft = value
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
useMany<V = unknown>(
|
||||
getSpecs: () => {
|
||||
itemKind: UserDraftItemKind
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
import { tick, untrack } from 'svelte'
|
||||
import type { stepState } from '$lib/components/stepHistoryLoader.svelte'
|
||||
import { page } from '$app/state'
|
||||
import { UserDraft, type UserDraftHandle } from '$lib/userDraft.svelte'
|
||||
import { UserDraft } from '$lib/userDraft.svelte'
|
||||
import { notifyDraftLoaded } from '$lib/userDraftToast'
|
||||
|
||||
let version: undefined | number = $state(undefined)
|
||||
@@ -56,18 +56,12 @@
|
||||
* deploy lands at this path. */
|
||||
let isNewFlow = $state(false)
|
||||
|
||||
// `useMany` keyed off the reactive `flowDraftPath` re-keys the handle on nav;
|
||||
// `flowHandle` proxies the current handle so `flowStore` keeps a fixed ref.
|
||||
const flowHandles = UserDraft.useMany<Flow>(() => [{ itemKind: 'flow', path: flowDraftPath }])
|
||||
const flowHandle: UserDraftHandle<Flow> = {
|
||||
get draft() {
|
||||
return flowHandles[0]?.draft
|
||||
},
|
||||
set draft(value) {
|
||||
const handle = flowHandles[0]
|
||||
if (handle) handle.draft = value
|
||||
}
|
||||
}
|
||||
// Re-keys the handle on nav (the reactive `flowDraftPath` is read inside
|
||||
// the reconcile) while keeping `flowStore` a stable ref.
|
||||
const flowHandle = UserDraft.useReactive<Flow>(() => ({
|
||||
itemKind: 'flow',
|
||||
path: flowDraftPath
|
||||
}))
|
||||
|
||||
function emptyFlow(): Flow {
|
||||
return {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import { get } from 'svelte/store'
|
||||
import { untrack } from 'svelte'
|
||||
import { page } from '$app/state'
|
||||
import { UserDraft, type UserDraftHandle } from '$lib/userDraft.svelte'
|
||||
import { UserDraft } from '$lib/userDraft.svelte'
|
||||
import { notifyDraftLoaded } from '$lib/userDraftToast'
|
||||
import { UserDraftDbSyncer } from '$lib/userDraftDbSyncer.svelte'
|
||||
|
||||
@@ -35,20 +35,12 @@
|
||||
// local draft — that view is read-only relative to drafts.
|
||||
let draftPath = $derived(hash ? '' : (page.params.path ?? ''))
|
||||
|
||||
// `useMany` keyed off the reactive `draftPath` re-keys the handle on nav;
|
||||
// `scriptHandle` proxies the current handle so `bind:script` stays a fixed lvalue.
|
||||
const scriptHandles = UserDraft.useMany<EditableScript>(() => [
|
||||
{ itemKind: 'script', path: draftPath }
|
||||
])
|
||||
const scriptHandle: UserDraftHandle<EditableScript> = {
|
||||
get draft() {
|
||||
return scriptHandles[0]?.draft
|
||||
},
|
||||
set draft(value) {
|
||||
const handle = scriptHandles[0]
|
||||
if (handle) handle.draft = value
|
||||
}
|
||||
}
|
||||
// Re-keys the handle on nav (the reactive `draftPath` is read inside
|
||||
// the reconcile) while keeping `bind:script` a stable lvalue.
|
||||
const scriptHandle = UserDraft.useReactive<EditableScript>(() => ({
|
||||
itemKind: 'script',
|
||||
path: draftPath
|
||||
}))
|
||||
|
||||
$effect(() => {
|
||||
if (hash || !$workspaceStore) return
|
||||
|
||||
Reference in New Issue
Block a user