refactor(desktop): migrate workspace linear connections onto the design system
Merged
CH
5d ago+91+91+01234567890123456789-58-58-01234567890123456789
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'sSettingsRow:- owner/admin: through
MenuRow'srowform (as Members does), led by Linear'sProviderMarkin the.settings-row-markbox; 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, replacingtoolbar-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
SettingsRowwith the same mark and line
- owner/admin: through
- A sign-in that could not be begun is still said under the row as
.error-message role="alert", inside a.workspace-linearcolumn, as GitHub's, API keys', Members' and Invitations' are. - With both its rows moved, the Integrations group is
SettingsSection(title "Integrations"), itsGITHUB_REPOSITORIESsearch anchor on a wrapperdiv, as Members and Invitations do.SettingsGroupstays for Leave and the read-failure card, which are D22's and later. - Behaviour is unchanged: Connect sends one
WORKSPACE_LINEAR_CONNECTat once, asking nothing, and a second press while it starts sends nothing; Disconnect sendsWORKSPACE_LINEAR_DISCONNECTafter the confirm.
Selectors
.workspace-linearjoins the.api-key, .workspace-identity, .workspace-member, .workspace-invite-row, .workspace-githubcolumn rule and its> .error-messagerule.- Nothing Linear-specific existed to remove.
LinearCopybecamelinearLine, the description alone.
Visible changes
- Connect / Connect again use the shared outline
Buttonface (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-busyand 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 isaria-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 gainedlinearConnectHeldto 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.tsstill lands on the Integrationsh2. pnpm check:affectedexits 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.
| Light | Dark | |
|---|---|---|
| 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



