Skip to content

announcements wave#2217

Merged
simo6529 merged 10 commits intomainfrom
pinned-wave
Apr 8, 2026
Merged

announcements wave#2217
simo6529 merged 10 commits intomainfrom
pinned-wave

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Apr 6, 2026

Summary by CodeRabbit

  • New Features

    • Added an “Announcement waves” section in waves lists.
    • Added Waves selections REST API to manage wave/drop selections.
  • Bug Fixes

    • Improved pin control visibility and settings-load guards.
    • Normalized announcement IDs for reliable matching.
    • Announcement waves are excluded from regular/pinned lists and no longer count toward pin limits.
  • Tests

    • Expanded test coverage for announcement handling, pinning rules, and related UI behaviors.

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

coderabbitai Bot commented Apr 6, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds announcement-wave support: new settings field and helper, announcement resolution in waves hook (with conditional fetch), UI sections for announcement waves with adjusted pin visibility, pin-server eligibility updates, OpenAPI additions for wave selections, and corresponding tests and mocks.

Changes

Cohort / File(s) Summary
Context & Helper
contexts/SeizeSettingsContext.tsx, helpers/waves/wave.helpers.ts
Add announcements_wave_id, isAnnouncementsWave helper, and normalizeOptionalWaveId utility; normalize announcement IDs for matching.
Core Hooks
hooks/useWavesList.ts, hooks/usePinnedWavesServer.ts, __tests__/hooks/usePinnedWavesServer.test.tsx
Resolve announcement wave (conditional useWaveById), exclude announcements from pinned/main sets, expose announcement-related return fields; add canPinWave(waveId) server predicate that ignores announcement waves for budget checks; tests for pin budget and legacy announcement pins.
Sidebar Components
components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx, components/brain/left-sidebar/web/WebUnifiedWavesListWaves.tsx, components/brain/left-sidebar/waves/BrainLeftSidebarWavePin.tsx, __tests__/components/brain/left-sidebar/waves/BrainLeftSidebarWave.test.tsx, __tests__/components/brain/left-sidebar/waves/UnifiedWavesListWaves.test.tsx, __tests__/components/brain/left-sidebar/web/WebUnifiedWavesListWaves.test.tsx
Partition waves into announcement/pinned/regular groups; render "Announcement waves" section with runtime validity checks and conditional divider; adjust showPin semantics for announcement waves; update tests for rendering and pin visibility.
Pin Controls & Header
components/waves/header/WaveHeaderPinButton.tsx, __tests__/components/waves/header/WaveHeaderPinButton.test.tsx, __tests__/components/brain/left-sidebar/waves/BrainLeftSidebarWavePin.test.tsx
Use useSeizeSettings() and server canPinWave for pin visibility and click logic; hide controls for unpinned announcements or while settings load; adjust tests for settings and max-pin behavior.
Hook Tests & Mocks
__tests__/hooks/useWavesList.test.tsx, __tests__/contexts/wave/MyStreamContext.test.tsx, __tests__/utils/mockFactories.ts
Add/adjust tests and mocks for announcement-wave fetching and behavior; rename mock targets to useEnhancedWavesListCore; update factory import and formatting.
Seize Settings Tests
__tests__/contexts/SeizeSettingsContext.test.tsx
Add tests ensuring announcement ID normalization and isAnnouncementsWave helper behavior.
OpenAPI
openapi.yaml
Add wave selection endpoints and DTOs; add selections arrays to wave/drop schemas; add selection_id query param to drops endpoints; add announcements_wave_id to ApiSeizeSettings.
Misc Tests / Formatting
__tests__/**, playwright.config.ts, instrumentation.ts, knip.jsonc
Multiple test additions/formatting changes (single→double quotes), new web-component tests, TypeScript typing refinements, and Knip/Playwright config entry updates.

Sequence Diagram(s)

sequenceDiagram
  participant UI as Sidebar UI
  participant Hook as useWavesList
  participant Settings as SeizeSettingsContext
  participant API as useWaveById

  UI->>Settings: read announcements_wave_id & isAnnouncementsWave(waveId)
  UI->>Hook: request combined waves
  Hook->>Settings: normalize announcements_wave_id
  Hook->>Hook: filter main/pinned lists (exclude announcements)
  alt announcement id present and missing from lists
    Hook->>API: conditional fetch announcement (enabled)
    API-->>Hook: returns announcement wave
  end
  Hook-->>UI: combined waves (announcement inserted + sorted others)
  UI->>UI: render Announcement / Pinned / Regular sections with adjusted showPin
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • ragnep
  • prxt6529
  • GelatoGenesis

Poem

🐰 I trim the ids and hop with glee,

Announcements first in line to see.
Pins follow rules the server keeps,
The sidebar hums while everyone sleeps. 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'announcements wave' is vague and generic, using non-descriptive terminology that fails to convey the specific changes made in the pull request. Consider revising the title to be more specific and descriptive, such as 'Add announcement wave support to wave management' or 'Implement announcement wave filtering and pin controls' to better communicate the primary changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 pinned-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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 101e3a8fa6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread components/waves/header/WaveHeaderPinButton.tsx
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: 1

🧹 Nitpick comments (4)
contexts/SeizeSettingsContext.tsx (1)

21-23: Add announcements_wave_id to TempApiSeizeSettings type.

The announcements_wave_id field is initialized in state (line 58) and used throughout, but it's not declared in the TempApiSeizeSettings type definition (lines 21-23). TypeScript may allow this due to the spread from ApiSeizeSettings, but for type safety and documentation, explicitly add it.

♻️ Proposed fix
 type TempApiSeizeSettings = ApiSeizeSettings & {
   curation_wave_id: string | null;
+  announcements_wave_id: string | null;
 };

Also applies to: 58-58

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

In `@contexts/SeizeSettingsContext.tsx` around lines 21 - 23, The
TempApiSeizeSettings type is missing announcements_wave_id despite that field
being initialized and used; update the TempApiSeizeSettings type declaration
(which currently adds curation_wave_id) to also include announcements_wave_id:
string | null so the state shape matches the type and TypeScript enforces it
alongside the existing curation_wave_id declaration.
components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx (1)

215-215: Redundant check, but harmless and self-documenting.

Since pinnedWaves is already filtered to exclude announcement waves (line 117-119), wave.isAnnouncement will always be false here. The explicit !wave.isAnnouncement check is technically redundant but clearly communicates intent.

🔧 Optional simplification

If you prefer brevity over explicitness:

-                    showPin={!hidePin && !wave.isAnnouncement}
+                    showPin={!hidePin}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx` at line 215,
The prop expression showPin={!hidePin && !wave.isAnnouncement} is redundant
because pinnedWaves is already filtered to exclude announcement waves; remove
the needless !wave.isAnnouncement check and set showPin based only on hidePin
(i.e., showPin={!hidePin}) to simplify code while preserving behavior—update the
component rendering that uses showPin and ensure no other logic depends on
wave.isAnnouncement at that spot (reference: showPin, hidePin,
wave.isAnnouncement, pinnedWaves).
components/brain/left-sidebar/web/WebUnifiedWavesListWaves.tsx (2)

227-229: Redundant check (harmless).

Since waves in pinnedWaves are already guaranteed to be non-announcements (filtered at line 90), the !wave.isAnnouncement check is always true here. The check is defensive and doesn't cause issues, so this is a minor observation.

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

In `@components/brain/left-sidebar/web/WebUnifiedWavesListWaves.tsx` around lines
227 - 229, The showPin expression in WebUnifiedWavesListWaves currently includes
a redundant !wave.isAnnouncement check because pinnedWaves are already filtered
to exclude announcements; simplify the prop to showPin={!hidePin &&
!isCollapsed} by removing the unnecessary !wave.isAnnouncement clause (affecting
the showPin prop where pinnedWaves, hidePin, isCollapsed, and
wave.isAnnouncement are used).

284-284: Same redundant check as noted above.

Waves in regularWaves are non-announcements by construction. The !wave.isAnnouncement check is always true here. Consistent with line 228 but similarly redundant.

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

In `@components/brain/left-sidebar/web/WebUnifiedWavesListWaves.tsx` at line 284,
Redundant boolean check: when rendering items from regularWaves (which are
guaranteed non-announcements), remove the unnecessary "!wave.isAnnouncement"
check and set showPin based only on hidePin (e.g., change showPin={!hidePin &&
!wave.isAnnouncement} to showPin={!hidePin}) in the component where regularWaves
are mapped (reference: showPin prop in WebUnifiedWavesListWaves render).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contexts/wave/hooks/useEnhancedWavesListCore.ts`:
- Around line 27-30: The EnhancedApiWave.isAnnouncement flag is populated
explicitly by useWavesList() but left unset in useDmWavesList(), relying on a
fallback; update useDmWavesList() to explicitly set isAnnouncement: false on
each wave it returns to match the pattern in useWavesList() and keep the data
shape consistent across sources (reference EnhancedApiWave, useWavesList,
useDmWavesList).

---

Nitpick comments:
In `@components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx`:
- Line 215: The prop expression showPin={!hidePin && !wave.isAnnouncement} is
redundant because pinnedWaves is already filtered to exclude announcement waves;
remove the needless !wave.isAnnouncement check and set showPin based only on
hidePin (i.e., showPin={!hidePin}) to simplify code while preserving
behavior—update the component rendering that uses showPin and ensure no other
logic depends on wave.isAnnouncement at that spot (reference: showPin, hidePin,
wave.isAnnouncement, pinnedWaves).

In `@components/brain/left-sidebar/web/WebUnifiedWavesListWaves.tsx`:
- Around line 227-229: The showPin expression in WebUnifiedWavesListWaves
currently includes a redundant !wave.isAnnouncement check because pinnedWaves
are already filtered to exclude announcements; simplify the prop to
showPin={!hidePin && !isCollapsed} by removing the unnecessary
!wave.isAnnouncement clause (affecting the showPin prop where pinnedWaves,
hidePin, isCollapsed, and wave.isAnnouncement are used).
- Line 284: Redundant boolean check: when rendering items from regularWaves
(which are guaranteed non-announcements), remove the unnecessary
"!wave.isAnnouncement" check and set showPin based only on hidePin (e.g., change
showPin={!hidePin && !wave.isAnnouncement} to showPin={!hidePin}) in the
component where regularWaves are mapped (reference: showPin prop in
WebUnifiedWavesListWaves render).

In `@contexts/SeizeSettingsContext.tsx`:
- Around line 21-23: The TempApiSeizeSettings type is missing
announcements_wave_id despite that field being initialized and used; update the
TempApiSeizeSettings type declaration (which currently adds curation_wave_id) to
also include announcements_wave_id: string | null so the state shape matches the
type and TypeScript enforces it alongside the existing curation_wave_id
declaration.
🪄 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: 3e649c59-a63d-4e24-95b4-e4ef2c083306

📥 Commits

Reviewing files that changed from the base of the PR and between 97d225e and 101e3a8.

⛔ Files ignored due to path filters (10)
  • generated/models/ApiDrop.ts is excluded by !**/generated/**
  • generated/models/ApiDropWithoutWave.ts is excluded by !**/generated/**
  • generated/models/ApiSeizeSettings.ts is excluded by !**/generated/**
  • generated/models/ApiWave.ts is excluded by !**/generated/**
  • generated/models/ApiWaveMin.ts is excluded by !**/generated/**
  • generated/models/ApiWaveSelection.ts is excluded by !**/generated/**
  • generated/models/ApiWaveSelectionDropRequest.ts is excluded by !**/generated/**
  • generated/models/ApiWaveSelectionRequest.ts is excluded by !**/generated/**
  • generated/models/ObjectSerializer.ts is excluded by !**/generated/**
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (21)
  • __tests__/components/brain/left-sidebar/waves/BrainLeftSidebarWave.test.tsx
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesListWaves.test.tsx
  • __tests__/components/brain/left-sidebar/web/WebUnifiedWavesListWaves.test.tsx
  • __tests__/components/waves/header/WaveHeaderPinButton.test.tsx
  • __tests__/contexts/SeizeSettingsContext.test.tsx
  • __tests__/contexts/wave/MyStreamContext.test.tsx
  • __tests__/hooks/useWavesList.test.tsx
  • __tests__/utils/mockFactories.ts
  • components/brain/left-sidebar/waves/BrainLeftSidebarWave.tsx
  • components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx
  • components/brain/left-sidebar/web/WebUnifiedWavesListWaves.tsx
  • components/user/layout/userPageVisibility.ts
  • components/waves/header/WaveHeaderPinButton.tsx
  • components/waves/memes/submission/utils/buildPreviewDrop.ts
  • components/waves/utils/getOptimisticDrop.ts
  • contexts/SeizeSettingsContext.tsx
  • contexts/wave/hooks/useEnhancedWavesListCore.ts
  • helpers/waves/wave.helpers.ts
  • hooks/useWaveDropsSearch.ts
  • hooks/useWavesList.ts
  • openapi.yaml

Comment thread contexts/wave/hooks/useEnhancedWavesListCore.ts
simo6529 added 2 commits April 6, 2026 15:55
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: 1

🧹 Nitpick comments (3)
hooks/useWavesList.ts (1)

146-147: Make the new pin-state split explicit.

A legacy pinned announcement can now appear in waves with isPinned: true while being deliberately omitted from pinnedWaves. That asymmetry is easy for callers to read as a full mirror of pinnedIds. Consider renaming or documenting this return contract before more consumers depend on it.

Also applies to: 179-183

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

In `@hooks/useWavesList.ts` around lines 146 - 147, The function currently injects
a pin flag that can diverge from pinnedWaves/pinnedIds (via
waveIsDm/isAnnouncementsWave), so make that split explicit: replace the
ambiguous isPinned set in result.push with a clearly named property (e.g.,
isPinnedInResult or isLegacyAnnouncementPinned) and update the function's return
contract and any callers to consume the new field; alternatively add a short
JSDoc on the hook (useWavesList) explaining that this flag is not necessarily
derived from pinnedIds/pinnedWaves. Target symbols to change/inspect: the
result.push call that currently spreads wave and sets isPinned, the
pinnedWaves/pinnedIds usage, and callers of the hook that read wave.isPinned.
__tests__/hooks/useWavesList.test.tsx (1)

143-148: Avoid asserting a private data shape here.

This hasOwnProperty("isAnnouncement") check is testing an implementation detail rather than behavior. It makes it harder to move announcement classification into the returned wave data if we later want to remove the sidebars’ dependency on useSeizeSettingsOptional(). The ordering and pin assertions already cover the observable behavior.

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

In `@__tests__/hooks/useWavesList.test.tsx` around lines 143 - 148, Remove the
implementation-detail assertion that checks for the presence of "isAnnouncement"
on a wave (the Object.prototype.hasOwnProperty.call(...) assertion around
result.current.waves.find(wave => wave.id === "4")). Instead, delete that
assertion entirely and rely on the existing observable-behavior checks (ordering
and pin assertions) in the test; do not replace it with another shape-specific
check so the test doesn't depend on internal data shapes like isAnnouncement.
components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx (1)

114-136: Verify this component never depends on a missing settings provider.

Announcement bucketing now depends on useSeizeSettingsOptional(). If that hook can return undefined—or even lag the provider update by a render—the announcement wave falls back into the regular/pinned buckets, which also re-enables the normal pin control for an unpinned announcement. Please verify every call site guarantees the provider, or pass explicit announcement metadata on the waves items instead. The same pattern is duplicated in WebUnifiedWavesListWaves.tsx.

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

In `@components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx` around lines
114 - 136, The current bucketing uses useSeizeSettingsOptional() so when the
provider is missing or lags the optional hook returns undefined and
announcements silently fall into pinned/regular (see UnifiedWavesListWaves.tsx:
announcementWaves/pinnedWaves/regularWaves and the same pattern in
WebUnifiedWavesListWaves.tsx). Fix by either (A) requiring the provider: replace
useSeizeSettingsOptional() with the non-optional useSeizeSettings() (or
assert/throw if undefined) so isAnnouncementsWave is always callable, or (B)
make the buckets resilient by using explicit announcement metadata on each wave
(e.g., wave.isAnnouncement or wave.announcementFlag) and fall back to that when
seizeSettings is undefined; apply the same change to
WebUnifiedWavesListWaves.tsx so both components use the same
provider-or-metadata strategy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/useWavesList.ts`:
- Around line 86-96: The hook currently chooses announcementWave from
trackedAnnouncementWave or fetchedAnnouncementWave but doesn't surface the
fetchedAnnouncementWave's query state; update the hook to expose the fallback
query's loading and error (and refetch) so consumers can distinguish "no
announcement" from a loading/error state. Concretely, keep using
useWaveById(announcementsWaveId, { enabled: shouldFetchAnnouncementWave })
(fetchedAnnouncementWave, refetchAnnouncementWave) and add properties such as
announcementQueryLoading: fetchedAnnouncementWave.isLoading,
announcementQueryError: fetchedAnnouncementWave.error, and announcementRefetch:
refetchAnnouncementWave (or similar names used by your hook return object)
alongside the existing announcementWave, trackedAnnouncementWave and other flags
so callers can read loading/error for the fallback query.

---

Nitpick comments:
In `@__tests__/hooks/useWavesList.test.tsx`:
- Around line 143-148: Remove the implementation-detail assertion that checks
for the presence of "isAnnouncement" on a wave (the
Object.prototype.hasOwnProperty.call(...) assertion around
result.current.waves.find(wave => wave.id === "4")). Instead, delete that
assertion entirely and rely on the existing observable-behavior checks (ordering
and pin assertions) in the test; do not replace it with another shape-specific
check so the test doesn't depend on internal data shapes like isAnnouncement.

In `@components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx`:
- Around line 114-136: The current bucketing uses useSeizeSettingsOptional() so
when the provider is missing or lags the optional hook returns undefined and
announcements silently fall into pinned/regular (see UnifiedWavesListWaves.tsx:
announcementWaves/pinnedWaves/regularWaves and the same pattern in
WebUnifiedWavesListWaves.tsx). Fix by either (A) requiring the provider: replace
useSeizeSettingsOptional() with the non-optional useSeizeSettings() (or
assert/throw if undefined) so isAnnouncementsWave is always callable, or (B)
make the buckets resilient by using explicit announcement metadata on each wave
(e.g., wave.isAnnouncement or wave.announcementFlag) and fall back to that when
seizeSettings is undefined; apply the same change to
WebUnifiedWavesListWaves.tsx so both components use the same
provider-or-metadata strategy.

In `@hooks/useWavesList.ts`:
- Around line 146-147: The function currently injects a pin flag that can
diverge from pinnedWaves/pinnedIds (via waveIsDm/isAnnouncementsWave), so make
that split explicit: replace the ambiguous isPinned set in result.push with a
clearly named property (e.g., isPinnedInResult or isLegacyAnnouncementPinned)
and update the function's return contract and any callers to consume the new
field; alternatively add a short JSDoc on the hook (useWavesList) explaining
that this flag is not necessarily derived from pinnedIds/pinnedWaves. Target
symbols to change/inspect: the result.push call that currently spreads wave and
sets isPinned, the pinnedWaves/pinnedIds usage, and callers of the hook that
read wave.isPinned.
🪄 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: 58f6eb9d-1023-4d3f-bdc7-c1a3b54a4cad

📥 Commits

Reviewing files that changed from the base of the PR and between 101e3a8 and 4a0d65f.

📒 Files selected for processing (8)
  • __tests__/components/brain/left-sidebar/waves/BrainLeftSidebarWave.test.tsx
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesListWaves.test.tsx
  • __tests__/components/brain/left-sidebar/web/WebUnifiedWavesListWaves.test.tsx
  • __tests__/hooks/useWavesList.test.tsx
  • __tests__/utils/mockFactories.ts
  • components/brain/left-sidebar/waves/UnifiedWavesListWaves.tsx
  • components/brain/left-sidebar/web/WebUnifiedWavesListWaves.tsx
  • hooks/useWavesList.ts
✅ Files skipped from review due to trivial changes (1)
  • tests/utils/mockFactories.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/components/brain/left-sidebar/waves/BrainLeftSidebarWave.test.tsx
  • tests/components/brain/left-sidebar/waves/UnifiedWavesListWaves.test.tsx

Comment thread hooks/useWavesList.ts Outdated
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.

🧹 Nitpick comments (3)
__tests__/hooks/useWavesList.test.tsx (2)

65-107: Consider adding a test for DM announcement wave filtering.

The waveIsDm check in announcementWave resolution (line 96 of the hook) filters out DM waves even if configured as the announcement. There's no test covering this edge case.

🧪 Suggested test case
test("filters out DM waves from being treated as announcements", () => {
  const dmAnnouncementWave = {
    id: "5",
    created_at: 4,
    metrics: { latest_drop_timestamp: 400 },
    wave: { type: ApiWaveType.Chat },
    chat: { scope: { group: { is_direct_message: true } } },
  } as any;

  useSeizeSettingsMock.mockReturnValue({
    seizeSettings: {
      announcements_wave_id: "5",
    },
    isAnnouncementsWave: (waveId: string | null | undefined) => waveId === "5",
  });
  useWaveByIdMock.mockReturnValue({
    wave: dmAnnouncementWave,
    isLoading: false,
    isError: false,
    error: null,
    refetch: jest.fn(),
    isFetching: false,
  });

  const { result } = renderHook(() => useWavesList(), { wrapper });

  expect(result.current.announcementWave).toBeNull();
  expect(result.current.waves.find((w: any) => w.id === "5")).toBeUndefined();
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/hooks/useWavesList.test.tsx` around lines 65 - 107, The test suite
lacks coverage for the case where the configured announcement wave is a DM and
should be filtered out by the waveIsDm logic inside useWavesList; add a unit
test that mocks useSeizeSettingsMock to set announcements_wave_id to the DM wave
id, mocks useWaveByIdMock to return a wave with wave.type = ApiWaveType.Chat and
chat.scope.group.is_direct_message = true, then render useWavesList and assert
that announcementWave is null and that the DM wave is not present in the
returned waves array (reference identifiers: useWavesList, announcementWave,
waveIsDm, useSeizeSettingsMock, useWaveByIdMock).

198-228: Validates whitespace normalization in announcement ID.

The test uses announcements_wave_id: " 4 " (with surrounding spaces) but isAnnouncementsWave checks for "4". This implicitly tests that normalizeOptionalWaveId trims the ID before comparison.

However, the mock isAnnouncementsWave returns waveId === "4", which doesn't account for normalization. The test passes because the actual wave IDs in the fixtures are already trimmed ("4"), so the comparison works. Consider making the mock more realistic by having it call the actual normalization logic or documenting that the mock is simplified.

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

In `@__tests__/hooks/useWavesList.test.tsx` around lines 198 - 228, The test is
intended to validate whitespace normalization of announcements_wave_id but the
mock isAnnouncementsWave simply compares waveId === "4" and thus doesn't reflect
trimming; update the useSeizeSettingsMock so its isAnnouncementsWave uses the
same normalization as production (call normalizeOptionalWaveId or trim the
incoming waveId) or change announcements_wave_id to a trimmed value and/or
document the simplification; reference the mock provider (useSeizeSettingsMock),
the predicate isAnnouncementsWave, the input field announcements_wave_id, and
the hook under test useWavesList so the mock behavior matches
normalizeOptionalWaveId's contract.
hooks/useWavesList.ts (1)

167-176: Redundant isAnnouncementsWave check in combinedWaves.

The input arrays (mainWaves and separatelyFetchedPinnedWaves) are already filtered to exclude announcement waves in their respective useMemo hooks (lines 105-109 and 139-141). The check at line 168 is therefore always false for waves in these arrays.

While harmless, this adds unnecessary computation. Consider removing the redundant check for clarity.

♻️ Suggested simplification
     [...mainWaves, ...separatelyFetchedPinnedWaves].forEach((wave) => {
-      if (waveIsDm(wave) || isAnnouncementsWave(wave.id)) {
+      if (waveIsDm(wave)) {
         return;
       }
-
       allWavesMap.set(wave.id, {
         ...wave,
         isPinned: pinnedWavesSet.has(wave.id),
       });
     });

Then remove isAnnouncementsWave from the dependency array at line 198.

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

In `@hooks/useWavesList.ts` around lines 167 - 176, The loop merging mainWaves and
separatelyFetchedPinnedWaves into allWavesMap contains a redundant
isAnnouncementsWave(wave.id) check because both source arrays are already
filtered to exclude announcement waves; remove the isAnnouncementsWave condition
from that forEach (keep waveIsDm check) and ensure you also remove
isAnnouncementsWave from the dependency array of the useMemo that builds this
combinedWaves so dependencies reflect only the actually used values (e.g.,
mainWaves, separatelyFetchedPinnedWaves, pinnedWavesSet, waveIsDm if
applicable).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@__tests__/hooks/useWavesList.test.tsx`:
- Around line 65-107: The test suite lacks coverage for the case where the
configured announcement wave is a DM and should be filtered out by the waveIsDm
logic inside useWavesList; add a unit test that mocks useSeizeSettingsMock to
set announcements_wave_id to the DM wave id, mocks useWaveByIdMock to return a
wave with wave.type = ApiWaveType.Chat and chat.scope.group.is_direct_message =
true, then render useWavesList and assert that announcementWave is null and that
the DM wave is not present in the returned waves array (reference identifiers:
useWavesList, announcementWave, waveIsDm, useSeizeSettingsMock,
useWaveByIdMock).
- Around line 198-228: The test is intended to validate whitespace normalization
of announcements_wave_id but the mock isAnnouncementsWave simply compares waveId
=== "4" and thus doesn't reflect trimming; update the useSeizeSettingsMock so
its isAnnouncementsWave uses the same normalization as production (call
normalizeOptionalWaveId or trim the incoming waveId) or change
announcements_wave_id to a trimmed value and/or document the simplification;
reference the mock provider (useSeizeSettingsMock), the predicate
isAnnouncementsWave, the input field announcements_wave_id, and the hook under
test useWavesList so the mock behavior matches normalizeOptionalWaveId's
contract.

In `@hooks/useWavesList.ts`:
- Around line 167-176: The loop merging mainWaves and
separatelyFetchedPinnedWaves into allWavesMap contains a redundant
isAnnouncementsWave(wave.id) check because both source arrays are already
filtered to exclude announcement waves; remove the isAnnouncementsWave condition
from that forEach (keep waveIsDm check) and ensure you also remove
isAnnouncementsWave from the dependency array of the useMemo that builds this
combinedWaves so dependencies reflect only the actually used values (e.g.,
mainWaves, separatelyFetchedPinnedWaves, pinnedWavesSet, waveIsDm if
applicable).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c5f1d4f8-93d1-4e28-824d-7c0a02bffb50

📥 Commits

Reviewing files that changed from the base of the PR and between 4a0d65f and ad03547.

📒 Files selected for processing (2)
  • __tests__/hooks/useWavesList.test.tsx
  • hooks/useWavesList.ts

simo6529 added 3 commits April 7, 2026 08:06
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: 1

🧹 Nitpick comments (1)
__tests__/hooks/usePinnedWavesServer.test.tsx (1)

82-85: Add the unresolved-settings regression case here.

All of the new tests stub useSeizeSettingsOptional() as already resolved, so they won't catch the bootstrap path where the hook still sees null announcement settings and miscounts the budget. A case with useSeizeSettingsOptionalMock.mockReturnValue(null) would fail against the current hook logic and protect the fix.

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

In `@__tests__/hooks/usePinnedWavesServer.test.tsx` around lines 82 - 85, Add a
test in usePinnedWavesServer.test.tsx that covers the unresolved-settings
regression by setting useSeizeSettingsOptionalMock.mockReturnValue(null)
(instead of the resolved object used in other tests) and asserting the hook's
bootstrap path behaves correctly (e.g., budget/count is correct and no miscount
occurs); target the existing test harness that uses useSeizeSettingsOptionalMock
and the isAnnouncementsWave behavior to reproduce the failing path so the fix is
protected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/usePinnedWavesServer.ts`:
- Around line 99-133: The budget calculation counts announcement pins before
seize settings (and announcements_wave_id) are loaded; update the hook so budget
logic waits for settings readiness: add or derive a readiness flag from
useSeizeSettingsOptional (e.g. isSeizeSettingsReady or check
announcements_wave_id presence on seizeSettings) and use it in
countsTowardPinBudget/pinnedBudgetCount/getOngoingPinCount/canPinWave so that
until settings are ready you do not treat legacy announcement ids as counting
against the MAX_PINNED_WAVES (or alternatively return a readiness boolean from
the hook so callers can defer pin decisions until settings are loaded).

---

Nitpick comments:
In `@__tests__/hooks/usePinnedWavesServer.test.tsx`:
- Around line 82-85: Add a test in usePinnedWavesServer.test.tsx that covers the
unresolved-settings regression by setting
useSeizeSettingsOptionalMock.mockReturnValue(null) (instead of the resolved
object used in other tests) and asserting the hook's bootstrap path behaves
correctly (e.g., budget/count is correct and no miscount occurs); target the
existing test harness that uses useSeizeSettingsOptionalMock and the
isAnnouncementsWave behavior to reproduce the failing path so the fix is
protected.
🪄 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: 7c455d17-0495-4b22-8455-70c6d9b1d803

📥 Commits

Reviewing files that changed from the base of the PR and between ad03547 and fb131f0.

📒 Files selected for processing (8)
  • __tests__/components/brain/left-sidebar/waves/BrainLeftSidebarWavePin.test.tsx
  • __tests__/components/waves/header/WaveHeaderPinButton.test.tsx
  • __tests__/hooks/usePinnedWavesServer.test.tsx
  • __tests__/hooks/useWavesList.test.tsx
  • components/brain/left-sidebar/waves/BrainLeftSidebarWavePin.tsx
  • components/waves/header/WaveHeaderPinButton.tsx
  • hooks/usePinnedWavesServer.ts
  • hooks/useWavesList.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/hooks/useWavesList.test.tsx
  • tests/components/waves/header/WaveHeaderPinButton.test.tsx
  • hooks/useWavesList.ts

Comment thread hooks/usePinnedWavesServer.ts
simo6529 added 3 commits April 8, 2026 11:41
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 8, 2026

@simo6529 simo6529 merged commit 2783d43 into main Apr 8, 2026
8 checks passed
@simo6529 simo6529 deleted the pinned-wave branch April 8, 2026 09:41
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