Skip to content

Inline group creating when editing wave#2285

Merged
simo6529 merged 11 commits intomainfrom
inline-group-creating-when-editing-wave
Apr 16, 2026
Merged

Inline group creating when editing wave#2285
simo6529 merged 11 commits intomainfrom
inline-group-creating-when-editing-wave

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Apr 16, 2026

Summary by CodeRabbit

  • New Features

    • Added a modal "Change group" dialog for selecting or creating groups inline.
    • Group search now exposes accessible combobox interactions and keyboard navigation.
  • Improvements

    • Configurable group-clearing controls (can be disabled where needed).
    • Streamlined inline group creation with suggested names and clearer selection flows.
    • Search field debouncing and result highlighting improved for reliability and UX.

Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

Warning

Rate limit exceeded

@simo6529 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 31 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 31 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9a1cd0f-7f50-44a7-8b44-20447a5ae306

📥 Commits

Reviewing files that changed from the base of the PR and between b533056 and ef5979e.

📒 Files selected for processing (3)
  • __tests__/components/waves/create-wave/groups/CreateWaveGroupSearchField.test.tsx
  • components/waves/create-wave/groups/CreateWaveGroupSearchResults.tsx
  • components/waves/create-wave/groups/useCreateWaveGroupSearch.ts
📝 Walkthrough

Walkthrough

This refactor removes externally managed inline group-builder state from useWaveConfig and component props, moves builder state into CreateWaveGroupInlinePanel, breaks the group search into a hook + input/results components, and adds a WaveGroupChangeDialog and associated change/create flows with updated auth and mutation handling.

Changes

Cohort / File(s) Summary
Tests — group-builder removal & new search tests
__tests__/components/waves/create-wave/CreateWave.test.tsx, __tests__/components/waves/create-wave/groups/CreateWaveGroup.test.tsx, __tests__/components/waves/create-wave/groups/CreateWaveGroups.test.tsx, __tests__/components/waves/create-wave/groups/CreateWaveGroupInlinePanel.test.tsx, __tests__/components/waves/create-wave/groups/CreateWaveGroupSearchField.test.tsx, __tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx, __tests__/hooks/useWaveConfig.test.ts
Removed mocked groupBuilders and related callbacks from multiple tests; rewrote inline-panel tests to use controlled render harness; added comprehensive CreateWaveGroupSearchField tests; updated useWaveConfig and edit-button tests to match new onChange/onCreateGroup flows.
Top-level create flow — prop cleanup
components/waves/create-wave/CreateWave.tsx, components/waves/create-wave/groups/CreateWaveGroups.tsx, components/waves/create-wave/groups/CreateWaveGroup.tsx
Removed group-builder props from component signatures and JSX wiring; CreateWaveGroup now computes suggestedName and forwards simplified onChange/onCreateGroup.
Inline panel — internalized builder state
components/waves/create-wave/groups/CreateWaveGroupInlinePanel.tsx
Converted to internal builder state (createInitialInlineGroupBuilderState), added panel constants, identity dedupe, rule edit flow, and changed API to accept suggestedName, allowGroupClear, onChange, onCreateGroup.
Search decomposition — hook + input + results
components/waves/create-wave/groups/useCreateWaveGroupSearch.ts, components/waves/create-wave/groups/CreateWaveGroupSearchField.tsx, components/waves/create-wave/groups/CreateWaveGroupSearchInput.tsx, components/waves/create-wave/groups/CreateWaveGroupSearchResults.tsx
Extracted search/combobox state into useCreateWaveGroupSearch (debounce, query, keyboard, click-away, clear behavior), added accessible CreateWaveGroupSearchInput and animated CreateWaveGroupSearchResults; introduced allowClear prop.
Inline builder factory removal
components/waves/create-wave/groups/createWaveInlineGroupBuilder.ts
Deleted createInitialInlineGroupBuilderMap factory and removed an unused import.
useWaveConfig — remove builder API
components/waves/create-wave/hooks/useWaveConfig.ts
Removed groupBuilders state and all builder mutator functions from the hook and its return value.
New dialog & edit flow
components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx, components/waves/specs/groups/group/edit/WaveGroupEditButtons.tsx, components/waves/create-wave/groups/CreateWaveInlineGroupSearch.tsx
Added WaveGroupChangeDialog (portal + focus trap) wired to CreateWaveGroupInlinePanel with allowGroupClear=false; WaveGroupEditButtons now opens dialog and integrates inline-create via useGroupMutations, with success toast and controlled auth skip; CreateWaveInlineGroupSearch forwards allowGroupClear prop.

Sequence Diagram(s)

sequenceDiagram
    actor User as "User"
    rect rgba(240,248,255,0.5)
    participant UI as "CreateWaveGroupInlinePanel / Dialog"
    participant SearchHook as "useCreateWaveGroupSearch"
    participant API as "Groups API"
    end
    rect rgba(245,255,250,0.5)
    participant Mutations as "useGroupMutations / updateWave"
    participant AppState as "Parent (onChange/onCreateGroup)"
    end

    User->>UI: open panel / type search
    UI->>SearchHook: onInputChange / onInputFocus
    SearchHook->>API: query groups (debounced)
    API-->>SearchHook: suggestions
    SearchHook-->>UI: suggestions / open list
    User->>UI: select suggestion
    UI->>AppState: onChange(selectedGroup)
    AppState-->>UI: propagate selection (selectedGroup)
    User->>UI: click create new group
    UI->>Mutations: onCreateGroup(payload)
    Mutations->>API: submit create
    API-->>Mutations: created group
    Mutations-->>AppState: return created group
    AppState->>UI: onChange(createdGroup)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • ragnep

"🐰 I hopped into the panel bright,
Took builder bits and made them light.
Search split clean, dialog in place,
Groups now choose with kinder grace.
🥕✨"

🚥 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 'Inline group creating when editing wave' directly relates to the main objective of this PR: moving group creation from a builder-state model to an inline panel model that allows creating groups during wave editing.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch inline-group-creating-when-editing-wave

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
__tests__/components/waves/create-wave/groups/CreateWaveGroupInlinePanel.test.tsx (1)

45-69: ⚠️ Potential issue | 🟠 Major

Make the search-field mock respect allowClear.

The real CreateWaveGroupSearchField now gates clearing behind allowClear, but this mock always renders a working "clear group" button. That means the new "clearing is disabled" test is no longer verifying the real integration and can pass or fail for the wrong reason. Mirror the prop in the mock before asserting disabled-clear behavior.

🧪 Suggested fix
       <div data-testid="group-search">
         <div>{props.selectedGroup?.name ?? "No group selected"}</div>
         <button
           type="button"
           onClick={() =>
             props.onSelect({
               id: "group-2",
               name: "Selected Group",
               created_by: { handle: "builder" },
             })
           }
         >
           select group
         </button>
-          <button type="button" onClick={() => props.onSelect(null)}>
-            clear group
-          </button>
+        {props.allowClear !== false && (
+          <button type="button" onClick={() => props.onSelect(null)}>
+            clear group
+          </button>
+        )}
       </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@__tests__/components/waves/create-wave/groups/CreateWaveGroupInlinePanel.test.tsx`
around lines 45 - 69, The mock for CreateWaveGroupSearchField always renders an
active "clear group" button which ignores the allowClear prop; update the
MockCreateWaveGroupSearchField implementation to read props.allowClear and only
render the clear-control when allowClear is true (or render a disabled/absent
button when false) so tests that assert clearing-is-disabled reflect the real
component behavior and the onClick handler is not exposed when allowClear is
false.
🧹 Nitpick comments (5)
__tests__/hooks/useWaveConfig.test.ts (1)

27-42: Broaden this to the other onGroupSelect branches.

The hook still has separate paths for CAN_DROP, CAN_VOTE, CAN_CHAT, and ADMIN, plus the clear-to-null case. Exercising only CAN_VIEW leaves most of that switch unguarded after the refactor. A small table-driven test would cover the rest cheaply.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/hooks/useWaveConfig.test.ts` around lines 27 - 42, Add table-driven
cases to the existing test for useWaveConfig to exercise all onGroupSelect
branches: call result.current.onGroupSelect with a sample group and each
CreateWaveGroupConfigType value (CAN_VIEW, CAN_DROP, CAN_VOTE, CAN_CHAT, ADMIN)
and assert that the corresponding config.groups.<field> (e.g.,
config.groups.canView, canDrop, canVote, canChat, admin) equals the group's id
and that groupsCache["group-1"] equals the group; also include the clear-to-null
case by calling onGroupSelect with group: null for one of the types and assert
the corresponding config.groups.<field> becomes null. Use the existing group
object and the onGroupSelect function name to locate where to add the looped
assertions.
__tests__/components/waves/create-wave/groups/CreateWaveGroupSearchField.test.tsx (1)

41-48: useDebounce mock has an eslint-exhaustive-deps-like issue.

The mock calls callback inside a useEffect but the callback itself isn't in the dependency array - only deps is passed. While this works for testing (it just runs synchronously), the pattern could cause stale closure issues if callback changes. Consider including callback in deps:

     useDebounce: (
       callback: () => void,
       _delay: number,
       deps: DependencyList
     ) => {
-      React.useEffect(callback, deps);
+      React.useEffect(callback, [...deps, callback]);
     },

However, since this is a test mock and the intent is to run synchronously, this is a minor concern.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@__tests__/components/waves/create-wave/groups/CreateWaveGroupSearchField.test.tsx`
around lines 41 - 48, The useDebounce mock in the test calls
React.useEffect(callback, deps) which omits the callback from the dependency
array and can cause stale closure issues; update the mock for useDebounce (the
function named useDebounce in this test) to include the callback in the
dependency array (e.g., React.useEffect(callback, [callback, ...deps]) or
combine callback with deps) so the effect re-runs when the callback changes
while preserving the synchronous test behavior.
__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx (1)

396-420: Mock placement after describe block is unconventional.

The @headlessui/react mock is placed after the describe block ends. While Jest hoists jest.mock() calls to the top of the file regardless of placement, this makes the test file harder to read and maintain. Consider moving this mock to join the other mocks at the top of the file (around lines 12-185).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx`
around lines 396 - 420, The jest.mock for "@headlessui/react" is placed after
the describe block; move that jest.mock(...) declaration up with the other
top-of-file mocks so it sits alongside the other mock setups (i.e., before any
describe/it blocks) to improve readability and maintenance; keep the mock
implementation exactly as-is (Menu, MenuButton, MenuItems, MenuItem, Transition
and the local close jest.fn()) and ensure no duplicate identifiers collide when
moved.
components/waves/create-wave/groups/useCreateWaveGroupSearch.ts (1)

327-338: Complex conditional logic for clearing selection on input change.

The logic for deciding whether to clear the selection when the user types is a bit complex: it clears only if there's a selectedGroup AND allowClear is true. Consider adding a brief comment explaining this behavior for future maintainers.

 const handleInputChange = (value: string) => {
+  // Clear selection when user modifies input text (if clearing is allowed)
   setSearchState({
     selectedGroupKey: selectedGroup && allowClear ? null : selectedGroupKey,
     inputValue: value,
     searchCriteria: value,
     activeIndex: -1,
   });
   setIsOpen(true);
   if (selectedGroup && allowClear) {
     onSelect(null);
   }
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/waves/create-wave/groups/useCreateWaveGroupSearch.ts` around lines
327 - 338, The handleInputChange function currently clears the selected group
only when both selectedGroup and allowClear are true, which is subtle; add a
concise inline comment above the conditional (referencing handleInputChange,
selectedGroup, allowClear, and onSelect) explaining that typing will reset the
selection only when a selection exists and clearing is permitted, and note that
onSelect(null) is invoked to notify consumers of the clear action.
components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx (1)

116-123: Using <dialog> with open attribute but without native dialog methods.

The <dialog> element is rendered with the open attribute, bypassing the native showModal() method. This means the browser's built-in modal behavior (like automatic focus trapping and backdrop) isn't used. Since you're using FocusTrap and a manual backdrop, this works, but consider whether a plain <div role="dialog"> would be more semantically appropriate given the non-native usage.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx` around
lines 116 - 123, The dialog is rendered with a raw <dialog> element but not
using native showModal()/close(), so either use the native API or switch to a
semantic non-native element: update WaveGroupChangeDialog to either call
modalRef.current.showModal() / close() (and manage backdrop/focus via the
existing modalRef and lifecycle hooks) so the <dialog> uses native modal
behavior, or replace the <dialog> tag with a <div role="dialog"> (preserving
aria-modal="true", aria-labelledby={titleId}, aria-describedby={descriptionId},
tabIndex={-1} and the existing className and modalRef) and continue using
FocusTrap and the manual backdrop; reference modalRef, titleId, descriptionId,
and the component WaveGroupChangeDialog when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx`:
- Around line 26-30: The mock for useGroupMutations is incomplete—only submit
(mockSubmitInlineGroup) is provided while the real hook also exposes validate,
runTest, updateVisibility, isSubmitting, isTesting, and isUpdatingVisibility;
update the jest.mock so useGroupMutations returns stubbed implementations for
validate, runTest, updateVisibility and the boolean flags (isSubmitting,
isTesting, isUpdatingVisibility) alongside submit (use existing
mockSubmitInlineGroup) to mirror the real hook's shape and avoid undefined
property access in components or tests.

In `@components/waves/create-wave/groups/CreateWaveGroupSearchInput.tsx`:
- Around line 79-84: The aria-label on the clear button is generic and can be
misleading because showClearButton is true for both a typed query and a selected
group; update the button rendering (the element using showClearButton,
onClearSelection, and aria-label) to set aria-label dynamically based on
hasSelectedGroup (use "Clear selected group" when hasSelectedGroup is true,
otherwise "Clear search") so screen readers announce the correct action.

In `@components/waves/create-wave/groups/CreateWaveGroupSearchResults.tsx`:
- Around line 160-164: The loading branch in CreateWaveGroupSearchResults
renders only a spinner (CircleLoader with CircleLoaderSize.SMALL) which is
inaccessible to screen readers; wrap the spinner in a container with
role="status" and include a short visually-hidden label like "Loading groups"
(using the project's sr-only utility class, e.g., "sr-only" or "tw-sr-only") so
assistive tech announces the loading state when isFetching is true.

In `@components/waves/create-wave/groups/useCreateWaveGroupSearch.ts`:
- Around line 305-317: Escape presses currently trigger closeSearch() twice
because the input's onKeyDown handler (the input's Escape branch at the input
onKeyDown around lines 165-167) calls preventDefault() but not
stopPropagation(), and useKeyPressEvent("Escape") in useCreateWaveGroupSearch.ts
also listens globally; update the input's onKeyDown Escape branch to also call
event.stopPropagation() so the global useKeyPressEvent("Escape") does not
receive the event, or alternatively remove the useKeyPressEvent("Escape")
listener and rely solely on the input's onKeyDown; pick one approach, and ensure
references to the input onKeyDown handler and useKeyPressEvent("Escape") are
updated accordingly.

In `@components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx`:
- Line 39: The assignment for created_by in WaveGroupChangeDialog.tsx uses
group.author (ApiGroup.author) which can be undefined while
ApiGroupFull.created_by expects ApiProfileMin; update the creation logic for
ApiGroupFull (the object assembled in the component) to handle the undefined
case by providing a safe fallback (e.g., map to a minimal ApiProfileMin
placeholder, null-check and omit created_by, or derive from current user
context) before assigning to created_by; locate the code where created_by:
group.author is set and replace it with a guarded assignment that ensures
created_by always matches ApiProfileMin or is handled explicitly by the API
call.
- Around line 30-44: getSelectedGroup currently returns an object cast to
ApiGroupFull but omits the required "group" field (ApiGroupDescription); fix by
populating the "group" property with a default ApiGroupDescription built from
available values (e.g., use group.name and set other optional fields to sensible
defaults such as empty description/avatar/metadata or nulls) so the returned
object conforms to ApiGroupFull, or alternatively change the function
signature/return type to reflect a partial (e.g., Partial<ApiGroupFull> | null)
if you intentionally want to omit that nested field; update getSelectedGroup to
implement one of these two approaches and keep the rest of the mapped fields
as-is.

---

Outside diff comments:
In
`@__tests__/components/waves/create-wave/groups/CreateWaveGroupInlinePanel.test.tsx`:
- Around line 45-69: The mock for CreateWaveGroupSearchField always renders an
active "clear group" button which ignores the allowClear prop; update the
MockCreateWaveGroupSearchField implementation to read props.allowClear and only
render the clear-control when allowClear is true (or render a disabled/absent
button when false) so tests that assert clearing-is-disabled reflect the real
component behavior and the onClick handler is not exposed when allowClear is
false.

---

Nitpick comments:
In
`@__tests__/components/waves/create-wave/groups/CreateWaveGroupSearchField.test.tsx`:
- Around line 41-48: The useDebounce mock in the test calls
React.useEffect(callback, deps) which omits the callback from the dependency
array and can cause stale closure issues; update the mock for useDebounce (the
function named useDebounce in this test) to include the callback in the
dependency array (e.g., React.useEffect(callback, [callback, ...deps]) or
combine callback with deps) so the effect re-runs when the callback changes
while preserving the synchronous test behavior.

In
`@__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx`:
- Around line 396-420: The jest.mock for "@headlessui/react" is placed after the
describe block; move that jest.mock(...) declaration up with the other
top-of-file mocks so it sits alongside the other mock setups (i.e., before any
describe/it blocks) to improve readability and maintenance; keep the mock
implementation exactly as-is (Menu, MenuButton, MenuItems, MenuItem, Transition
and the local close jest.fn()) and ensure no duplicate identifiers collide when
moved.

In `@__tests__/hooks/useWaveConfig.test.ts`:
- Around line 27-42: Add table-driven cases to the existing test for
useWaveConfig to exercise all onGroupSelect branches: call
result.current.onGroupSelect with a sample group and each
CreateWaveGroupConfigType value (CAN_VIEW, CAN_DROP, CAN_VOTE, CAN_CHAT, ADMIN)
and assert that the corresponding config.groups.<field> (e.g.,
config.groups.canView, canDrop, canVote, canChat, admin) equals the group's id
and that groupsCache["group-1"] equals the group; also include the clear-to-null
case by calling onGroupSelect with group: null for one of the types and assert
the corresponding config.groups.<field> becomes null. Use the existing group
object and the onGroupSelect function name to locate where to add the looped
assertions.

In `@components/waves/create-wave/groups/useCreateWaveGroupSearch.ts`:
- Around line 327-338: The handleInputChange function currently clears the
selected group only when both selectedGroup and allowClear are true, which is
subtle; add a concise inline comment above the conditional (referencing
handleInputChange, selectedGroup, allowClear, and onSelect) explaining that
typing will reset the selection only when a selection exists and clearing is
permitted, and note that onSelect(null) is invoked to notify consumers of the
clear action.

In `@components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx`:
- Around line 116-123: The dialog is rendered with a raw <dialog> element but
not using native showModal()/close(), so either use the native API or switch to
a semantic non-native element: update WaveGroupChangeDialog to either call
modalRef.current.showModal() / close() (and manage backdrop/focus via the
existing modalRef and lifecycle hooks) so the <dialog> uses native modal
behavior, or replace the <dialog> tag with a <div role="dialog"> (preserving
aria-modal="true", aria-labelledby={titleId}, aria-describedby={descriptionId},
tabIndex={-1} and the existing className and modalRef) and continue using
FocusTrap and the manual backdrop; reference modalRef, titleId, descriptionId,
and the component WaveGroupChangeDialog when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 28f79a33-1670-4f56-a146-91239df590a1

📥 Commits

Reviewing files that changed from the base of the PR and between f04d0f8 and f4187e0.

📒 Files selected for processing (20)
  • __tests__/components/waves/create-wave/CreateWave.test.tsx
  • __tests__/components/waves/create-wave/groups/CreateWaveGroup.test.tsx
  • __tests__/components/waves/create-wave/groups/CreateWaveGroupInlinePanel.test.tsx
  • __tests__/components/waves/create-wave/groups/CreateWaveGroupSearchField.test.tsx
  • __tests__/components/waves/create-wave/groups/CreateWaveGroups.test.tsx
  • __tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx
  • __tests__/hooks/useWaveConfig.test.ts
  • components/waves/create-wave/CreateWave.tsx
  • components/waves/create-wave/groups/CreateWaveGroup.tsx
  • components/waves/create-wave/groups/CreateWaveGroupInlinePanel.tsx
  • components/waves/create-wave/groups/CreateWaveGroupSearchField.tsx
  • components/waves/create-wave/groups/CreateWaveGroupSearchInput.tsx
  • components/waves/create-wave/groups/CreateWaveGroupSearchResults.tsx
  • components/waves/create-wave/groups/CreateWaveGroups.tsx
  • components/waves/create-wave/groups/CreateWaveInlineGroupSearch.tsx
  • components/waves/create-wave/groups/createWaveInlineGroupBuilder.ts
  • components/waves/create-wave/groups/useCreateWaveGroupSearch.ts
  • components/waves/create-wave/hooks/useWaveConfig.ts
  • components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx
  • components/waves/specs/groups/group/edit/WaveGroupEditButtons.tsx
💤 Files with no reviewable changes (5)
  • tests/components/waves/create-wave/CreateWave.test.tsx
  • components/waves/create-wave/CreateWave.tsx
  • tests/components/waves/create-wave/groups/CreateWaveGroups.test.tsx
  • components/waves/create-wave/hooks/useWaveConfig.ts
  • components/waves/create-wave/groups/createWaveInlineGroupBuilder.ts

Comment thread components/waves/create-wave/groups/CreateWaveGroupSearchInput.tsx
Comment thread components/waves/create-wave/groups/CreateWaveGroupSearchResults.tsx Outdated
Comment thread components/waves/create-wave/groups/useCreateWaveGroupSearch.ts
Comment thread components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx
Comment thread components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (1)
__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx (1)

111-114: Align renderTrigger mock invocation with the real render-prop contract.

Line 113 and Line 149 treat renderTrigger as a component. The real prop shape is a callback (renderTrigger({ open })). Matching that shape improves test fidelity against WaveGroupEditButton/WaveGroupRemoveButton behavior.

Suggested fix
-      if (renderTrigger) {
-        const Trigger = renderTrigger;
-        return <Trigger open={open} />;
-      }
+      if (renderTrigger) {
+        return renderTrigger({ open });
+      }

Apply the same change in both mock trigger helpers.

Also applies to: 147-150

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx`
around lines 111 - 114, The tests treat renderTrigger like a React component but
the real prop is a render-prop function; replace the JSX usage (const Trigger =
renderTrigger; return <Trigger open={open} />) with a direct function call
return renderTrigger({ open }), and make the same change in the other mock
trigger helper used for WaveGroupEditButton/WaveGroupRemoveButton so both mocks
match the renderTrigger({ open }) contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx`:
- Around line 387-391: The test currently asserts mutateAsync synchronously
after waiting for auth, which can be flaky; wrap the mutateAsync assertions in a
waitFor to make them async-safe: after awaiting waitFor(() =>
expect(auth.requestAuth).toHaveBeenCalled()), add a waitFor that checks
expect(mutateAsync).toHaveBeenCalled() and then assert the payload
(mutateAsync.mock.calls[0][0].visibility.scope.group_id === "group-2") inside
that waitFor so the test waits for mutateAsync to resolve before reading its
mock calls.

In `@components/waves/create-wave/groups/CreateWaveGroupSearchResults.tsx`:
- Around line 162-170: The CreateWaveGroupSearchResults component renders a
container with role="listbox" but its loading and empty rows are plain <li>
elements; update those rows (the loading block inside the isFetching branch and
the empty/helper branch) to include role="option" and appropriate ARIA state
(e.g., aria-disabled="true" for non-interactive rows) so every direct child of
the listbox meets ARIA listbox requirements; locate these blocks in
CreateWaveGroupSearchResults and add role="option" (and aria-disabled where
applicable) to the rendered element(s).

---

Nitpick comments:
In
`@__tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx`:
- Around line 111-114: The tests treat renderTrigger like a React component but
the real prop is a render-prop function; replace the JSX usage (const Trigger =
renderTrigger; return <Trigger open={open} />) with a direct function call
return renderTrigger({ open }), and make the same change in the other mock
trigger helper used for WaveGroupEditButton/WaveGroupRemoveButton so both mocks
match the renderTrigger({ open }) contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3e873dea-8a7f-41d5-9098-3073acc9a266

📥 Commits

Reviewing files that changed from the base of the PR and between f4187e0 and b533056.

📒 Files selected for processing (4)
  • __tests__/components/waves/specs/groups/group/edit/WaveGroupEditButtons.test.tsx
  • components/waves/create-wave/groups/CreateWaveGroupSearchInput.tsx
  • components/waves/create-wave/groups/CreateWaveGroupSearchResults.tsx
  • components/waves/specs/groups/group/edit/WaveGroupChangeDialog.tsx
✅ Files skipped from review due to trivial changes (1)
  • components/waves/create-wave/groups/CreateWaveGroupSearchInput.tsx

Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@simo6529 simo6529 merged commit e1bb24f into main Apr 16, 2026
6 checks passed
@simo6529 simo6529 deleted the inline-group-creating-when-editing-wave branch April 16, 2026 13:14
@sonarqubecloud
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot mentioned this pull request Apr 27, 2026
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