Skip to content

[Chakra exit · Phase 1 · PR 4/14] frontend: SingleSelect and the error/not-found surfaces on Registry components, plus two guard tests - #2629

Open
SpicyPete wants to merge 1 commit into
chakra-exit/03-display-primitivesfrom
chakra-exit/04-interactive-surfaces
Open

[Chakra exit · Phase 1 · PR 4/14] frontend: SingleSelect and the error/not-found surfaces on Registry components, plus two guard tests#2629
SpicyPete wants to merge 1 commit into
chakra-exit/03-display-primitivesfrom
chakra-exit/04-interactive-surfaces

Conversation

@SpicyPete

@SpicyPete SpicyPete commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Chakra exit · Phase 1 (wrappers) · PR 4 of 14

Part of the Chakra exit plan and live tracker. Phase 1 re-implements the shared wrappers behind their existing exports, so page code does not change. Last PR of the phase. Branch chakra-exit/04-interactive-surfaces, stacked on #2628; each PR on the ladder shows only its own diff and re-targets master as its base merges.

The last Phase 1 PR. SingleSelect keeps its export and moves onto the Registry Select (and the Registry Combobox for its one creatable caller); the error, not-found and modal-container surfaces move onto Tailwind and Registry Dialog / Empty / Button. Two app-owned guard tests pin registry contracts the registry itself ships untested.

misc/select.tsx — the hunk that carries judgement

SingleSelect<T> keeps options / value / onChange / isDisabled / placeholder / creatable / data-testid, so its 9 call sites in 7 files do not change — except login.tsx, which passed a chakraStyles object that returned provided unchanged; type:check flagged it and it is gone.

  • Values round-trip through a string key. The Registry Select keys on strings; callers pass enums (SASLMechanism, SCRAMAuth_Mechanism), numbers (schema versions) and string unions. toKey(value) maps each option to String(value) and back, so onChange still receives the typed value. A value that matches no option (create-connector's undefined cluster) renders the placeholder instead of an empty label.
  • creatable goes to the Registry Combobox, which is the searchable/creatable one; the plain Select has no text input. Only preview-settings.tsx uses it, with string values. clearable={false} keeps the old "no clear button" behaviour. Because onChange fires with the typed text on create, T must be string there — noted on the prop.
  • data-testid still wraps the control in a div, as before. The e2e page object clicks that wrapper and then an option by exact text, which the Registry Select satisfies; the only live spec assertions on these three ids are toBeVisible().
  • tests/mock-react-select.tsx and its two setup-file imports are gone. Nothing rendered a react-select under test any more, so no test changes.

Error and not-found surfaces (exports unchanged)

Module Was Now
misc/error-result HStack/Stack/Heading/Text, Chakra CodeBlock, Chakra Avatars asset flex divs, text-heading-lg / text-body-lg, Registry SimpleCodeBlock, the local ErrorBananaSlip.svg the not-found page already uses
misc/error-display Chakra Result + Button, Chakra Section, List/ListItem/ListIcon Registry Empty (title, description, Retry Button), the app Section wrapper, a plain ul with the existing WarningIcon
misc/error-modal Chakra Modal with onCloseComplete driving the modal queue Registry Dialog size="lg"; Base UI's onOpenChangeComplete(false) is the same hook, so the queue's afterClose still fires after the exit transition. The Dialog adds its close button; it routes through onClose like OK does
misc/error-boundary Box/Flex/Icon, Chakra Button size="large" isLoading divs, Registry Button size="lg" with icon and isLoading
misc/not-found-page, misc/not-found-content Center/Stack/Image/Heading as="h1" flex divs, img, h1.text-heading-xl — the h1 keeps the test's getByRole('heading', { level: 1 }) contract; the test's hand-written Chakra mock is deleted
utils/modal-container Box div

Guard tests (new, app-owned, in src/components/registry-guards/)

  • Expanded rows survive a data swap (data-table-expanded-rows.test.tsx): expands a row, replaces the data array, flushes TanStack's scheduled reset, and expects the sub-row to stay. Verified negative: with tableOptions={{ autoResetExpanded: true }} the same test fails.
  • Alert paints one icon (alert-default-icon.test.tsx): default icon, custom icon replacing it, icon={null} painting none. The Chakra pattern (an icon child) paints two, which is the case every <AlertIcon /> swap in Phase 2 must avoid; 11 files still pass <AlertIcon /> to Chakra's Alert and are listed in the plan.

Not in src/components/ui/ because Biome ignores that directory; these must stay linted.

Effect

Files importing @redpanda-data/ui: 89 → 81. misc/ is down to the chrome leftovers PR 8 owns.

Gates

bun run type:check · bun run lint (no dirty tree; remaining findings on touched files are pre-existing on master) · unit suite · integration suite (123 files / 1274 tests), including not-found-page.test.tsx and the two guards. To exercise by hand: the debug dialog's "Throw in render (ErrorBoundary)" button, and any failing backend call for ErrorDisplay / showErrorModal.

Review pass (2026-09-03)

  • Base UI popups inside Chakra modals. SingleSelect is the first Registry popup rendered inside a Chakra Modal (column settings, preview fields). Chakra's scroll lock swallows wheel events outside the modal and its focus lock pulls focus back, so both modals now provide a PortalContainer and the popups render inside them. Noted for the feat: new topic messages page behind enableNewTopicMessagesPage flag #2588 stream, which owns those files.
  • SingleSelect: an unset value selects nothing instead of colliding with an empty-string option; the Combobox's clear signals (re-select, Escape, blur) are ignored so a preview-tag pattern can no longer be emptied by accident; id lands on the trigger and the login form's "SASL Mechanism" label points at it again; options are mapped once.
  • Behaviour that differs from react-select and is accepted: the plain Select has no type-to-filter, and typed-but-uncommitted Combobox text stays visible after blur.
  • Error boundary icons lead their labels again; the error dialog is size="xl" to keep its old width; the Alert guard drops the test that asserted the footgun itself, keeping the three contract tests.

Plan (internal): https://claude.ai/code/artifact/1861e21c-624b-4270-98ad-9921b22c2498

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Clean — no registry drift, off-token colours, or ad-hoc classes

App: frontend · Scope: diff vs origin/chakra-exit/03-display-primitives · Files: 15

Count
⚠️ Outdated registry components 0
🛠 Locally-modified components 0
❓ Unknown to registry 0
🎨 Off-token palette colours 0
🔢 Ad-hoc utility classes 0

Generated by lookout audit-changes.

@SpicyPete SpicyPete changed the title frontend: SingleSelect and the error/not-found surfaces on Registry components, plus two guard tests [Chakra exit · Phase 1 · PR 4/14] frontend: SingleSelect and the error/not-found surfaces on Registry components, plus two guard tests Sep 2, 2026
@SpicyPete
SpicyPete requested review from a team, Mateoc, graham-rp, jvorcak and yougotashovel and removed request for a team September 2, 2026 22:15
@SpicyPete SpicyPete self-assigned this Sep 2, 2026
@SpicyPete
SpicyPete force-pushed the chakra-exit/03-display-primitives branch from a3fe072 to 8e31d03 Compare September 3, 2026 15:30
@SpicyPete
SpicyPete force-pushed the chakra-exit/04-interactive-surfaces branch from e664510 to 3de4dd2 Compare September 3, 2026 15:30
@SpicyPete
SpicyPete force-pushed the chakra-exit/03-display-primitives branch from 8e31d03 to 85b9ef3 Compare September 3, 2026 15:53
@SpicyPete
SpicyPete force-pushed the chakra-exit/04-interactive-surfaces branch from 3de4dd2 to 718f6b8 Compare September 3, 2026 15:53
@SpicyPete
SpicyPete force-pushed the chakra-exit/03-display-primitives branch from 85b9ef3 to dd5ebb7 Compare September 3, 2026 23:08
@SpicyPete
SpicyPete force-pushed the chakra-exit/04-interactive-surfaces branch from 718f6b8 to 0e22b80 Compare September 3, 2026 23:08
@SpicyPete
SpicyPete force-pushed the chakra-exit/03-display-primitives branch from dd5ebb7 to fad9e0b Compare September 4, 2026 14:06
@SpicyPete
SpicyPete force-pushed the chakra-exit/04-interactive-surfaces branch from 0e22b80 to 88ffd56 Compare September 4, 2026 14:06
@SpicyPete
SpicyPete force-pushed the chakra-exit/03-display-primitives branch from fad9e0b to fb58adc Compare September 4, 2026 14:55
@SpicyPete
SpicyPete force-pushed the chakra-exit/04-interactive-surfaces branch 2 times, most recently from 37a4888 to ecdd0a9 Compare September 4, 2026 15:17
…omponents, plus two guard tests

Last Phase 1 PR of the Chakra exit. Every wrapper keeps its export.

- misc/select: SingleSelect<T> on the Registry Select; values round-trip
  through a string key so enum/number callers keep their types, an unset
  value selects nothing (no collision with an empty-string option), and an
  `id` lands on the trigger for <label htmlFor>. The one `creatable`
  caller (preview-settings) goes to the Registry Combobox with the old
  cannot-clear behaviour kept. `data-testid` still wraps the control in a
  div, which is the e2e page object's contract. login.tsx drops a no-op
  chakraStyles prop and labels the SASL select through FormControl's id.
  tests/mock-react-select.tsx and its two setup imports are gone; nothing
  rendered react-select under test.
- Tab.Messages column-settings and preview-fields-modal: the two Chakra
  modals that host SingleSelect provide a PortalContainer, so Base UI
  popups render inside the modal's focus and scroll lock.
- misc/error-result: flex divs + text-heading-lg/text-body-lg, Registry
  SimpleCodeBlock, the local ErrorBananaSlip.svg instead of Chakra Avatars.
- misc/error-display: Chakra Result -> Registry Empty + Button; Chakra
  Section -> the app Section wrapper; List -> a plain ul.
- misc/error-modal: Chakra Modal -> Registry Dialog size="xl" (keeps the
  old 3xl footprint); Base UI's onOpenChangeComplete(false) replaces
  onCloseComplete for the queue.
- misc/error-boundary: Box/Flex/Icon -> divs; Registry Button size="lg"
  with leading icons and isLoading.
- misc/not-found-page, not-found-content: divs + h1.text-heading-xl (keeps
  the level-1 heading the test asserts); the test's Chakra mock is deleted.
- utils/modal-container: Box -> div.
- src/components/registry-guards/: app-owned tests for two registry
  contracts the registry ships untested - an expanded DataTable row
  survives a data swap (fails with autoResetExpanded: true), and Alert
  paints exactly one icon by default, replaces it for `icon`, and paints
  none for `icon={null}`. Not under components/ui/ because Biome ignores
  that directory.

Importers of @redpanda-data/ui: 89 -> 81.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@SpicyPete
SpicyPete force-pushed the chakra-exit/03-display-primitives branch from ba59065 to 2a6dbb6 Compare September 4, 2026 15:56
@SpicyPete
SpicyPete force-pushed the chakra-exit/04-interactive-surfaces branch from ecdd0a9 to 054ad0d Compare September 4, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant