mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 16:02:19 +00:00
25a891041d
* fix(frontend): wire DB-backed autosave into the whitelabel flow SDK FlowWrapper (the @windmill-labs/components flow editor entry) was never updated after DB-backed user drafts moved autosave wiring to the page layer, so the SDK editor had no autosave and never rendered the AutosaveIndicator. Back the bound store with a per-user UserDraft handle (workspace-guarded so it no-ops before a workspace exists) and pass liveEditorDraftStoragePath so the indicator and Ctrl/Cmd+S flush engage. Also set $workspaceStore on the /test_dev/sdk_flow harness page, which lives outside the (logged) layout and so had an empty workspace store (mirrors the sibling sdk_resource page). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(frontend): shared test_dev header to log in + set the SDK token Add a common TestDevHeader (rendered by a test_dev/+layout) that logs in (email/password → bearer token), lets a token be pasted/set manually, picks the workspace, loads the user, and persists the session across reloads — mirroring the React SDK's initializeClients. test_dev routes live outside the (logged) layout, so this is the single place that wires OpenAPI.TOKEN + workspaceStore + userStore for the SDK demo pages. Drop the now-redundant per-page workspace/user wiring from sdk_flow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(frontend): reuse usePageDraftSync in the flow SDK instead of a parallel copy FlowWrapper hand-rolled UserDraft.useMany + a manual seed effect, duplicating the core of usePageDraftSync but dropping recordRemoteSync/seedBaseline/discardIf — a divergence that would drift. The only reason it couldn't reuse the helper was that useReactive passes workspace straight into useMany, whose reconcile called resolveWorkspace() (which throws) before the detached-handle check. Make reconcile resolve the workspace without throwing and treat an absent workspace like an empty path — handing out a detached, local-only handle that re-keys into a real entry once the workspace resolves. FlowWrapper then reuses usePageDraftSync directly, keeping one code path for the page and SDK editors. Seed via the spec's defaultValue (threaded through usePageDraftSync -> useReactive -> useMany, captured once on first acquire and swallowed by the syncer's seed guard) rather than a manual first-write effect, dropping the fragile skipNextWrite assumption and the seededPath bookkeeping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): wire DB-backed autosave into the whitelabel script SDK ScriptWrapper had the same gap FlowWrapper did: ScriptBuilder delegates its draft handle to the page (it only stop/restart-syncs and flushes by userDraftPath), so the SDK's plain `bind:script` never reached a UserDraft handle — no autosave, no indicator. Back it with usePageDraftSync<script> (bind:script={draftSync.draft}, userDraftPath), seeded from the consumer's script via defaultValue. Same one-code-path reuse as the flow SDK. AppWrapper needs no change: AppEditor already self-acquires its handle (UserDraft.use('app', ...)), so apps autosave already — and now also tolerate mounting before login via the reconcile change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): gate SDK editors on a resolved workspace Before a workspace exists the draft handle is detached (local-only); editing into it and then having the workspace resolve re-keys to a fresh real entry seeded from the original value, silently dropping those edits. Gate the flow, script, and app SDK editors on `$workspaceStore` so no editing happens until the real draft key exists. Embedders set the workspace before rendering (React SDK initializeClients); the test_dev header sets it on mount. AppEditor additionally acquires its handle at init from a non-reactive workspace, so gating AppWrapper also ensures it mounts with the workspace already set rather than permanently detached. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(frontend): add sdk_app test_dev page for the app editor SDK Exercises AppWrapper the same way sdk_flow/sdk_script exercise their editors, under the shared TestDevHeader. Confirms the app editor's self-managed autosave + AutosaveIndicator work via the SDK wrapper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
41 lines
1.6 KiB
Svelte
41 lines
1.6 KiB
Svelte
<script lang="ts">
|
|
import { untrack } from 'svelte'
|
|
import ScriptBuilder from '$lib/components/ScriptBuilder.svelte'
|
|
import AiChatLayout from './copilot/chat/AiChatLayout.svelte'
|
|
import type { ScriptBuilderProps } from './script_builder'
|
|
import { usePageDraftSync } from './usePageDraftSync.svelte'
|
|
import { workspaceStore } from '$lib/stores'
|
|
|
|
let { script: oldScript, disableAi, ...props }: ScriptBuilderProps = $props()
|
|
|
|
// Stable per-user draft storage key. Mirrors the full-page editor keying on
|
|
// the URL path; falls back through the SDK's path inputs.
|
|
const draftStoragePath = untrack(() => props.initialPath || oldScript?.path || '')
|
|
|
|
// Reuse the full-page script editor's draft orchestration (same as the flow
|
|
// SDK) so the SDK gets autosave + the AutosaveIndicator (gated by ScriptBuilder
|
|
// on `userDraftPath`) from one code path. `defaultValue` seeds the handle from
|
|
// the consumer's script on first acquire (swallowed by the syncer's seed guard,
|
|
// never POSTs). `useReactive` tolerates mounting before login (detached
|
|
// local-only handle, no throw); the builder is gated on the workspace below so
|
|
// edits aren't made into that detached handle and lost when it re-keys.
|
|
const initialScript = untrack(() => oldScript)
|
|
const draftSync = usePageDraftSync<ScriptBuilderProps['script']>({
|
|
itemKind: 'script',
|
|
path: () => draftStoragePath,
|
|
workspace: () => $workspaceStore,
|
|
defaultValue: initialScript
|
|
})
|
|
</script>
|
|
|
|
<AiChatLayout noPadding {disableAi}>
|
|
{#if $workspaceStore && draftSync.draft}
|
|
<ScriptBuilder
|
|
bind:script={draftSync.draft}
|
|
userDraftPath={draftStoragePath}
|
|
{disableAi}
|
|
{...props}
|
|
/>
|
|
{/if}
|
|
</AiChatLayout>
|