refactor(desktop): migrate workspace member list onto the design system

Merged
CH
5d ago
+92-63

D18 of the design-system migration (Desktop stack, base feature/desktop-d17-workspace-identity-form, #3393).

What

  • Settings › Workspace › Members uses @luke/ui's SettingsSection, titled "Members", in place of the desktop SettingsGroup. The section's search anchor (SETTINGS_SECTION.MEMBERS, which search results and the person page's link land on) is now on a wrapper div around the section, because SettingsSection takes no anchor.
  • Each member is a SettingsRow through MenuRow's row form (added in D16), replacing the hand-built .settings-copy markup:
    • leading: their face, at the card size, as before
    • label: their name, with You on the reader's own row inside the person card's .actor-card-name wrapper, as before
    • description: their email, kept to one line by OneLine (ellipsis, with a pill showing the whole address when it is cut short)
    • control: their role, then the ⋯, or the ⋯'s empty space on a row with no actions so every role ends in the same column
  • Behaviour is unchanged:
    • who is offered Open profile, Make admin, Make member, Make owner and Remove from workspace (memberActs)
    • Make admin and Make member apply at once
    • Make owner and Remove ask first through ConfirmDialog, and the question goes away with its subject
    • a refused role change is shown under the row (role="alert")
    • the members read and Retry are unchanged
  • No @luke/ui/compat callers lived on this surface.

Selectors

  • New .workspace-member wrapper (row plus its refusal). It joins the existing API keys and identity rules: .api-key, .workspace-identity, .workspace-member and … > .error-message.
  • .settings-row-value and .settings-act-slot now use the contract's tokens (--luke-color-text-muted, the body size and leading, --luke-control-height) instead of the legacy aliases. Both resolve to the same values as before.
  • Nothing became unused. SettingsGroup, .settings-copy, .settings-row and .actor-card-name still have other callers.

Visible changes

  • The name uses the label role (13/18, 500) instead of strong (13/1.35, 500). The email uses the caption role in the subtle colour (12/16) instead of small (12/1.4, tertiary). This matches the identity row above it and the other migrated rows.
  • "Members" uses the shared section heading, which matches the other headings on the page.
  • Below a 380px row, the role and the ⋯ drop below the words to the row's end, as the shared row contract requires.

Tests

  • In workspace-page.test.ts, member rows are now found with a memberNamed helper: a MenuRow inside .workspace-member, matched by its label. The email is read from the row's description instead of the retired small. rowNamed stays for the GitHub and Linear rows, which are still on the old markup. No assertion about behaviour changed.
  • No new tests, because no behaviour changed.
  • 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 a synthetic workspace "acme" with Dana (owner, the reader), Ola (admin) and Sam (member). The output was placed in the built desktop stylesheet inside the SettingsPage frame.

LightDark
Owner's view, with a long address cut short
Role change refused, shown under the row

Not verified on a Mac

  • SF Pro rendering of the rows, faces and You badge
  • Role changes, transfer and removal against a live workspace, which were tested only through the tests
  • The search-result ring landing on the Members wrapper in the real window

🤖 Generated with Claude Code