mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-23 19:06:33 +00:00
feat(web): show archived banner in-place on live archive (TASK-1833) (#736)
Follow-up to TASK-1829 (Codex review of #735). When the open item was archived live — via the SSE item_archived handler or the sync-resume deleted path — the detail route redirected back to the collection, so the new in-place Archived banner only appeared on a fresh direct load. Now both handlers re-fetch the item (GET returns soft-deleted items with deleted_at, #733) and render the banner in place. - SSE item_archived: re-fetch and show the banner instead of goto(). - Sync-resume deleted: re-fetch — an archived item (still resolvable, 200) shows the banner; a hard-deleted one (404) still redirects. - Both keep the prior redirect when mid-edit (saveStatus==='saving' || editingTitle): an in-flight save against an archived row would fail and a re-fetch would clobber the editor (the original Codex-round-2 reasoning). - Race guards mirror the handlers' existing pattern (capture item id before await, bail if navigated away). The actor's own archive still navigates via handleDelete's goto; this only changes the someone-else-archived-it case. svelte-check + web build green.
This commit is contained in:
@@ -338,7 +338,33 @@
|
||||
// them on a non-existent item is worse than discarding the
|
||||
// edit. Per Codex review round 2.
|
||||
if (event.type === 'item_archived') {
|
||||
goto(`/${username}/${wsSlug}/${collSlug}`);
|
||||
// The open item was archived (another tab / user). GET still
|
||||
// returns soft-deleted items (deleted_at set, #733), so re-fetch
|
||||
// and show the in-place Archived banner instead of yanking the
|
||||
// user back to the collection (TASK-1833). Two cases keep the
|
||||
// prior redirect: mid-edit (an in-flight save will fail against
|
||||
// the archived row and re-fetching would clobber the editor —
|
||||
// the Codex-round-2 reasoning still holds there), and a re-fetch
|
||||
// 404 (item hard-deleted — gone for real).
|
||||
// editorStore.dirty catches unsaved content BEFORE the 1.2s
|
||||
// debounced save flips saveStatus to 'saving' — without it a
|
||||
// live archive in that window would re-fetch and clobber the
|
||||
// user's in-progress edit (Codex P1).
|
||||
if (saveStatus === 'saving' || editingTitle || editorStore.dirty) {
|
||||
goto(`/${username}/${wsSlug}/${collSlug}`);
|
||||
return;
|
||||
}
|
||||
const archItemId = item.id;
|
||||
const archWsSlug = wsSlug;
|
||||
const archItemSlug = itemSlug;
|
||||
try {
|
||||
const archived = await api.items.get(archWsSlug, archItemSlug);
|
||||
if (!item || item.id !== archItemId) return;
|
||||
item = withInflightTags(archived);
|
||||
} catch {
|
||||
if (!item || item.id !== archItemId) return;
|
||||
goto(`/${username}/${wsSlug}/${collSlug}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -410,7 +436,31 @@
|
||||
// Check this BEFORE the edit-conflict guard so a deleted item
|
||||
// doesn't sit there gated by an in-flight save.
|
||||
if (result.type === 'incremental' && result.changes.deleted.includes(item.id)) {
|
||||
goto(`/${username}/${wsSlug}/${collSlug}`);
|
||||
// Archived or hard-deleted while we were away. GET returns
|
||||
// soft-deleted items (deleted_at set) but 404s on a hard delete,
|
||||
// so re-fetch: an archived item shows the in-place banner, a
|
||||
// hard-deleted one redirects (TASK-1833). Keep the prior redirect
|
||||
// when mid-edit (don't clobber an in-flight save against a
|
||||
// now-archived row).
|
||||
// editorStore.dirty catches unsaved content BEFORE the 1.2s
|
||||
// debounced save flips saveStatus to 'saving' — without it a
|
||||
// live archive in that window would re-fetch and clobber the
|
||||
// user's in-progress edit (Codex P1).
|
||||
if (saveStatus === 'saving' || editingTitle || editorStore.dirty) {
|
||||
goto(`/${username}/${wsSlug}/${collSlug}`);
|
||||
return;
|
||||
}
|
||||
const delItemId = item.id;
|
||||
const delWsSlug = wsSlug;
|
||||
const delItemSlug = itemSlug;
|
||||
try {
|
||||
const refreshed = await api.items.get(delWsSlug, delItemSlug);
|
||||
if (!item || item.id !== delItemId) return;
|
||||
item = withInflightTags(refreshed);
|
||||
} catch {
|
||||
if (!item || item.id !== delItemId) return;
|
||||
goto(`/${username}/${wsSlug}/${collSlug}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user