refactor(desktop): migrate workspace linear connections onto the design system

Merged
CH
5d ago
+91-58

D21 of the design-system migration (Desktop stack, base feature/desktop-d20-workspace-github-connections, #3399).

What

  • Linear's row in Settings › Workspace › Integrations is @luke/ui's SettingsRow:
    • owner/admin: through MenuRow's row form (as Members does), led by Linear's ProviderMark in the .settings-row-mark box; label "Linear", description the line for where the connection stands
    • control: Connect (none stands) or Connect again (Linear stopped honoring it) as the outline Button, replacing toolbar-button bordered-button; none while a connection is active
    • Disconnect stays behind the ⋯ (and right-click) once a connection stands, asking first through ConfirmDialog
    • member: a read-only SettingsRow with the same mark and line
  • A sign-in that could not be begun is still said under the row as .error-message role="alert", inside a .workspace-linear column, as GitHub's, API keys', Members' and Invitations' are.
  • With both its rows moved, the Integrations group is SettingsSection (title "Integrations"), its GITHUB_REPOSITORIES search anchor on a wrapper div, as Members and Invitations do. SettingsGroup stays for Leave and the read-failure card, which are D22's and later.
  • Behaviour is unchanged: Connect sends one WORKSPACE_LINEAR_CONNECT at once, asking nothing, and a second press while it starts sends nothing; Disconnect sends WORKSPACE_LINEAR_DISCONNECT after the confirm.

Selectors

  • .workspace-linear joins the .api-key, .workspace-identity, .workspace-member, .workspace-invite-row, .workspace-github column rule and its > .error-message rule.
  • Nothing Linear-specific existed to remove. LinearCopy became linearLine, the description alone.

Visible changes

  • Connect / Connect again use the shared outline Button face (weight 500), as GitHub's Connect does since D20.
  • While the browser is being sent, Connect shows the shared button's busy ring, and is named "Connecting" for that moment. Before, it was disabled with aria-busy and no ring. It still refuses a second press.
  • Linear's label and description use the label role (13/18, 500) and caption role (12/16), matching GitHub's row above it.
  • The Integrations heading and card are now the shared section's (same as Members and Invitations above it).
  • Below a 380px row, Connect drops below the words, per the shared row contract.

Tests

  • New in workspace-page.test.ts: while a Linear sign-in is held on the wire, an admin's Connect is named "Connecting" and is aria-busy. Once it lands, Connect returns to its own name, with no alert. Verified to fail with the busy props removed. This is the only user-visible behaviour change. The harness gained linearConnectHeld to hold the act; unheld, it still answers as before.
  • Otherwise no test changed. workspace-page.test.ts's helpers already read both shared and window rows since D20, and its Linear tests (connect once, connect-twice guard, ⋯ Disconnect with confirm, Escape returning focus to the ⋯, member read-only, unconnected wording) pass unchanged. settings-link.test.ts still lands on the Integrations h2.
  • pnpm check:affected exits 0.

Evidence

Captured on Linux with headless Chrome at 1280×840. The real WorkspacePage was rendered in jsdom by a throwaway, uncommitted copy of the page's test, using synthetic workspaces. Its Integrations section was placed in the built desktop stylesheet inside the SettingsPage frame. Each shot stacks three cases: Linear connected (with GitHub's connected and suspended accounts), Linear expired, and nothing connected. In the owner shot, the third case is after Connect was refused; its red line is the test harness's synthetic refusal.

LightDark
Owner/admin: connected (⋯ only); expired (Connect again + ⋯); unconnected after a refused Connect
Member: connected; expired; unconnected (read only)

Not verified on a Mac

  • SF Pro rendering of the row and the button
  • Connect opening Linear's sign-in in the browser against a live workspace, which was covered only by the tests
  • The search-result ring landing on the Integrations group in the real window

🤖 Generated with Claude Code