mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-13 08:02:47 +00:00
fix(sessions): send a write's settled draft before the list frame re-reads it
The settle that follows a write parks its draft delete on the autosave debounce, so the list frame reloaded straight after read the row's `*` and kept it: its markers come from a store inside the iframe, and nothing reloads it a second time when the delete lands. The fan-out sends what is parked for the key first. That needed the variable save to report after settling rather than before — reporting first meant there was nothing parked yet to send, and the flush passed over a cell about to queue a delete. Every editor now resolves its cell before saying so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KcyBRxE8j3ujCYkum9KrC4
This commit is contained in:
co-authored by
Claude Opus 5
parent
d27eec52ab
commit
08386433aa
@@ -339,11 +339,6 @@
|
||||
existedInitially[ws] = true
|
||||
}
|
||||
if (ws === fromWs) actingCommitted = true
|
||||
// Per workspace, as each write lands. Each carries its own workspace and
|
||||
// the path it wrote there, so a linked workspace's rename moves the tabs
|
||||
// acting on it and no others — and a workspace written before a later one
|
||||
// threw is still reported, because it is deployed.
|
||||
onSaved?.(s.path, from, ws)
|
||||
// The just-saved state is the new deployed baseline; this resets the handle
|
||||
// to it via `discard` (not `remove` — blanking the cell to `undefined` reads
|
||||
// as dirty) and keeps an edit made mid-request. Each workspace settles
|
||||
@@ -351,6 +346,12 @@
|
||||
settleDraftAfterWrite('variable', s, states[ws]?.draft, from ?? '', s.path, {
|
||||
workspace: ws
|
||||
})
|
||||
// Reported after settling, so what hears about the write sees a cell that
|
||||
// has already been resolved. Per workspace, each carrying its own and the
|
||||
// path it wrote there, so a linked workspace's rename moves the tabs acting
|
||||
// on it and no others — and a workspace written before a later one threw is
|
||||
// still reported, because it is deployed.
|
||||
onSaved?.(s.path, from, ws)
|
||||
// Path now exists server-side — drop the autocomplete cache so
|
||||
// it shows up immediately instead of after the 60s TTL.
|
||||
invalidateWorkspacePaths(ws)
|
||||
|
||||
@@ -290,6 +290,20 @@ export function settleDraftAfterWrite<V>(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send whatever this cell has parked on the autosave debounce, now. For a reader
|
||||
* that cannot be corrected once it has read — a list page inside an iframe, whose
|
||||
* draft markers come from its own store — and would otherwise render a row the
|
||||
* debounce has not caught up with.
|
||||
*/
|
||||
export async function flushDraftWrites(
|
||||
itemKind: UserDraftItemKind,
|
||||
path: string,
|
||||
opts?: UserDraftOptions
|
||||
): Promise<void> {
|
||||
await UserDraftDbSyncer.flush({ workspace: resolveWorkspace(opts), itemKind, path })
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a queued draft delete to land, reporting whether the draft is gone. A
|
||||
* caller acts on this — a host leaves an editor whose item the discard removed —
|
||||
@@ -304,7 +318,7 @@ export async function flushDraftDelete(
|
||||
opts?: UserDraftOptions
|
||||
): Promise<boolean> {
|
||||
const query = { workspace: resolveWorkspace(opts), itemKind, path }
|
||||
await UserDraftDbSyncer.flush(query)
|
||||
await flushDraftWrites(itemKind, path, opts)
|
||||
return (
|
||||
UserDraftDbSyncer.lastLandedWasDelete(query) &&
|
||||
UserDraftDbSyncer.getState(query).state === 'none'
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
type WorkspaceItemKind
|
||||
} from '$lib/components/workspacePicker'
|
||||
import { splitterPointerCapture } from '$lib/utils/splitterPointerCapture'
|
||||
import { UserDraft } from '$lib/userDraft.svelte'
|
||||
import { UserDraft, flushDraftWrites } from '$lib/userDraft.svelte'
|
||||
|
||||
const globalEnabled = isGlobalAiEnabled()
|
||||
|
||||
@@ -614,7 +614,7 @@
|
||||
// A hosted entity editor wrote its item. Every tab on it hears, across warm
|
||||
// sessions: they share the one draft cell and the one server row, so one left
|
||||
// behind edits a path that is gone or discards over a value already deployed.
|
||||
function entityWritten(ev: {
|
||||
async function entityWritten(ev: {
|
||||
kind: EntityEditorKind
|
||||
path: string
|
||||
workspace: string
|
||||
@@ -625,6 +625,11 @@
|
||||
}) {
|
||||
const page = entityListPage(ev.kind)?.path
|
||||
if (!page) return
|
||||
// The settle that follows a write parks its draft delete on the autosave
|
||||
// debounce, and a list frame reads its `*` markers from a store of its own
|
||||
// — read before that lands, it keeps the row's marker until something else
|
||||
// reloads it, and nothing does.
|
||||
await flushDraftWrites(ev.kind, ev.path, { workspace: ev.workspace })
|
||||
for (const s of warmSessions) {
|
||||
const owner = getRuntime(s.id)?.previewTabs
|
||||
if (!owner || getEffectiveWorkspaceId(s) !== ev.workspace) continue
|
||||
|
||||
Reference in New Issue
Block a user