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-111

2.5 Issue list view

Done
Description

The project's issue index — the surface the sidebar "Issues" link opens (today a stub). Per the shipped mockup design/work-items/tree.png this is a hierarchical tree-table: a Server-Component route at /issues that lists every non-archived issue in the active project nested by parent (epic → story → task → sub-task, with bugs in place), each row carrying its type icon · PROD-N identifier · title (tree-indented, expand/collapse), assignee, and a status pill. Above the table: an "Issues" header + the "all issues in {project}" subtitle, a Filter affordance (kind · status · assignee · text), a "Tree" view-switcher, and the "New issue" trigger (reuses 2.3.3's CreateIssueModal). Rows support inline status + assignee edits (the same gated controls the detail page uses), plus the drawn empty state and loading skeleton. This is the precursor surface Epic 6's search + saved filters extend.

Prerequisites: Tree-table design EXISTS; the two undrawn seams each get a design subtask (the design-reference rule / notes.html mistake #31). The tree-table mockup was drafted in the 2.3 design pass and lives under its area at design/work-items/tree.png (+ tree.pen, frames table / list-tree / table (skeleton)). But tree.png draws the [Filter] and [Tree ▾] controls only in their disabled, closed state — their expanded surfaces are undrawn, so each gets its own design subtask before its code can build: 2.5.7 designs the List view + switcher menu (gating 2.5.8), and 2.5.9 designs the open filter-bar popover (gating 2.5.4). Every UI subtask below carries its design reference in CONTEXT and MUST match its layout: the [Filter] · [Tree ▾] · [+ New issue] toolbar, the TITLE / ASSIGNEE / STATUS three-column tree-table with type icon + identifier + indented title, the centered empty state, and the skeleton. Reuse the named primitives (Card, Pill, Button, Combobox, Popover, EmptyState, Spinner, IssueTypeIcon) and the --el-* element tokens (never Tier-0 --color-* / text-foregroundmotir-core/CLAUDE.md); issue-type icons take their type hue via IssueTypeIcon, status goes through Pill tones (finding #35 AA-safe).

Read-mostly & reconciled with shipped reality (decision-authority rung 2 > rung 3). Story 1.4 already ships the reads this Story composes: workItemRepository.findByProjectFiltered (flat, non-archived, key asc — kind/status/assignee filters) + findSubtree (recursive CTE) + workItemsService.listWorkItems. The two write affordances (inline status / assignee) add NO new mutation primitives — they reuse 2.2.4's gated updateStatus (via 2.4.4's changeStatusAction) and 2.3.6's status-free updateWorkItem (via updateIssueAction), and the shared StatusPicker / AssigneePicker. The "New issue" button reuses 2.3.3's CreateIssueModal / CreateIssueProvider (no second create path). All routes follow the 4-layer architecture and carry an explicit workspaceId gate at the read layer (finding #26 — the shipped findByProjectFiltered filters only projectId; 2.5.1 ADDS the workspace filter, since RLS is inert under the dev/CI superuser until the Epic-8 cutover). Route reconciliation (finding #50): the list lives at app/(authed)/issues/page.tsx resolving the active project via getActiveProject(), NOT a card-illustrative /projects/[key]/issues.

Card-vs-design reconciliation (the design is the layout authority). The Epic-2 card calls this "a sortable table … with column controls." The shipped mockup draws a hierarchical tree-table with a fixed TITLE / ASSIGNEE / STATUS column set, a [Filter] button, and a [Tree ▾] view-switcher — no per-column sort arrows and no column show/hide menu. v1 ships the Tree view exactly as drawn; 2.5.3 renders the [Tree ▾] control disabled (only "Tree") as a forward-compatible seam. Making that switcher work — the flat, sortable "List" mode behind it — is now its own planned work: 2.5.7 designs the List view + switcher menu (the design gate: tree.png doesn't specify them), and 2.5.8 wires the control (Tree ↔ List + single-column sort, URL-driven). Saved / named views, multi-sort, and column show/hide config stay Epic 6 (saved views & advanced search) — not invented here (no complexity for nothing).

Verification

  • Pull the Story branch, pnpm install && pnpm prisma generate && pnpm prisma migrate dev against a fresh local DB (no new migration expected — this Story is read-first; the only writes reuse shipped mutation paths).
  • pnpm test — Vitest covers: getProjectTree nesting + ancestor-retained filter + cross-workspace isolation (2.5.1); TreeTable nesting/expand/keyboard (2.5.2); page data-shaping (2.5.3); filter callback + URL state (2.5.4); inline cell opens shared picker + calls shared action (2.5.5).
  • pnpm test:e2eissue-list-flow (2.5.6) + the shell-a11y sweep on /issues.
  • Manual UX check — render: open "Issues"; confirm the tree-table matches tree.png (type icons, identifiers, indented titles, expand chevrons on parents only, assignee, status pills, the Filter / Tree / New-issue toolbar).
  • Manual UX check — interact: expand/collapse rows; filter by kind/status/assignee/text (ancestors stay for context; URL updates + reloads safely); change a row's status inline (only legal targets; illegal rejected); reassign + unassign inline; click a row → its detail page; a row's quick-view button opens the item in a modal (a "peek") with an "Open full page" link to its detail page; "New issue" opens the create modal.
  • Empty + loading: a fresh project shows "No issues yet"; the table shows the skeleton while loading.
  • Cross-workspace check: as a workspace-A-only user, the workspace-B project's issues never appear at /issues.
  • Scale check (finding #57) — pnpm db:seed:large (2.5.16): seed the large project, open it at /issues. List: the footer shows "1–50 of N" and Next/Prev/page-jump move through pages (the page doesn't render all N rows). Tree: a collapsed parent shows a chevron but its children aren't loaded; expanding lazy-loads them (a brief loading row); a parent with >50 children shows "Load more children"; scrolling a deeply-expanded tree stays smooth (virtualized — the DOM row count stays bounded). Confirms the issue index survives a real backlog, not just a demo.
Child work items