Skip to content

fix(electron): apply persisted hide-app-icon setting at startup#28

Merged
ryota-murakami merged 4 commits intomainfrom
fix/electron-hide-app-icon-startup-sync
Apr 29, 2026
Merged

fix(electron): apply persisted hide-app-icon setting at startup#28
ryota-murakami merged 4 commits intomainfrom
fix/electron-hide-app-icon-startup-sync

Conversation

@ryota-murakami
Copy link
Copy Markdown
Collaborator

@ryota-murakami ryota-murakami commented Apr 29, 2026

Summary

  • Bug: At Electron app startup, Settings "Hide App Icon" toggle showed ON but the Dock icon was still visible. Toggling the switch off→on then made the icon disappear correctly.
  • Root cause: macOS app.setActivationPolicy() is runtime-only and resets to regular on every launch. The Redux hideAppIcon value persisted in localStorage via redux-storage-middleware, but was never re-applied to the main process at startup, so the renderer UI and the actual dock state diverged.
  • Fix: Added <ElectronStartupSync /> component (src/components/electron/ElectronStartupSync.tsx) mounted inside <ReduxProvider> in app/layout.tsx. It forwards the persisted hideAppIcon value to the main process via the existing window.electronAPI.settings.setHideAppIcon IPC after Redux hydrates from localStorage. Re-fires on Redux value change so the Settings UI keeps the dock policy in sync at runtime.

Implementation notes

  • Uses isElectronEnvironment() directly inside the effect rather than the useIsElectron hook — avoids importing the heavy auth-form module (and its Clerk hooks) into the root layout chunk for web users, while staying SSR-safe because effects only run in the browser.
  • Effect dependency is [hideAppIcon] so the dock policy follows the Redux value at runtime, not just at mount.
  • IPC failures are surfaced via console.error with prefix [ElectronStartupSync] Failed to sync hideAppIcon: — swallowing them silently would mask main-process regressions during startup sync.
  • The IPC handler in electron/main.ts:1365 is idempotent (re-applying the same activation policy is a no-op), so firing on every selector change is safe.

Test plan

  • pnpm test — 58/58 unit tests pass (6 new in ElectronStartupSync.test.tsx)
    • Forwards persisted hideAppIcon=true to main process on mount
    • Forwards persisted hideAppIcon=false to main process on mount
    • Skips IPC call when not running in Electron
    • Does not throw when window.electronAPI is undefined
    • Logs an error when setHideAppIcon rejects (locks down the .catch handler)
    • Re-syncs when hideAppIcon changes after mount (locks down the [hideAppIcon] dependency)
  • pnpm typecheck — clean
  • pnpm lint — clean (no warnings)
  • Manual verification on Electron build: launch with hideAppIcon=true persisted in localStorage → dock icon should be hidden immediately, no toggle required

Summary by CodeRabbit

  • New Features

    • Added automatic synchronization of the app icon visibility setting between the web application and the Electron desktop environment, ensuring consistent configuration across application usage.
  • Tests

    • Comprehensive test coverage added for the synchronization feature, including edge case handling and error scenarios.

The hideAppIcon preference is persisted in renderer-side localStorage via
redux-storage-middleware, but app.setActivationPolicy() is runtime-only and
resets to 'regular' on every launch. The Settings UI showed the toggle as ON
while the dock icon remained visible until the user toggled it again.

Adds ElectronStartupSync mounted in the root layout to forward the persisted
value to the main process via IPC after Redux hydration. The IPC handler is
idempotent so firing on every selector change is safe.
Apply review feedback from /simplify:
- Replace useIsElectron hook with isElectronEnvironment() called inside
  the effect. Avoids hauling ElectronLoginForm + Clerk hooks into the
  root layout chunk for web users; SSR-safe because effects are
  browser-only anyway.
- Catch IPC promise rejection so a main-process regression surfaces in
  the console instead of being silently swallowed.
- Drop the redundant typeof window guard inside useEffect.
- Collapse duplicated true/false test cases into it.each, and add
  coverage for the not-in-Electron and missing-electronAPI guards.
Adds two regression tests surfaced during /review:

1. setHideAppIcon rejection — asserts the .catch handler logs the
   prefixed error to console.error. Without this test, removing the
   handler would not cause a CI failure.
2. hideAppIcon re-sync — asserts the effect re-fires when the Redux
   value changes after mount. Locks down the [hideAppIcon] dependency
   so a future refactor to [] (mount-only) is caught immediately.

Skipped lower-value findings: partial electronAPI shape edge cases
(existing undefined test covers optional chaining), afterEach cleanup
(Vitest isolates JSDOM per file), JSDoc rewording (current text is
accurate).
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
corelive Ready Ready Preview, Comment Apr 29, 2026 4:03pm

Request Review

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.03%. Comparing base (ddbfecb) to head (ce704bf).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #28      +/-   ##
==========================================
+ Coverage   62.95%   64.03%   +1.08%     
==========================================
  Files          13       17       +4     
  Lines         332      367      +35     
  Branches       81       83       +2     
==========================================
+ Hits          209      235      +26     
- Misses        114      123       +9     
  Partials        9        9              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

Warning

Rate limit exceeded

@ryota-murakami has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 33 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ 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: c60bf709-0104-41c4-84f0-529eb5237b2d

📥 Commits

Reviewing files that changed from the base of the PR and between 5b02920 and ce704bf.

📒 Files selected for processing (2)
  • src/components/electron/ElectronStartupSync.test.tsx
  • src/components/electron/ElectronStartupSync.tsx
📝 Walkthrough

Walkthrough

Introduces a new ElectronStartupSync component that synchronizes the hideAppIcon setting from Redux to the Electron main process via IPC. The component is imported and rendered in the app layout, running on mount and whenever the setting changes.

Changes

Cohort / File(s) Summary
Electron Synchronization Component
src/components/electron/ElectronStartupSync.tsx, src/components/electron/ElectronStartupSync.test.tsx
New React component that listens to hideAppIcon from Redux state and syncs it to Electron main process using IPC when environment is available. Includes comprehensive test suite validating on-mount sync, web/non-Electron behavior, error handling with prefixed console logging, and re-synchronization on state updates.
App Layout Integration
src/app/layout.tsx
Imports and renders ElectronStartupSync within RootLayout inside ReduxProvider, positioned before ElectronAuthProvider to ensure early initialization.

Sequence Diagram(s)

sequenceDiagram
    participant App as App Shell
    participant Component as ElectronStartupSync
    participant Redux as Redux Store
    participant IPC as Electron IPC
    participant Main as Main Process

    App->>Component: Render & Mount
    Component->>Redux: Select hideAppIcon value
    Redux-->>Component: Return setting value
    Component->>Component: Check isElectronEnvironment()
    alt Electron Environment Detected
        Component->>IPC: window.electronAPI.settings.setHideAppIcon(value)
        IPC->>Main: IPC Message
        Main-->>IPC: Acknowledge
        IPC-->>Component: Promise resolved
    else Not Electron / API unavailable
        Component->>Component: Skip IPC call
    end
    Note over Component: useEffect runs on hideAppIcon change
    Redux->>Component: hideAppIcon updated
    Component->>IPC: Re-sync new value
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A hop and a sync, a setting takes flight,
Through Electron's bridge to the main process bright,
Hide icons or show them, the choice is all yours,
While Redux and IPC dance through the doors,
The startup is graceful, the code clean and light! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'fix(electron): apply persisted hide-app-icon setting at startup' directly and specifically describes the main change: applying the persisted hide-app-icon setting at app startup for the Electron app.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ 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 fix/electron-hide-app-icon-startup-sync

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
Review rate limit: 0/1 reviews remaining, refill in 52 minutes and 33 seconds.

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

@argos-ci
Copy link
Copy Markdown

argos-ci Bot commented Apr 29, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ⚠️ Changes detected (Review) 2 changed Apr 29, 2026, 4:07 PM

Copy link
Copy Markdown
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/electron/ElectronStartupSync.tsx`:
- Around line 52-59: The current call to
window.electronAPI?.settings?.setHideAppIcon(hideAppIcon) only handles rejected
promises via .catch and misses when the IPC resolves to false; update the call
in ElectronStartupSync.tsx (the window.electronAPI?.settings?.setHideAppIcon
invocation with hideAppIcon) to inspect the resolved value (e.g., await or
.then(result => ...)) and treat a false result as a failure — log an error (or
handle appropriately) when result === false in addition to preserving the
existing .catch for thrown errors.
🪄 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: 985fa1d7-3072-4c66-a95e-9d8cb819d0c5

📥 Commits

Reviewing files that changed from the base of the PR and between ddbfecb and 5b02920.

📒 Files selected for processing (3)
  • src/app/layout.tsx
  • src/components/electron/ElectronStartupSync.test.tsx
  • src/components/electron/ElectronStartupSync.tsx

Comment thread src/components/electron/ElectronStartupSync.tsx Outdated
The preload bridge for setHideAppIcon swallows thrown errors via try/catch
and resolves to `false` instead of rejecting (see electron/preload.ts:1491-
1502). The previous .catch-only handler was therefore unreachable in the
real failure path: any main-process regression during startup sync would be
silently dropped.

Switch to .then(ok => ...) + .catch chain so we log when the IPC resolves
to `false` (the actual failure signal) while keeping the .catch as defense-
in-depth in case preload behavior changes.

Two new tests pin down the contract:
- false-resolve must log the IPC-returned-false error
- true-resolve must not log anything (guards against inverted check)

Addresses CodeRabbit major finding on PR #28.
@ryota-murakami ryota-murakami merged commit a3ba591 into main Apr 29, 2026
14 of 15 checks passed
@ryota-murakami ryota-murakami deleted the fix/electron-hide-app-icon-startup-sync branch April 29, 2026 16:14
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