Skip to content

feat(consumers): migrate consumer groups to UI Registry#2545

Open
jvorcak wants to merge 13 commits into
masterfrom
UX-1371-move-consumer-groups-to-ui-registry
Open

feat(consumers): migrate consumer groups to UI Registry#2545
jvorcak wants to merge 13 commits into
masterfrom
UX-1371-move-consumer-groups-to-ui-registry

Conversation

@jvorcak

@jvorcak jvorcak commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Migrates the consumer groups feature (list, detail, and the edit/delete offset modals) from the legacy @redpanda-data/ui components to the Registry components — matching the already-migrated Topics/Security pages.

List (group-list.tsx)

  • Hand-rolled TanStack useReactTable + Registry Table inside ListLayout
  • URL-persisted page / pageSize / sort / search (nuqs), sortable columns, pagination
  • State faceted filter (all states always available, even when not present in the data)
  • New useLegacyListConsumerGroupsFullQuery hook returning enriched GroupDescription (lagSum/isInUse/perms)

Detail (group-details.tsx)

  • Registry Tabs (Topics / ACL, active tab persisted in the URL), Card stats bar, Accordion per topic, sortable + paginated PartitionTable
  • Disabled Edit/Delete Group buttons now show an explanatory tooltip ("Offsets can only be edited while the group is Empty with no connected members.")
  • Shared ConsumerGroupStateCell (icon + state) reused by both list and detail

Modals (modals.tsx)

  • DeleteOffsetsModal → Registry AlertDialog
  • EditOffsetsModal → Registry Dialog / Select / RadioGroup / Input / Accordion + useReactTable preview tables; toasts moved to sonner. KowlTimePicker kept (no Registry datetime picker yet).
  • modals.tsx no longer imports @redpanda-data/ui at all.

Test plan

  • bun run type:check — pass
  • bun run lint — pass
  • bun run test:integration — all consumer-group tests pass (group-details 2/2); full suite green apart from one unrelated flaky observability-page test that passes in isolation
  • Manual: list sorting/pagination/filter + URL persistence; detail tabs/accordion/partition table; delete + edit offset flows against an Empty group
Screenshot 2026-07-01 at 10 05 29 Screenshot 2026-07-01 at 10 05 41 Screenshot 2026-07-01 at 10 05 36 Screenshot 2026-07-01 at 10 05 49

🤖 Generated with Claude Code

Migrate the consumer groups list, detail page, and the edit/delete
offset modals from legacy @redpanda-data/ui to the Registry components.

List (group-list.tsx):
- TanStack useReactTable + Registry Table inside ListLayout
- URL-persisted page/pageSize/sort/search (nuqs), sortable columns,
  pagination, and a State faceted filter (all states always available)
- New useLegacyListConsumerGroupsFullQuery hook (Connect/REST) returning
  enriched GroupDescription (lagSum/isInUse/perms)

Detail (group-details.tsx):
- Registry Tabs (Topics/ACL, tab persisted in URL), Card stats bar,
  Accordion per topic, and a sortable+paginated PartitionTable
- Disabled Edit/Delete buttons now show an explanatory tooltip
- Shared ConsumerGroupStateCell (icon + state) reused by list and detail

Modals (modals.tsx):
- DeleteOffsetsModal -> Registry AlertDialog
- EditOffsetsModal -> Registry Dialog/Select/RadioGroup/Input/Accordion +
  useReactTable preview tables; toasts moved to sonner
- KowlTimePicker kept (no Registry datetime picker yet)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

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

App: frontend · Scope: diff vs origin/master · Files: 11

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.

jvorcak and others added 6 commits June 30, 2026 21:15
base-ui SelectValue renders the raw selected value, so the "All
Topics/Partitions" sentinel ('__all__') and the strategy keys
(endOffset, ...) leaked into the trigger. Map value -> label via a
SelectValue render function, matching the add-acl-dialog pattern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Empty groups have no protocol/protocolType, which rendered blank stat
values, and the legacy ProtocolType helper duplicated protocolType under
a "Protocol" label. Show the actual group.protocol field (matching the
list column) and group.protocolType with an em-dash fallback, and drop
the redundant ProtocolType component.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Coordinator ID copy button used size="icon" (size-9, 36px), which
was much taller than the stat label text; the flex row stretched every
stat to that height, inflating the card and leaving gaps under the other
labels. Shrink the copy button to size-5 and add items-start so the row
hugs its natural content height.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The migrated partition action buttons use the registry (base-ui) tooltip,
which renders a `[data-slot="tooltip-content"]` popup without
role="tooltip" (the old Chakra tooltip had it). Match on the slot + text
instead of getByRole('tooltip'). No app code changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Local e2e runs remap every host port via E2E_PORTS_OVERRIDE, but the
enterprise config hardcoded shadowBackendURL to http://localhost:3101,
so the shadowlink tests hit ERR_CONNECTION_REFUSED (the dest backend was
on a random port). Resolve the shadow backend port from the override
(falling back to 3101 for CI/static-port runs). No app code changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move DisabledReasonButton out of group-details.tsx into
src/components/ui/ so it can be reused outside consumer group
details. Behavior unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jvorcak jvorcak requested a review from a team July 1, 2026 08:05
jvorcak and others added 3 commits July 1, 2026 10:51
Two layout fixes surfaced by the group list page:

- group-list rendered its table inside ListLayoutContent (flex-1),
  which grew to fill the min-h-screen layout and pushed the pagination
  bar to the bottom of the viewport. Render <Table> directly like the
  other list pages so pagination sits under the last row.
- ListLayoutPagination did not stretch its child, so DataTablePagination
  collapsed to content width and its internal justify-between clustered
  the controls on the left. Add [&>*]:w-full so the controls span the
  row (also fixes topics/quotas/users/roles list pages).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…y drift

The pagination full-width fix edited the vendored list-layout registry
component in-place, which the UI audit flags as locally-modified drift.
Revert list-layout to its released bytes and apply [&>*]:w-full via
className at the ListLayoutPagination call site instead — same render,
no registry drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Console's dialog and tabs were pinned to registry 2.3.0's predecessor
(2.2.0), which the frontend UI audit flags as outdated once the consumer
pages use them. Sync both to the 2.3.0 release:

- dialog: scroll-shadow refactor — useScrollShadow now takes the container
  ref and returns axis-relative { start, end } edges (was sentinel refs +
  { top, bottom }).
- use-scroll-shadow: rewritten to the 2.3.0 geometry-based API (scroll +
  ResizeObserver/MutationObserver, horizontal orientation support). Only
  caller in console is DialogBody; rp-connect only mentions it in a comment.
- tabs: add ScrollableTabsList, pulling in the new drag-scroll-area dep.
- drag-scroll-area: new component from 2.3.0.

Audit now reports dialog + tabs up-to-date at 2.3.0; 0 drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines +137 to +138
// Registry (base-ui) tooltip renders a `[data-slot="tooltip-content"]` popup
// without role="tooltip", so match on the slot + text instead of the role.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds like we should fix this so we can have simpler test assertions to write

// without role="tooltip", so match on the slot + text instead of the role.
await expect(
page.locator('[data-slot="tooltip-content"]').filter({ hasText: 'No committed offset' }).first()
).toBeVisible({ timeout: 5000 });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would refrain from using timeouts if possible

*
* Uses the legacy REST API (same reason as {@link useLegacyListConsumerGroupsQuery}):
* authorization is only possible with Console v3 and above.
* TODO: Remove once Console v3 is released.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like we are still using this despite console v3 being released a long time ago, should we clean it up?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a separate ticket for this.

Comment on lines +22 to +23
variant?: 'ghost' | 'outline' | 'link';
size?: 'icon-sm' | 'sm' | 'md';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just map it from registry so it never gets out of sync, using proper types

},
});

const dialogScrollShadow = 'pointer-events-none sticky z-10 h-0 transition-opacity duration-150';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are all of these properly upstreamed?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's update from the UI registry (see commits)

Base UI's tooltip popup sets no ARIA role, so the disabled-action tooltip
was only reachable via a [data-slot] selector. Set role="tooltip" at the
call site (keeping the registry component free of drift) so it is exposed
as a tooltip to assistive tech and to getByRole in tests.

Derive the button variant/size props from the registry ButtonProps so they
cannot drift from the Button they are forwarded to.

Drop the per-assertion timeouts in the e2e spec: the Playwright config
already sets a 60s expect timeout, so they were only shortening the default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jvorcak jvorcak requested a review from malinskibeniamin July 13, 2026 11:19
jvorcak and others added 2 commits July 13, 2026 13:26
The tooltip reads "No committed offsets" (plural). Switching the assertion
from a substring filter to toHaveText made the exact text matter, so the
singular string no longer matched and the test timed out. Pull the string
into a constant so it stays tied to group-details.tsx.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants