refactor(desktop): migrate plans collection onto the design system

Merged
CH
8d ago
+39-29

D37 of the design-system migration (Desktop stack, base feature/desktop-d36-home, #3414).

Which surface

No surface is called "plans collection" any more. Since the plans → tasks/issues renames, the plan's row maps to the Issues page's list (issues-page.tsx and issue-list.tsx). The orchestrator agreed. The Issues board (issue-board.tsx) is left for D40 "Plan board". The sidebar's Tasks section (its hover cards, selection and "No tasks yet" notes) stays under D04's coverage.

What

  • New issue in the toolbar is now the barrel's outline Button with its + glyph. It replaces the raw toolbar-button bordered-button and keeps its aria-keyshortcuts, its press, and being unavailable while no workspace is listed or the card is already open.
  • View options is now the barrel's IconButton, the same way D04 did the sidebar's. Its tooltip, name, and menu (menu.trigger()) are unchanged.
  • Status group headings in the list are now Text: the status in the section role (muted) and the count in subtle caption Text. Both sit inside an Issues-owned h2.issue-group-head on the rows' inset, so heading navigation still announces the count. They no longer use Home's .home-section-title/.home-section-count.
  • No list empty state ("No issues yet") and read failure (Retry) were already the barrel's EmptyState/ErrorState. They're unchanged.
  • No caller here imported @luke/ui/compat. No selector became unused: .toolbar-button, .bordered-button, .icon-button-glyph, .home-section-title/-count, .home-column, and .issues-column all still have other callers (Home, the person page, other toolbars).

No behaviour changed. These all work as before: ↑/↓/Return through the rows, Escape back to the list with the row holding the keyboard, right-click / menu key / ⇧F10 for Issue actions, C and New issue, the Board/List choice kept in storage, and archive confirmation.

Why not CollectionPage / ListRow

The orchestrator asked for this reasoning to be written down for a shared fix.

  • CollectionPage draws its own 22/30 in-page title header over one scroll column at a 720px measure. The Issues page doesn't have that layout. It sits under the window's desktop toolbar (15px title, Experimental tag, Send feedback, hairline, native drag region), the same frame as Inbox, Factory, Automations, the issue's own detail page, and the Board layout. The Board scrolls sideways in its own scroller and can't live in a 720px column. If only the List layout moved to CollectionPage, the header would jump when switching Board/List, and the List would lose the toolbar's drag region. That's a redesign, not a migration. Toolbar-framed desktop pages need a CollectionPage that can sit under a window toolbar, i.e. without its own title header.

  • ListRow accepts no ref, onContextMenu, onKeyDown, or data attribute on its row button, and the list needs all four:

    • a ref, to focus the row the page came back from on Escape;
    • a context-menu handler and a key handler, so right-click, the menu key and ⇧F10 open Issue actions (useMenu's contextMenu()/keyMenu);
    • data-issue-id, so the page can tell whether the keyboard stayed on the issue a change moved;
    • and useRowKeys finds rows by the sidebar row class.

    The list's rows are also deliberately Home's rows, which D36 kept. ListRow's two-line 8/12-padded row would visibly change them.

Visible changes

  • New issue: label type 13/18 weight 500 instead of 12.5px weight 600 (the contract's label). The outline edge and 30px height are unchanged.
  • Group headings: 13/18 semibold in muted ink (the section role) instead of 12px semibold. The count is 12/16 caption in subtle ink instead of 11.5px medium. Each group is about 4px taller.
  • View options: none intended.

Tests

  • No behaviour changed, so no tests were added.
  • issues-page.test.ts's groups() helper reads each group's h2 instead of .home-section-title. The expected words and counts are unchanged, so the grouping test also fails if the count leaves the heading (Devin's review).
  • Deleted "the list stands in the window's own frame…". It only asserted class names and the DOM nesting (.home-section > h2.home-section-title > .home-section-count, etc.), which the testing rules forbid. What a user sees there is covered by "the listed workspace's issues stand under a heading for each status…" and the ↑/↓/Return and Escape tests.
  • issues-page.test.ts: 45 tests pass. pnpm check:affected exits 0.

Evidence

Captured on Linux with headless Chrome at 1280×840, the same way #3414 was. A throwaway, uncommitted jsdom test rendered the real IssuesPage (the existing test's harness, synthetic issues). That markup was framed in main.desktop-main with the built desktop stylesheet from each commit. "Before" is the base, #3414.

LightDark
List, before
List, after
Empty, before
Empty, after
Board toolbar, before
Board toolbar, after

Not captured: the read-failure state, which this PR didn't touch (the barrel's ErrorState already).

Not verified on a Mac

  • New issue and View options staying no-drag in the toolbar's drag region (.luke-button is in the no-drag list).
  • SF Pro rendering of the button and headings; the window's scroll.

🤖 Generated with Claude Code