MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-994

2.9.5 Archived-list row ⋯ Delete… affordance + optimistic removal

Done
Description

Estimate: 40m · Type: code

Add permanent Delete to the archived work items list (app/(authed)/issues/archived/_components/ArchivedWorkItemsList.tsx, 2.9.3) per delete-confirm.mock.html + design-notes.md §2.9.7. Restore stays the prominent inline [Restore] button (canEdit); Delete goes in a per-row overflow menu as a single danger Delete… row, gated canManage — the row is purely the Delete affordance (NOT the full edit/copy/archive menu), so it maps 1:1 to the capability.

Re-scoped (2026-06-16 re-plan). This card originally claimed "reuse the modal as-is, no new endpoint, no new design". Its design gate 2.9.7 (MOTIR-997) actually requires a getDeletePreview live/archived split + a dialog variant + the placement + new copy — so the work was split: 2.9.9 / MOTIR-999 (preview backend) and 2.9.10 (dialog variant) now precede this, which is just the LIST affordance. Detail is 2.9.11.

  • Gate matrix (total over the 4 combos; each affordance HIDDEN — never shown-disabled — when its gate is unmet): canEdit→[Restore], canManage→⋯(Delete…); both→both; neither→actions column dropped (the existing view-only state). Read canManage from useProjectAccess() (provider mounted in the authed layout — verified; WorkItemRowActions reads it the same way) — no new server prop. The island today only takes canEdit.
  • Grid: widen the actions column 120→150px to seat [Restore] + (the canEdit template only; view-only template unchanged).
  • Confirm: open the archived variant of DeleteWorkItemDialog (2.9.10), already wired to fetchDeletePreview + deleteWorkItem (subtree cascade, canManage). No new endpoint/modal here.
  • Page state after delete (CLAUDE.md § page-state — the list is a CLIENT ISLAND): on the delete 200, remove the row LOCALLY (optimistic, seq-guarded, like the existing restore-removal set) + decrement the pager total; do NOT router.refresh(). The deleted subtree disappears from the active /issues + board on their next read.

Design: delete-confirm.mock.html (row ⋯ → Delete… vocab + gate matrix) + archived.mock.html (the list this extends). Reuse the RowActionsMenu/Popover vocab; no new primitive.

Acceptance criteria

  • An archived row shows Delete… in a menu to managers (canManage); non-managers don't see the ; Restore stays inline (canEdit); neither → column dropped.
  • Delete… opens the 2.9.10 archived confirm (cascade count + live-descendant warning); confirming deletes the subtree and removes the row from the archived view (optimistic, seq-guarded, pager decremented) after the delete 200.
  • Reuses DeleteWorkItemDialog (archived variant) + fetchDeletePreview + deleteWorkItem — no new endpoint. Component test covers render + canManage gating + delete-from-archived removal; coverage gate holds.

Context refs

  • app/(authed)/issues/archived/_components/ArchivedWorkItemsList.tsx, archived/page.tsx, _components/archivedRows.ts
  • app/(authed)/_components/ProjectAccessProvider.tsx (useProjectAccesscanManage); app/(authed)/issues/_components/WorkItemRowActions.tsx (the active-list pattern)
  • components/issues/actions/DeleteWorkItemDialog.tsx (2.9.10 archived variant), WorkItemActionsMenu.tsx (the ⋯/Popover vocab)
  • motir-core/CLAUDE.md § "Page state after a mutation" + § "E2E authoritative signal"
  • design: delete-confirm.mock.html, archived.mock.html, design-notes.md §2.9.7