refactor(desktop): migrate integration directory onto the design system
Merged
CH
5d ago+678+678+012345678901234567890123456789-141-141-012345678901234567890123456789
D24 of the design-system migration (Desktop stack, base feature/desktop-d23-coding-agent-defaults, #3402).
What
- New shared
SearchFieldin@luke/ui(per the orchestrator's addendum), used here for the directory's search:- search glyph, controlled
value/onChange,labelrequired by type (the accessible name) - end slot: a typed
tally({ count, at?, more? }→ "No results" / "4 results" / "500+ results" / "3 of 12", in a polite live region while a query stands) or atrailingReactNode shortcut: the summoning chord, shown while empty and unfocusedonClear: a built-in "Clear search" button while a query stands, which hands the caret backonEnter/onShiftEnter/onEscape, ignored while an IME composes (isComposingor keyCode 229). An Escape the field answers is stopped from reaching the surface behind it even mid-composition, which is what find-in-tab and this page already did.id,keyShortcuts(aria-keyshortcuts),placeholder,ref. NoclassName/style.- Desktop tokens: control height (30px), control radius, control icon, body type; same well, fill, border, inset and nested clear as the old
.settings-search-well. - Catalog example (
search-fields), jsdom tests for typing, Enter/Shift+Enter/Escape, IME, tally, chord and clear. - The command palette, find-in-tab, the Settings sidebar search and the file tree still use the bespoke well; they move in follow-ups, so
.settings-search-*stays.
- search glyph, controlled
- Settings › Integrations:
- The page's search is
SearchField. Command-F still lands in it, Escape still clears a query and then lets go of the caret, and Settings' own search still hands its query down. - Connected and Not connected (and the read-failed card) are
SettingsSectioninstead of the desktop'sSettingsGroup. - Each row is
MenuRow'sSettingsRowform, as D20 and D21 did: the provider mark isleading, the name (search words still marked) is the label, and the status line (connected with its tool count toggle, checking, waiting with its ring, expired, refused) is the description. Rename still swaps the label for the name field. The ⋯ menu, right-click, search anchor and the GitHub heading are unchanged. - Each row, its tools panel and its refusal share an
.integration-rowwrapper. That wrapper joins the existing refusal-under-row rules, and the panel's hairline now hangs off it rather than.settings-card.
- The page's search is
- Left for their own rows: the Connect / Reconnect / Reopen / Cancel buttons are still the window's own buttons (D26, connection controls), and the tools panel is untouched (D25). This page imported nothing from
@luke/ui/compat.
Selectors
- Moved:
.settings-card > .integration-tools-panelbecomes.integration-row > .integration-tools-panel. - None removed:
.settings-search-well/-input/-shortcut/-clear,.field-well,.settings-group*,.settings-card*and.settings-noteall still have other callers..integrations-filterand.integration-account-inputhad no rules; the page no longer uses either class.
Visible changes
- Row names use the label role (13/18, 500). They were
<strong>in.settings-copy. - Status lines use the caption role (12/16, subtle ink). They were 12px/1.4, tertiary.
- Section headings are the shared section heading. They were the old 12px/600 group title.
- Below a 380px row, the row's button and ⋯ drop below the words, per the shared row contract.
- The search field looks the same (30px, 8px radius, same fill, border, inset and nested clear). It now draws in
--luke-font-sansrather than inheriting, which is the same face.
Tests
integrations-page.test.tspasses (42 tests) with its locators moved to the shared row (.luke-settings-row,[id$="label"]) and section (.luke-settings-section,h2). That covers search filtering, grouping order, row status lines, Clear search, and Command-F/Escape not reaching the window.- New
search-field.test.ts(7, jsdom). pnpm check:affectedexits 0.
Evidence
Captured on Linux with headless Chrome at 1280×840, animations held still. A throwaway, uncommitted copy of the page's test rendered the real IntegrationsSection in jsdom, with synthetic statuses and tools. The result was placed in the built desktop stylesheet inside the SettingsPage frame. The ⌘ in the chord shows as a missing glyph only because Linux has no font for it.
| Light | Dark | |
|---|---|---|
| Connected with Linear's tools open, Notion expired, Vercel connected | ![]() | ![]() |
| "deploy": one row kept, opened onto the tool it found, with the clear button | ![]() | ![]() |
| A query that finds nothing | ![]() | ![]() |
Not verified on a Mac
- SF Pro rendering of the rows and the ⌘F chord
- Command-F landing in the field in the real window (covered by the jsdom test only)
- Japanese/Chinese IME composition in the real field (covered by the jsdom tests only)
- Connecting, reconnecting and disconnecting against the live service, which only the tests cover
🤖 Generated with Claude Code





