mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
fix: keep an outside draft written to an editor still loading behind a move
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015vn1jCHUcAdaG9C4NsUehF
This commit is contained in:
co-authored by
Claude Opus 5
parent
aca3aef0ec
commit
984e958a72
@@ -421,8 +421,14 @@ class Entry<V> {
|
||||
* changed from its own deployed side, so they stay a draft over what this entry deployed.
|
||||
* Compared exactly, as a save is: a field the draft comparison ignores (run-as) is an edit. */
|
||||
carryEditsOf(old: Entry<V>): void {
|
||||
if (old.origin !== 'deployed' || old.value === undefined || old.deployed === undefined) return
|
||||
if (this.value === undefined) return
|
||||
if (old.value === undefined || this.value === undefined) return
|
||||
// Not loaded yet (its read waits behind the move): only an outside write can have filled it,
|
||||
// and nothing has persisted that write but this entry.
|
||||
if (!old.loaded) {
|
||||
this.applyExternal(old.value)
|
||||
return
|
||||
}
|
||||
if (old.origin !== 'deployed' || old.deployed === undefined) return
|
||||
const edited = old.value as Record<string, unknown>
|
||||
const base = old.deployed as Record<string, unknown>
|
||||
const next = snapshot(this.value) as Record<string, unknown>
|
||||
|
||||
@@ -556,6 +556,36 @@ describe('item store: one entry per key', () => {
|
||||
expect(rows.writes.at(-1)).toEqual({ path: 'u/me/b', value: chat })
|
||||
})
|
||||
|
||||
it('keeps a draft written from outside to an editor that opened during the move', async () => {
|
||||
const rows = fakeRows()
|
||||
const store = createItemStore(rows.port)
|
||||
const gate = deferred()
|
||||
const b = { ...deployedRes, path: 'u/me/b' }
|
||||
const temporary = newItemPath()
|
||||
const { handle: moving } = store.acquire(
|
||||
{ workspace: 'w', kind: 'resource', path: temporary },
|
||||
{ workspace: 'w', path: temporary, template: b },
|
||||
adapter({}, () => gate.promise)
|
||||
)
|
||||
await settle()
|
||||
moving.value = { ...b, args: { a: 2 } }
|
||||
const moved = moving.save()
|
||||
await settle()
|
||||
const { handle: opened } = store.acquire(
|
||||
{ workspace: 'w', kind: 'resource', path: 'u/me/b' },
|
||||
{ workspace: 'w', path: 'u/me/b' },
|
||||
adapter({ deployed: b })
|
||||
)
|
||||
const chat = { ...b, description: 'written by the chat meanwhile' }
|
||||
// The opened editor holds the key, so the store persists it.
|
||||
expect(store.bridge.seed('w', 'resource', 'u/me/b', chat)).toBe(true)
|
||||
|
||||
gate.resolve()
|
||||
expect(await moved).toMatchObject({ ok: true, moved: true })
|
||||
expect(opened.value).toEqual(chat)
|
||||
expect(rows.writes.at(-1)).toEqual({ path: 'u/me/b', value: chat })
|
||||
})
|
||||
|
||||
it('keeps a change the draft comparison ignores in an editor a move replaces', async () => {
|
||||
type Sched = { path: string; summary: string; permissioned_as?: string }
|
||||
const rows = fakeRows()
|
||||
|
||||
Reference in New Issue
Block a user