diff --git a/frontend/src/lib/itemStore.svelte.ts b/frontend/src/lib/itemStore.svelte.ts index e7ee5a5320..0c2b913936 100644 --- a/frontend/src/lib/itemStore.svelte.ts +++ b/frontend/src/lib/itemStore.svelte.ts @@ -803,7 +803,11 @@ export function createItemStore(ports: ItemRowPort) { const arrived = arrivals.get(to) if (arrived !== undefined) { arrivals.delete(to) + // Parked before anything this entry has been asked since, so applying it now does not + // make it the latest ask: a discard asked meanwhile still outranks it. + const asked = entry.lastOutsideAsk entry.applyExternal(arrived) + entry.lastOutsideAsk = asked } }, /** diff --git a/frontend/src/lib/itemStore.test.ts b/frontend/src/lib/itemStore.test.ts index a6864485d5..aa572d8e15 100644 --- a/frontend/src/lib/itemStore.test.ts +++ b/frontend/src/lib/itemStore.test.ts @@ -620,7 +620,11 @@ describe('item store: one entry per key', () => { const b = { ...deployedRes, path: 'u/me/b' } const moveOnto = async ( openBefore: boolean, - outside: (store: ReturnType, open: () => void) => void, + outside: ( + store: ReturnType, + open: () => void, + moving: ItemHandle + ) => void, refuse?: string ) => { const rows = fakeRows() @@ -648,7 +652,7 @@ describe('item store: one entry per key', () => { ).handle } if (openBefore) open() - outside(store, open) + outside(store, open, moving) gate.resolve() expect(await moved).toMatchObject(refuse ? { ok: false } : { ok: true, moved: true }) await settle() @@ -687,6 +691,16 @@ describe('item store: one entry per key', () => { expect(failed.shown.value).toEqual(again) expect(failed.rows.writes.at(-1)).toEqual({ path: 'u/me/b', value: again }) + // A draft parked for the move, then Discard clicked on the editor doing the moving: the + // discard came last, so the parked draft does not come back with the item. + const discardedAfterParking = await moveOnto(false, (store, open, moving) => { + store.bridge.seed('w', 'resource', 'u/me/b', { ...b, description: 'parked draft' }) + open() + void moving.discard() + }) + expect(discardedAfterParking.moving.dirty).toBe(false) + expect(discardedAfterParking.rows.writes.at(-1)).toEqual({ path: 'u/me/b', value: null }) + // Deleted last: the delete is what holds, however many drafts preceded it. const deleted = await moveOnto(true, (store) => { store.bridge.seed('w', 'resource', 'u/me/b', { ...b, description: 'first draft' })