MOTIR-980Done
2.9.3 Archived work items view UI + per-item Restore (unarchive)
Estimate: 55m · Type: code · Depends on: 2.9.1, 2.9.2
Build the archived work items view + per-item Restore, at the placement 2.9.1 decides, reading 2.9.2.
- Render the flat, paginated archived list per the 2.9.1 design (rows: key, type glyph, title, status, archived-by/at; reuse
IssueListPager, the issues-row vocabulary, and the empty/loading states). - Restore per row → call the EXISTING client helper
unarchiveWorkItemincomponents/issues/actions/workItemActionsClient.ts(→DELETE /api/work-items/[id]/archive→workItemsService.unarchiveWorkItem). Do not add a new write path — the service/route/MCP already exist. - Page state after restore (CLAUDE.md § page-state): the restored row leaves the archived list (optimistic remove or refetch the page, seq-guarded) AND active views must reflect it — if the archived view is a client island, bump the existing
CreateIssueProvider.issuesChangedAt-style tick the board/issues watch; otherwiserouter.refresh()the server surfaces. Wait on the unarchive 200 before asserting persisted state. - Gating: Restore visible only to editors (
useProjectAccess().canEdit, matching the shippedassertCanEdit); view per the 2.9.1 decision. - Copy in the existing namespace (en + zh).
Acceptance criteria
- The archived view lists archived items (paginated) at the 2.9.1 placement; clicking Restore removes the row and returns the item to active views; activity shows "restored".
- Restore is hidden/disabled for non-editors; the view obeys the 2.9.1 access decision.
- No new write endpoint — reuses
unarchiveWorkItem. Component test covers render + restore (page-state) + gating; per-file coverage gate holds.
Context refs
- 2.9.1 design (
design/work-items/archived asset) · 2.9.2 read path (listArchivedWorkItems) components/issues/actions/workItemActionsClient.ts(unarchiveWorkItem);app/api/work-items/[id]/archive/route.ts(DELETE = unarchive)app/(authed)/issues/_components/IssueListPager.tsx,WorkItemRowActions.tsx(row vocabulary +notifyIssuesChangedtick pattern)motir-core/CLAUDE.md§ "Page state after a mutation" + § "E2E waits on the authoritative signal"