Skip to content

feat: limit badges to 2 with hover/click popover in UserListTable#35

Open
tomerqodo wants to merge 2 commits intocoderabbit_full_base_feat_limit_badges_to_2_with_hover_click_popover_in_userlisttable_pr8from
coderabbit_full_head_feat_limit_badges_to_2_with_hover_click_popover_in_userlisttable_pr8
Open

feat: limit badges to 2 with hover/click popover in UserListTable#35
tomerqodo wants to merge 2 commits intocoderabbit_full_base_feat_limit_badges_to_2_with_hover_click_popover_in_userlisttable_pr8from
coderabbit_full_head_feat_limit_badges_to_2_with_hover_click_popover_in_userlisttable_pr8

Conversation

@tomerqodo
Copy link

@tomerqodo tomerqodo commented Jan 29, 2026

Benchmark PR from agentic-review-benchmarks#8

Summary by CodeRabbit

  • New Features

    • New badge list UI component that displays items with customizable visibility limits and popover support for hidden items on hover (desktop only).
  • Refactor

    • Simplified insights value display by adopting the new badge list component.
    • Enhanced code organization and type safety in table components.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 29, 2026

Walkthrough

A new LimitedBadges UI component is introduced to render badges with overflow handling via a popover. ResponseValueCell is refactored to use LimitedBadges instead of Badge and HoverCard components, and its rowId prop is removed. The hook useInsightsColumns is updated to stop passing rowId. UserListTable exports are reorganized from default to named exports with type refinements.

Changes

Cohort / File(s) Summary
New UI Component
apps/web/components/ui/LimitedBadges.tsx
Introduces LimitedBadges component that displays a configurable number of visible badges with a popover overlay for hidden items. Includes responsive behavior via useMediaQuery to disable popover on mobile, per-item onClick handlers, and customizable badge variants.
Component Refactoring
apps/web/modules/insights/components/ResponseValueCell.tsx
Replaces multi-branch Badge and HoverCard rendering with simplified LimitedBadges composition. Removes rowId prop and useId-based cellId generation. Reduces component dependencies and simplifies signature.
Hook Update
apps/web/modules/insights/hooks/useInsightsColumns.tsx
Removes rowId prop passed to ResponseValueCell in dynamic field rendering for multi/single select values.
Export Reorganization
apps/web/modules/users/components/UserTable/UserListTable.tsx
Converts default function export to non-exported function with named exports at bottom. Moves UserListTableProps type to bottom-level re-export. Updates return type annotations and generic type specifications throughout for improved type safety.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Poem

🐰 A new badge box hops onto the scene,
With popover magic, so sleek and clean!
Old cards retire as components align,
Exports refined—now the types all shine! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: introducing a LimitedBadges component that limits visible badges to a maximum with a hover/click popover for overflow items, and integrating it into ResponseValueCell and UserListTable.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/web/components/ui/LimitedBadges.tsx`:
- Around line 68-97: In LimitedBadges, the overflow items in hiddenItems are
rendered as plain <span> elements so their onClick handlers never fire and the
key uses only item.label which can collide; update the hiddenItems rendering
inside PopoverContent to render each entry as an interactive element (e.g.,
Button or Badge with onClick={item.onClick} and the same hover/mouse handlers
like handleMouseEnter/handleMouseLeave) and replace the unstable key
(item.label) with a stable identifier such as item.id or a compound key like
`${item.id ?? item.label}-${index}` to avoid collisions and ensure clicks
trigger the intended actions.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab49951 and 8b8cbd5.

📒 Files selected for processing (4)
  • apps/web/components/ui/LimitedBadges.tsx
  • apps/web/modules/insights/components/ResponseValueCell.tsx
  • apps/web/modules/insights/hooks/useInsightsColumns.tsx
  • apps/web/modules/users/components/UserTable/UserListTable.tsx
💤 Files with no reviewable changes (1)
  • apps/web/modules/insights/hooks/useInsightsColumns.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/modules/insights/components/ResponseValueCell.tsx (1)
apps/web/components/ui/LimitedBadges.tsx (1)
  • LimitedBadges (107-107)
🔇 Additional comments (6)
apps/web/modules/insights/components/ResponseValueCell.tsx (1)

1-21: LGTM: simplified rendering via LimitedBadges.

apps/web/modules/users/components/UserTable/UserListTable.tsx (5)

3-65: LGTM: updated imports, explicit return types, and named exports.

Also applies to: 124-159, 746-747


200-266: LGTM: attribute values now render consistently via LimitedBadges.


282-518: LGTM: column cell typings and badge rendering are consistent.


541-543: LGTM: table config tweaks and download handler typing.

Also applies to: 581-632


666-734: LGTM: bulk-action gating and analytics capture.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +68 to +97
{visibleItems.map((item, index) => (
<Badge key={item.label} variant={item.variant || "gray"} onClick={item.onClick}>
{item.label}
</Badge>
))}
{hasHiddenItems && (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<Button
color="minimal"
className="h-auto p-0 border-0 hover:border-0"
aria-label={`Show ${hiddenItems.length} more items`}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<Badge variant="gray">+{hiddenItems.length}</Badge>
</Button>
</PopoverTrigger>
<PopoverContent
side="bottom"
align="start"
className="w-fit p-2"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<div className="flex flex-col gap-1">
{hiddenItems.map((item, index) => (
<span
key={item.label}
className="text-default cursor-pointer text-sm hover:text-emphasis">
{item.label}
</span>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hidden overflow badges aren’t clickable (and keys may collide).

Overflow items are rendered as plain spans, so onClick handlers never fire (e.g., team filter actions). Also, using item.label alone as a key can collide when labels repeat. Consider rendering overflow items as buttons and using a stable key.

🛠️ Proposed fix
-      {visibleItems.map((item, index) => (
-        <Badge key={item.label} variant={item.variant || "gray"} onClick={item.onClick}>
+      {visibleItems.map((item, index) => (
+        <Badge key={`${item.label}-${index}`} variant={item.variant || "gray"} onClick={item.onClick}>
           {item.label}
         </Badge>
       ))}
@@
-              {hiddenItems.map((item, index) => (
-                <span
-                  key={item.label}
-                  className="text-default cursor-pointer text-sm hover:text-emphasis">
-                  {item.label}
-                </span>
-              ))}
+              {hiddenItems.map((item, index) => (
+                <button
+                  key={`${item.label}-${index}`}
+                  type="button"
+                  onClick={item.onClick}
+                  disabled={!item.onClick}
+                  className={`text-default text-sm bg-transparent p-0 border-0 ${
+                    item.onClick ? "cursor-pointer hover:text-emphasis" : "cursor-default"
+                  }`}>
+                  {item.label}
+                </button>
+              ))}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{visibleItems.map((item, index) => (
<Badge key={item.label} variant={item.variant || "gray"} onClick={item.onClick}>
{item.label}
</Badge>
))}
{hasHiddenItems && (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<Button
color="minimal"
className="h-auto p-0 border-0 hover:border-0"
aria-label={`Show ${hiddenItems.length} more items`}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<Badge variant="gray">+{hiddenItems.length}</Badge>
</Button>
</PopoverTrigger>
<PopoverContent
side="bottom"
align="start"
className="w-fit p-2"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<div className="flex flex-col gap-1">
{hiddenItems.map((item, index) => (
<span
key={item.label}
className="text-default cursor-pointer text-sm hover:text-emphasis">
{item.label}
</span>
{visibleItems.map((item, index) => (
<Badge key={`${item.label}-${index}`} variant={item.variant || "gray"} onClick={item.onClick}>
{item.label}
</Badge>
))}
{hasHiddenItems && (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<Button
color="minimal"
className="h-auto p-0 border-0 hover:border-0"
aria-label={`Show ${hiddenItems.length} more items`}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<Badge variant="gray">+{hiddenItems.length}</Badge>
</Button>
</PopoverTrigger>
<PopoverContent
side="bottom"
align="start"
className="w-fit p-2"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<div className="flex flex-col gap-1">
{hiddenItems.map((item, index) => (
<button
key={`${item.label}-${index}`}
type="button"
onClick={item.onClick}
disabled={!item.onClick}
className={`text-default text-sm bg-transparent p-0 border-0 ${
item.onClick ? "cursor-pointer hover:text-emphasis" : "cursor-default"
}`}>
{item.label}
</button>
))}
🤖 Prompt for AI Agents
In `@apps/web/components/ui/LimitedBadges.tsx` around lines 68 - 97, In
LimitedBadges, the overflow items in hiddenItems are rendered as plain <span>
elements so their onClick handlers never fire and the key uses only item.label
which can collide; update the hiddenItems rendering inside PopoverContent to
render each entry as an interactive element (e.g., Button or Badge with
onClick={item.onClick} and the same hover/mouse handlers like
handleMouseEnter/handleMouseLeave) and replace the unstable key (item.label)
with a stable identifier such as item.id or a compound key like `${item.id ??
item.label}-${index}` to avoid collisions and ensure clicks trigger the intended
actions.

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.

1 participant