Skip to content

refactor(DisplayTab): DisplayTab refactored into focused Settings sections#1126

Open
reachrazamair wants to merge 5 commits into
rcfrom
refactoring
Open

refactor(DisplayTab): DisplayTab refactored into focused Settings sections#1126
reachrazamair wants to merge 5 commits into
rcfrom
refactoring

Conversation

@reachrazamair

@reachrazamair reachrazamair commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Refactors DisplayTab from one 1,686-line component into a directory module with a 173-line shell.
  • Extracts each visible Display settings area into focused section components while preserving the existing ./DisplayTab public import path.
  • Moves local stateful behavior into dedicated hooks for font configuration and Bionify algorithm draft/modal state.
  • Adds DisplayTab-local utilities for Bionify validation, context warning threshold updates, and file preview toolbar labels.
  • Keeps Settings search ids and rendered data-setting-id wrappers aligned with searchableSettings.ts.

Details

  • Preserves the existing SettingsModal contract and visible section order.
  • Reuses existing Settings primitives:
    • ToggleSwitch
    • ToggleButtonGroup
    • SettingsSectionHeading
    • FontConfigurationPanel
    • IgnorePatternsSection
    • FilePanelSettingsSection
  • Adds private DisplayTab helpers for repeated card and toggle row layout without broadening the shared component surface.
  • Keeps the Cue indicator setting gated behind the Cue Encore feature.
  • Leaves SettingsModal, settings store, IPC/preload APIs, other Settings tabs, searchableSettings.ts, and docs/releases.md unchanged.

Tests

  • Added focused DisplayTab tests:
    • hooks.test.tsx
    • sections.test.tsx
    • utils.test.ts
  • Coverage added for:
    • Lazy font detection success/failure
    • Saved custom fonts
    • Add/remove/duplicate custom font handling
    • Bionify algorithm draft validation and commit behavior
    • Bionify info modal state
    • Main header and left panel setting toggles
    • Cue indicator visibility
    • File edit and file preview toolbar controls
    • Tab options
    • Context warning threshold correction
    • Accessibility and Bionify controls

Verification

  • npm run test -- src/__tests__/renderer/components/Settings/tabs/DisplayTab.test.tsx src/__tests__/renderer/components/Settings/tabs/DisplayTab src/__tests__/renderer/components/Settings/searchableSettings.test.ts
    • 5 files / 191 tests passed
  • npm run test -- src/__tests__/renderer/components/Settings/tabs/GeneralTab.test.tsx src/__tests__/renderer/components/Settings/tabs/GeneralTab src/__tests__/renderer/components/Settings/tabs/EncoreTab.test.tsx
    • 4 files / 177 tests passed
  • npm run format:check
  • npm run lint
  • npm run lint:eslint
  • npx tsc --noEmit --pretty
  • npm run test
    • 1,118 files passed, 1 skipped
    • 31,698 tests passed, 108 skipped

Manual QA

  • Open Settings > Display and verify section order is unchanged.
  • Search Display settings and confirm scroll/highlight lands on the expected controls.
  • Verify font loading, custom font add/remove, and font family persistence.
  • Exercise font size, max log buffer, max output lines, message alignment, and file icon theme controls.
  • Toggle window chrome, main header, left panel, file edit/preview, tab options, document graph, context warnings, accessibility, Bionify, and file indexing settings.
  • Verify Cue indicator visibility changes when Cue is disabled/enabled.
  • Smoke light and dark themes for spacing, disabled states, borders, and text overlap.

Summary by CodeRabbit

  • New Features
    • Reworked the Display settings area into clearer grouped sections (fonts, appearance controls, window chrome, panels, file preview, tab options, document graph, context warnings, accessibility, and file indexing).
    • Added Accessibility controls: color-blind mode, Bionify emphasis with algorithm validation, and a Bionify algorithm reference modal.
    • Updated Max Log Buffer choices to use abbreviated labels (e.g., 1.0K, 5.0K).
  • Bug Fixes
    • Improved custom font detection/loading/persistence behavior and Bionify algorithm draft validation/commit flow.
    • Prevented context warning threshold interactions when disabled and enforced valid yellow/red ordering.
    • Fixed quota refresh so it won’t apply updates after unmount.
  • Tests
    • Added/expanded Vitest + React Testing Library coverage for Display settings hooks/components/utilities.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

DisplayTab is rebuilt into reusable sections, hooks, helpers, and tests. The tab shell now composes the new sections and conditionally shows the Bionify info modal. A separate quota refresh hook change now stops after unmount.

Changes

Display settings tab rebuild

Layer / File(s) Summary
Contracts and pure helpers
src/renderer/components/Settings/tabs/DisplayTab/{types.ts,utils/*}, src/__tests__/renderer/components/Settings/tabs/DisplayTab/utils.test.ts
Defines the DisplayTab types, bionify validation, context-warning threshold updates, toolbar labels, and tests for the pure helpers.
Font and bionify hooks
src/renderer/components/Settings/tabs/DisplayTab/hooks/*, src/__tests__/renderer/components/Settings/tabs/DisplayTab/hooks.test.tsx
Implements font loading and persistence state plus bionify draft and modal state, with tests for loading, persistence, validation, normalization, and modal toggling.
Shared primitives and simple sections
src/renderer/components/Settings/tabs/DisplayTab/components/{SectionCard.tsx,ToggleSettingRow.tsx,MainHeaderPanelSection.tsx,WindowChromeSection.tsx,FontSizeSection.tsx,MaxLogBufferSection.tsx,MaxOutputLinesSection.tsx,MessageAlignmentSection.tsx,IconThemeSection.tsx,FontFamilySection.tsx}, src/__tests__/renderer/components/Settings/tabs/DisplayTab/{sections.test.tsx,DisplayTab.test.tsx,SettingsModal.test.tsx}
Adds the shared card and toggle-row wrappers and the simpler Display sections for header, window chrome, font, output, alignment, and icon theme, with matching UI tests.
Advanced sections and interaction tests
src/renderer/components/Settings/tabs/DisplayTab/components/{LeftSidePanelSection.tsx,FileEditPreviewSection.tsx,TabOptionsSection.tsx,DocumentGraphSection.tsx,ContextWarningsSection.tsx,AccessibilitySection.tsx,BionifyInfoModal.tsx,FileIndexingSection.tsx}, src/__tests__/renderer/components/Settings/tabs/DisplayTab/sections.test.tsx
Adds the left-panel, file preview, tab option, document graph, context warning, accessibility, bionify modal, and file indexing sections, plus interaction tests for switches, sliders, and the algorithm input.
DisplayTab shell and exports
src/renderer/components/Settings/tabs/DisplayTab/DisplayTab.tsx, src/renderer/components/Settings/tabs/DisplayTab/{index.ts,components/index.ts}
Rebuilds the DisplayTab wrapper to compose the new hooks and sections, conditionally render BionifyInfoModal, and re-export the tab entry points and barrels.

Quota refresh unmount guard

Layer / File(s) Summary
Unmount guard
src/renderer/components/UsageDashboard/quota/useQuotaRefresh.ts, src/__tests__/renderer/components/UsageDashboard/useQuotaRefresh.test.tsx
Adds mount tracking to the quota refresh hook and verifies the in-flight refresh completes without a late update after unmount.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • RunMaestro/Maestro#502: Shares the DisplayTab settings surface and overlapping tests around font, bionify, and context-warning behavior.

Suggested labels

approved

Poem

A bunny hopped through Display land,
with toggles neat and helpers planned.
Fonts hummed softly, modal lights gleam,
while quotas finished their tiny dream.
Now settings purr with tidier grace.

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 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: refactoring DisplayTab into focused settings sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactoring

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.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR splits the Display settings tab into smaller local modules. The main changes are:

  • A new DisplayTab directory entry point for the existing public import path.
  • Focused section components for each visible Display settings area.
  • Local hooks for font loading and Bionify algorithm state.
  • DisplayTab-local utilities and focused tests for hooks, sections, and helpers.

Confidence Score: 5/5

This looks safe to merge after checking the Display settings refactor.

  • No blocking issues found in the changed code.
  • The known app import paths use named exports and resolve through the new directory entry point.
  • The remaining note is limited to local hot-reload behavior during the file-to-directory swap.

Important Files Changed

Filename Overview
src/renderer/components/Settings/tabs/DisplayTab/DisplayTab.tsx New shell component wires settings values and setters into focused Display settings sections.
src/renderer/components/Settings/tabs/DisplayTab/index.ts New directory entry point preserves named exports for fresh builds, with a possible dev hot-reload edge case from the file-to-directory swap.
src/renderer/components/Settings/tabs/DisplayTab/components/LeftSidePanelSection.tsx Extracts left panel controls while preserving Cue gating, search ids, disabled state, and setter wiring.
src/renderer/components/Settings/tabs/DisplayTab/components/AccessibilitySection.tsx Extracts color blind and Bionify controls with the algorithm draft state passed in from the new hook.
src/renderer/components/Settings/tabs/DisplayTab/hooks/useBionifyAlgorithmState.ts Moves existing Bionify draft validation, commit behavior, and info modal state into a local hook.
src/renderer/components/Settings/tabs/DisplayTab/hooks/useFontConfigurationState.ts Moves lazy font detection and custom font persistence into a local hook with retry behavior after failures.
src/renderer/components/Settings/tabs/DisplayTab/utils/contextWarnings.ts Extracts context warning threshold correction helpers from the previous inline logic.

Reviews (1): Last reviewed commit: "Refactor DisplayTab into focused section..." | Re-trigger Greptile

@@ -0,0 +1,2 @@
export { DisplayTab } from './DisplayTab';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 File To Directory Hot Swap

When a dev session already has ./tabs/DisplayTab loaded from the old DisplayTab.tsx file, replacing that path with a same-named directory can leave Vite's module graph pointing at the deleted file until a full page reload. The Display settings tab can fail to hot-reload during local development even though a fresh build resolves the new index.ts entry.

Context Used: CLAUDE.md (source)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
src/__tests__/renderer/components/Settings/tabs/DisplayTab/sections.test.tsx (1)

252-263: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Brittle DOM/class-based selectors in TabOptions assertions.

These two assertions traverse via .closest('.flex.items-center.justify-between') + querySelector('[role="switch"]'), coupling the test to Tailwind layout classes. The other rows in this file use getByRole('switch', { name }). If TabOptionsSection exposes ariaLabels for these toggles, prefer the role+name query for resilience.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/renderer/components/Settings/tabs/DisplayTab/sections.test.tsx`
around lines 252 - 263, The switch assertions in TabOptionsSection tests are
using brittle Tailwind class traversal to find the toggles; update these two
clicks to use role-based queries like the other rows in this test file. Locate
the assertions around getByText for “Show starred tabs when filtering by unread”
and “Show file preview tabs when filtering by unread” and, if TabOptionsSection
provides accessible names/aria labels for those switches, replace the
closest/querySelector path with getByRole('switch', { name: ... }) so the test
no longer depends on layout classes.
src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx (1)

3-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the shared platform detection helper here.

This new section imports isMacOSPlatform() from utils/platformUtils, but the repo guideline for TS/TSX files requires isMacOS() from src/shared/platformDetection.ts so platform-specific UI copy stays on the shared path.

As per coding guidelines, **/*.{ts,tsx,js,jsx}: Use isWindows(), isMacOS(), or isLinux() from src/shared/platformDetection.ts for platform detection. Do not create duplicate implementations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx`
around lines 3 - 31, The platform check in TabOptionsSection uses a non-shared
helper, which violates the TS/TSX platform detection guideline. Update the
import and usage in TabOptionsSection to use isMacOS() from
src/shared/platformDetection.ts instead of isMacOSPlatform() from
utils/platformUtils, keeping the shortcutPrefix logic the same.

Source: Coding guidelines

src/renderer/components/Settings/tabs/DisplayTab/components/MaxLogBufferSection.tsx (1)

20-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Format the preset labels with formatNumber().

These values are user-visible labels, so rendering them as raw numbers leaves 1000/25000 unformatted here. Please map them to { value, label } options using formatNumber() so this stays consistent with the rest of the app’s number formatting.

As per coding guidelines, "Use formatSize(), formatNumber(), formatTokens(), formatTokensCompact(), estimateTokenCount(), formatElapsedTime(), formatElapsedTimeColon(), formatRelativeTime(), or formatCost() from src/shared/formatters.ts for formatting operations. Do not create duplicate implementations."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/renderer/components/Settings/tabs/DisplayTab/components/MaxLogBufferSection.tsx`
around lines 20 - 25, The preset values passed to ToggleButtonGroup in
MaxLogBufferSection are being rendered as raw user-facing numbers, so update
this to use { value, label } options instead of a plain numeric array. Map each
preset through formatNumber() so the labels match the app’s standard number
formatting, and keep the existing onChange behavior tied to setMaxLogBuffer.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/renderer/components/Settings/tabs/DisplayTab/components/AccessibilitySection.tsx`:
- Around line 98-167: The Bionify settings block is only visually/mouse-disabled
via `pointerEvents` and opacity, but the `ToggleButtonGroup` and
`bionify-algorithm-input` still remain keyboard-focusable. Update
`AccessibilitySection` so the controls are truly disabled when
`bionifyReadingMode` is false, using `disabled`, `tabIndex={-1}`, or `inert` as
appropriate. Apply this consistently to the intensity options and the algorithm
input, and keep the enabled state tied to the existing `bionifyReadingMode`
condition.

In
`@src/renderer/components/Settings/tabs/DisplayTab/components/ContextWarningsSection.tsx`:
- Around line 38-44: The threshold range inputs in ContextWarningsSection remain
keyboard-operable when contextWarningsEnabled is false because the wrapper only
uses opacity and pointerEvents. Update the two slider inputs in
ContextWarningsSection to also respect contextWarningsEnabled via the native
disabled attribute so they are removed from the tab order and cannot be adjusted
while the feature is off.

In
`@src/renderer/components/Settings/tabs/DisplayTab/components/DocumentGraphSection.tsx`:
- Around line 35-49: The range input in DocumentGraphSection lacks a
programmatic accessible name, so update the control rendered in the
DocumentGraphSection component to be labeled by the “Maximum nodes to display”
text. Add a proper label association using label/htmlFor with a matching id on
the input, or use aria-label/aria-labelledby directly on the input, keeping the
existing slider behavior unchanged.

In
`@src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx`:
- Around line 54-64: The switch’s aria-label is hardcoded to Command+0 while the
rendered shortcut text in TabOptionsSection depends on shortcutPrefix, so screen
readers can announce the wrong key combo on non-Mac platforms. Update the
ariaLabel on the same control to use the same shortcutPrefix-derived value used
in the title/description, so the accessible label always matches the displayed
shortcut.

In
`@src/renderer/components/Settings/tabs/DisplayTab/hooks/useBionifyAlgorithmState.ts`:
- Around line 15-17: The `algorithmDraft` state in `useBionifyAlgorithmState` is
only initialized once, so it can get out of sync when `bionifyAlgorithm` updates
after mount. Update the hook to keep `algorithmDraft` synchronized with the
incoming `bionifyAlgorithm` prop/state changes, using the existing
`setAlgorithmDraft` in a side effect keyed on `bionifyAlgorithm`, while
preserving the `DEFAULT_BIONIFY_ALGORITHM` fallback when the value is absent.

---

Nitpick comments:
In
`@src/__tests__/renderer/components/Settings/tabs/DisplayTab/sections.test.tsx`:
- Around line 252-263: The switch assertions in TabOptionsSection tests are
using brittle Tailwind class traversal to find the toggles; update these two
clicks to use role-based queries like the other rows in this test file. Locate
the assertions around getByText for “Show starred tabs when filtering by unread”
and “Show file preview tabs when filtering by unread” and, if TabOptionsSection
provides accessible names/aria labels for those switches, replace the
closest/querySelector path with getByRole('switch', { name: ... }) so the test
no longer depends on layout classes.

In
`@src/renderer/components/Settings/tabs/DisplayTab/components/MaxLogBufferSection.tsx`:
- Around line 20-25: The preset values passed to ToggleButtonGroup in
MaxLogBufferSection are being rendered as raw user-facing numbers, so update
this to use { value, label } options instead of a plain numeric array. Map each
preset through formatNumber() so the labels match the app’s standard number
formatting, and keep the existing onChange behavior tied to setMaxLogBuffer.

In
`@src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx`:
- Around line 3-31: The platform check in TabOptionsSection uses a non-shared
helper, which violates the TS/TSX platform detection guideline. Update the
import and usage in TabOptionsSection to use isMacOS() from
src/shared/platformDetection.ts instead of isMacOSPlatform() from
utils/platformUtils, keeping the shortcutPrefix logic the same.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5098d151-1e7f-43c4-a073-ab84e3c4f191

📥 Commits

Reviewing files that changed from the base of the PR and between 48a4cda and fa08295.

📒 Files selected for processing (33)
  • src/__tests__/renderer/components/Settings/tabs/DisplayTab/hooks.test.tsx
  • src/__tests__/renderer/components/Settings/tabs/DisplayTab/sections.test.tsx
  • src/__tests__/renderer/components/Settings/tabs/DisplayTab/utils.test.ts
  • src/renderer/components/Settings/tabs/DisplayTab.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/DisplayTab.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/AccessibilitySection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/BionifyInfoModal.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/ContextWarningsSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/DocumentGraphSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/FileEditPreviewSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/FileIndexingSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/FontFamilySection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/FontSizeSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/IconThemeSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/LeftSidePanelSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/MainHeaderPanelSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/MaxLogBufferSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/MaxOutputLinesSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/MessageAlignmentSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/SectionCard.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/ToggleSettingRow.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/WindowChromeSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/index.ts
  • src/renderer/components/Settings/tabs/DisplayTab/hooks/index.ts
  • src/renderer/components/Settings/tabs/DisplayTab/hooks/useBionifyAlgorithmState.ts
  • src/renderer/components/Settings/tabs/DisplayTab/hooks/useFontConfigurationState.ts
  • src/renderer/components/Settings/tabs/DisplayTab/index.ts
  • src/renderer/components/Settings/tabs/DisplayTab/types.ts
  • src/renderer/components/Settings/tabs/DisplayTab/utils/bionifyAlgorithm.ts
  • src/renderer/components/Settings/tabs/DisplayTab/utils/contextWarnings.ts
  • src/renderer/components/Settings/tabs/DisplayTab/utils/filePreviewToolbar.ts
  • src/renderer/components/Settings/tabs/DisplayTab/utils/index.ts
💤 Files with no reviewable changes (1)
  • src/renderer/components/Settings/tabs/DisplayTab.tsx

Comment thread src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/__tests__/renderer/components/Settings/tabs/DisplayTab.test.tsx (1)

728-761: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the preset labels with formatNumber().

These hardcoded 1.0K / 5.0K / 10.0K / 25.0K strings duplicate the formatter output from MaxLogBufferSection, so a formatter-only change will break this test without a behavior regression. As per coding guidelines, "Use formatSize(), formatNumber(), formatTokens(), formatTokensCompact(), estimateTokenCount(), formatElapsedTime(), formatElapsedTimeColon(), formatRelativeTime(), or formatCost() from src/shared/formatters.ts for formatting operations. Do not create duplicate implementations."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/renderer/components/Settings/tabs/DisplayTab.test.tsx` around
lines 728 - 761, The DisplayTab tests are hardcoding preset button labels that
duplicate the formatting used by MaxLogBufferSection. Update these assertions to
derive the expected labels with formatNumber() from src/shared/formatters.ts
instead of literal strings, so the test tracks formatter changes without
behavior changes. Use the existing DisplayTab test helpers and the
MaxLogBufferSection preset expectations to locate the affected click assertions.

Source: Coding guidelines

src/__tests__/renderer/components/SettingsModal.test.tsx (1)

937-946: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use formatNumber() for the queried button names here too.

This test now hardcodes presentation strings that are generated in the UI via formatNumber(), so it will drift for formatting-only changes. As per coding guidelines, "Use formatSize(), formatNumber(), formatTokens(), formatTokensCompact(), estimateTokenCount(), formatElapsedTime(), formatElapsedTimeColon(), formatRelativeTime(), or formatCost() from src/shared/formatters.ts for formatting operations. Do not create duplicate implementations."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/renderer/components/SettingsModal.test.tsx` around lines 937 -
946, The SettingsModal test is hardcoding button labels that should come from
the same formatter used by the UI. Update the queries in SettingsModal.test.tsx
to use formatNumber() for the expected button names instead of literal strings,
so the test tracks the formatting logic used by the component and stays stable
across presentation-only changes.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/__tests__/renderer/components/Settings/tabs/DisplayTab.test.tsx`:
- Around line 728-761: The DisplayTab tests are hardcoding preset button labels
that duplicate the formatting used by MaxLogBufferSection. Update these
assertions to derive the expected labels with formatNumber() from
src/shared/formatters.ts instead of literal strings, so the test tracks
formatter changes without behavior changes. Use the existing DisplayTab test
helpers and the MaxLogBufferSection preset expectations to locate the affected
click assertions.

In `@src/__tests__/renderer/components/SettingsModal.test.tsx`:
- Around line 937-946: The SettingsModal test is hardcoding button labels that
should come from the same formatter used by the UI. Update the queries in
SettingsModal.test.tsx to use formatNumber() for the expected button names
instead of literal strings, so the test tracks the formatting logic used by the
component and stays stable across presentation-only changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c5c57173-e520-437d-807e-e64a51bfd3f8

📥 Commits

Reviewing files that changed from the base of the PR and between fa08295 and 0a3f66a.

📒 Files selected for processing (11)
  • src/__tests__/renderer/components/Settings/tabs/DisplayTab.test.tsx
  • src/__tests__/renderer/components/Settings/tabs/DisplayTab/hooks.test.tsx
  • src/__tests__/renderer/components/Settings/tabs/DisplayTab/sections.test.tsx
  • src/__tests__/renderer/components/SettingsModal.test.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/AccessibilitySection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/ContextWarningsSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/DocumentGraphSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/MaxLogBufferSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/hooks/useBionifyAlgorithmState.ts
  • src/renderer/components/ToggleButtonGroup.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/renderer/components/Settings/tabs/DisplayTab/components/DocumentGraphSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/MaxLogBufferSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/ContextWarningsSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/TabOptionsSection.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/hooks/useBionifyAlgorithmState.ts
  • src/tests/renderer/components/Settings/tabs/DisplayTab/hooks.test.tsx
  • src/renderer/components/Settings/tabs/DisplayTab/components/AccessibilitySection.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/components/UsageDashboard/quota/useQuotaRefresh.ts`:
- Around line 57-63: The mountedRef logic in useQuotaRefresh is only cleared on
cleanup, so it can stay false after React 18 StrictMode remounts and block
handleRefresh from running. Set mountedRef.current back to true at the start of
the useEffect body that defines the cleanup, while keeping the cleanup that
flips it to false, so the live instance is initialized correctly and visualBusy
can recover.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 40f8d6b0-9242-44cf-9a5d-982eda571183

📥 Commits

Reviewing files that changed from the base of the PR and between 0a3f66a and 5cbe457.

📒 Files selected for processing (2)
  • src/__tests__/renderer/components/UsageDashboard/useQuotaRefresh.test.tsx
  • src/renderer/components/UsageDashboard/quota/useQuotaRefresh.ts

Comment thread src/renderer/components/UsageDashboard/quota/useQuotaRefresh.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/renderer/components/UsageDashboard/useQuotaRefresh.test.tsx`:
- Around line 42-74: The test in useQuotaRefresh should trigger the refresh
during the StrictMode mount cycle instead of calling handleRefresh after
renderHook returns. Update the useQuotaRefresh test to start the refresh from a
mount effect in the wrapper or keep the in-flight promise/timer across an
explicit unmount/remount so the StrictMode dev remount path is actually
exercised. Keep the assertions around result.current.isBusy and doRefresh, but
make sure the refresh begins before the initial mount cycle completes.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a426fcbe-bfbe-44a5-9692-cfe05d874070

📥 Commits

Reviewing files that changed from the base of the PR and between 5cbe457 and 5ac4a96.

📒 Files selected for processing (2)
  • src/__tests__/renderer/components/UsageDashboard/useQuotaRefresh.test.tsx
  • src/renderer/components/UsageDashboard/quota/useQuotaRefresh.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/components/UsageDashboard/quota/useQuotaRefresh.ts

Comment on lines +42 to +74
it('recovers visual busy state after a StrictMode effect remount', async () => {
vi.useFakeTimers();
const doRefresh = vi.fn().mockResolvedValue(undefined);
const wrapper = ({ children }: { children: ReactNode }) => <StrictMode>{children}</StrictMode>;

const { result } = renderHook(
() =>
useQuotaRefresh({
providerId: 'claude-code',
refreshing: false,
autoRefresh: false,
accountCount: 0,
snapshotCount: 0,
doRefresh,
}),
{ wrapper }
);

let refreshPromise!: Promise<void>;
act(() => {
refreshPromise = result.current.handleRefresh();
});
expect(result.current.isBusy).toBe(true);

await Promise.resolve();
await act(async () => {
await vi.advanceTimersByTimeAsync(900);
await refreshPromise;
});

expect(result.current.isBusy).toBe(false);
expect(doRefresh).toHaveBeenCalledTimes(1);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In React 18 StrictMode, does the development-only mount → unmount → remount check happen during the initial render before test code can invoke callbacks returned from a hook rendered with @testing-library/react's renderHook?

💡 Result:

In React 18, when StrictMode is enabled, the development-only mount → unmount → remount sequence occurs synchronously during the initial render process [1][2][3]. When you use renderHook from @testing-library/react, this double-invocation behavior is triggered before your test code can interact with the results [4][5]. Specifically, React 18's StrictMode performs the following steps during the initial mount in development [1][2][3]: 1. React mounts the component/hook. 2. React simulates an unmount (destroying effects). 3. React simulates a remount (restoring the previous state and running effects again). Because this entire sequence happens as part of the initial render lifecycle triggered by renderHook, by the time the renderHook function returns the result object to your test, the hook has already been mounted, unmounted, and remounted [1][2][3]. This means that any side effects or callbacks initiated by your hook will have been executed twice (setup → cleanup → setup) [6][7]. If your test logic asserts on the number of times an effect has run, it will observe the effect running twice on the initial mount [4]. Consequently, you should write your tests to account for this double-execution, typically by resetting mocks or verifying state after the mount cycle is complete [4].

Citations:


Move the refresh trigger into the StrictMode mount cycle. This test calls handleRefresh() after renderHook() returns, so React’s dev-only mount → unmount → remount pass has already completed. It only covers a normal refresh on the remounted instance, not the regression this PR targets. Start the refresh from a mount effect or keep the promise/timer in flight across an explicit unmount/remount.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/renderer/components/UsageDashboard/useQuotaRefresh.test.tsx`
around lines 42 - 74, The test in useQuotaRefresh should trigger the refresh
during the StrictMode mount cycle instead of calling handleRefresh after
renderHook returns. Update the useQuotaRefresh test to start the refresh from a
mount effect in the wrapper or keep the in-flight promise/timer across an
explicit unmount/remount so the StrictMode dev remount path is actually
exercised. Keep the assertions around result.current.isBusy and doRefresh, but
make sure the refresh begins before the initial mount cycle completes.

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