feat(app): collapse notification settings to single tri-state control (phase 2 of #923)#938
Conversation
… (phase 2 of #923) Replace six sound toggles and three notification switches with one "Sounds & notifications" selector: Never / When not looking / Always. - settings.tsx: new NotifyLevel type, migration from old persisted shape - notification.tsx: gate idle/error alerts by tri-state + route visibility - layout-sdk-event-effects.ts: unify permission/question notification logic - settings UI: single Select replaces two multi-row sections (-233 LOC) - Electron: silent: true on OS Notification (app owns the sound) - sound.ts: remove unused SOUND_OPTIONS/SoundOption exports - i18n: en + zh updated, old keys removed
- Extract settingsSelectDefaults constant to deduplicate variant/size/ triggerVariant across all four settings dropdowns - Inline notify section into settings-general.tsx, delete standalone settings-sounds-section.tsx - Fix settings Select hover: scope transparent background to non-hover non-expanded state so picker.css hover overlay shows through
The renderer Notification (Web API) and the web entry Notification both lacked silent: true, so the OS played its default alert sound on top of the app's own notify/error sound.
There was a problem hiding this comment.
Suggested priority: P2 (includes user-path files (packages/app/src/components/settings-general.tsx, packages/app/src/components/settings-notifications-section.tsx, packages/app/src/components/settings-sounds-section.tsx, packages/app/src/context/notification.tsx, packages/app/src/context/settings.tsx, packages/app/src/entry.tsx, packages/app/src/i18n/en.ts, packages/app/src/i18n/zh.ts, packages/app/src/pages/layout.tsx, packages/app/src/pages/layout/layout-sdk-event-effects.test.ts, packages/app/src/pages/layout/layout-sdk-event-effects.ts, packages/app/src/utils/sound.ts, packages/desktop-electron/src/main/ipc.ts, packages/desktop-electron/src/renderer/index.tsx)).
P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.
|
Warning Review limit reached
More reviews will be available in 35 minutes and 27 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughSettings are refactored from separate notification and sound toggles to a single tri-state notification-level control ( ChangesNotification/Sound Settings Consolidation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Code Review
This pull request simplifies the notification and sound settings by consolidating them into a single tri-state notify level (never, unfocused, or always). It removes the separate notification and sound settings sections, updates the general settings UI, and introduces a migration effect to map existing user configurations to the new setting. Feedback on these changes highlights reactivity issues in SolidJS: notifyOptions should be wrapped in createMemo to ensure translations update dynamically when the language changes, and the settings migration createEffect should use untrack to prevent unnecessary re-runs when store properties are modified.
"When not looking" should mean the window is backgrounded too, not just a different session route. Add document.hasFocus() guard so switching to another app triggers sounds and notifications.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@packages/app/src/components/settings-general.tsx`:
- Around line 94-98: notifyOptions is built once so its labels won't update when
locale changes; wrap its construction in a reactive memo (e.g. const
notifyOptions = createMemo(() => [...])) and use notifyOptions() wherever the
Select reads the options (and similarly for the other options at the other
locations). Specifically, replace the static array of { id: NotifyLevel; label:
string } with a createMemo that calls language.t for each label, and update the
Select usage to read notifyOptions() so labels update when language changes.
In `@packages/app/src/i18n/zh.ts`:
- Line 758: The zh locale uses "PawWork" in the translation for the key
"settings.notify.description" which is inconsistent with the rest of the file
that uses "爪印"; update the value for "settings.notify.description" to replace
"PawWork" with "爪印" so the product name is consistently translated across the
locale.
🪄 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 Plus
Run ID: 8099e19a-ffcf-42a1-a11b-36971ddb754f
📒 Files selected for processing (15)
packages/app/src/components/settings-general.tsxpackages/app/src/components/settings-notifications-section.tsxpackages/app/src/components/settings-sounds-section.tsxpackages/app/src/context/notification.tsxpackages/app/src/context/settings.tsxpackages/app/src/entry.tsxpackages/app/src/i18n/en.tspackages/app/src/i18n/zh.tspackages/app/src/pages/layout.tsxpackages/app/src/pages/layout/layout-sdk-event-effects.test.tspackages/app/src/pages/layout/layout-sdk-event-effects.tspackages/app/src/utils/sound.tspackages/desktop-electron/src/main/ipc.tspackages/desktop-electron/src/renderer/index.tsxpackages/ui/src/components/select.css
💤 Files with no reviewable changes (2)
- packages/app/src/components/settings-notifications-section.tsx
- packages/app/src/components/settings-sounds-section.tsx
Perf delta summaryComparator: pass
|
…, zh brand name - Wrap notifyOptions in createMemo so labels update on locale change - Wrap migration effect body in untrack to avoid re-triggering on the store writes it performs - Use 爪印 instead of PawWork in zh.ts description (matches the rest of the zh dictionary)
The question notification path only called effects.notify() (now a
silent OS notification) without playing the app sound. Add
effects.playSound("notify") to match the permission path.
Add four tests asserting sound playback for question and permission
alerts, and silence for "never" and visible-session cases.
Bump PawWork desktop release version to 2026.5.28. Changes since v2026.5.27: - feat(ui): fold reasoning into trow block (#948) - feat: align outbound HTTP headers with canonical OpenCode desktop (#940) - feat(app): collapse notification settings to single tri-state control (#938) - fix(ui): track List header surface via --list-surface (#954) - fix(ui): render tooltip shortcut hints as plain sans glyphs (#955) - fix(watcher): isolate macOS workspace roots - fix(session): terminalize stale question blockers - fix(session): unify transport error classification for stream disconnect recovery (#941) - test: add route inventory guardrails - ci: repair electron desktop build + install
Summary
Replace six sound toggles and three notification switches with a single tri-state Sounds & notifications selector: Never / When not looking / Always. Silence OS notification sound on all Electron/web paths so only the app's own sounds play. Unify settings Select props and fix hover visibility.
Why
Phase 1 (#924) shipped two warm sounds but kept the old six-toggle + three-switch UI from upstream OpenCode. Users had to configure 9 controls for what is really one question: "when do you want to be alerted?" Phase 2 collapses this into a single tri-state that also gates OS notifications, matching the product direction outlined in #923.
Related Issue
Closes #923
Human Review Status
Pending
Review Focus
settings.tsx: old persistedsounds+notificationsfields map to the newnotifytri-state on first load, then get cleaned up. Verify the mapping covers edge cases (all disabled → "never", any enabled → "unfocused").document.hasFocus()is now part of "is the user looking at this session." Confirm this doesn't fire false negatives on macOS when the app window is in a different desktop/space.silent: trueon all three Notification paths (renderer Web API, main process IPC fallback, web entry).Risk Notes
settings.v3storage key. Users who downgrade to a pre-phase-2 build will lose theirnotifyvalue and get defaults. Low risk since the old defaults (agent sounds on, error sounds on, notifications on) are more permissive than "unfocused."Notification({ silent: true })is supported on macOS and Windows. Linux behavior depends on the notification daemon; some may ignore the flag. No regression since Linux previously had no sound gating either.How To Verify
Screenshots or Recordings
Settings page before (6 dropdowns + 3 switches across two sections):
Not captured — the old UI was removed in this PR. See phase 1 PR #924 for the prior state.
Settings page after (single tri-state dropdown):
Verified in
bun run dev:desktop— one "Sounds & notifications" row with a "Never / When not looking / Always" dropdown under a "Notifications" section header.Checklist
bug,enhancement,task,documentation. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this.app,ui,platform,harness,ci. The labeler bot assigns these on PR open based on changed paths. Confirm the bot's choice (or override if wrong), then tick this.P0,P1,P2,P3. The priority-triage bot suggests one on PR open. Confirm or override, then tick this.Pending,Approved by @<reviewer>, orNot required: <reason>(default isPending; "not required" is restricted to bot-authored low-risk PRs).dev, and my PR title and commit messages use Conventional Commits in English.