feat: Add app badge count for unread tasks#1723
feat: Add app badge count for unread tasks#1723arnestrickmann merged 1 commit intogeneralaction:mainfrom
Conversation
Show the native OS badge on the app icon with the count of tasks that have unread activity. Controlled by a new "App badge" toggle in notification settings, off by default.
|
@homebysix is attempting to deploy a commit to the General Action Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
📝 WalkthroughWalkthroughThis pull request implements an app badge count feature that displays the unread task count on the native OS dock/taskbar icon. The feature adds settings infrastructure, IPC bridge functionality, unread count tracking enhancements, and UI components to enable and synchronize the badge display across the renderer and main processes. Changes
Sequence DiagramsequenceDiagram
actor User
participant Settings as Settings UI
participant Store as agentStatusStore
participant Workspace as Workspace Component
participant IPC as electronAPI/ipcMain
participant Main as Main Process
User->>Settings: Toggle "App badge" setting
Settings->>Store: updateSettings({appBadge: true})
Note over Store: Task status changes<br/>(waiting/complete/error)
Store->>Store: setUnread(taskId, true)
Store->>Workspace: notify unread listeners
Workspace->>Workspace: sync(): compute badge count<br/>from getUnreadCount()
Workspace->>IPC: setBadgeCount(count)
IPC->>Main: ipcMain.on('app:set-badge-count')
Main->>Main: app.setBadgeCount(count)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 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.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/renderer/views/Workspace.tsx (1)
103-110: Skip unread subscription when app badge is disabled.This effect still subscribes and sends
0updates while disabled; short-circuiting avoids unnecessary IPC traffic.♻️ Proposed refinement
useEffect(() => { const enabled = (settings?.notifications?.enabled ?? true) && (settings?.notifications?.appBadge ?? false); - const sync = () => - window.electronAPI.setBadgeCount(enabled ? agentStatusStore.getUnreadCount() : 0); - sync(); - return agentStatusStore.onUnreadCountChange(sync); + if (!enabled) { + window.electronAPI.setBadgeCount(0); + return; + } + const sync = () => window.electronAPI.setBadgeCount(agentStatusStore.getUnreadCount()); + sync(); + return agentStatusStore.onUnreadCountChange(sync); }, [settings?.notifications?.enabled, settings?.notifications?.appBadge]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderer/views/Workspace.tsx` around lines 103 - 110, The effect currently always subscribes and calls setBadgeCount(0) when app badge is disabled; update the useEffect so it computes enabled from settings and short-circuits when the appBadge is false: if not enabled, call window.electronAPI.setBadgeCount(0) once and return without calling agentStatusStore.onUnreadCountChange, otherwise set up the sync function and return the subscription. Refer to useEffect, the local sync function, agentStatusStore.onUnreadCountChange and window.electronAPI.setBadgeCount when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/ipc/appIpc.ts`:
- Around line 203-207: The IPC handler for 'app:set-badge-count' currently
trusts the renderer-provided count; coerce and validate that input to a finite
non-negative integer before comparing against lastBadgeCount and calling
app.setBadgeCount. Inside the ipcMain.on callback (the handler that receives the
count parameter), convert the incoming value to a number, verify
Number.isFinite, floor it (or use Math.trunc) and clamp to zero for negatives,
treat invalid/non-finite inputs as 0 (or ignore), then use this normalized value
for the dedupe check against lastBadgeCount and for the subsequent
app.setBadgeCount call (update lastBadgeCount only after successful
normalization).
---
Nitpick comments:
In `@src/renderer/views/Workspace.tsx`:
- Around line 103-110: The effect currently always subscribes and calls
setBadgeCount(0) when app badge is disabled; update the useEffect so it computes
enabled from settings and short-circuits when the appBadge is false: if not
enabled, call window.electronAPI.setBadgeCount(0) once and return without
calling agentStatusStore.onUnreadCountChange, otherwise set up the sync function
and return the subscription. Refer to useEffect, the local sync function,
agentStatusStore.onUnreadCountChange and window.electronAPI.setBadgeCount when
making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5143a901-8941-4693-ad6c-06228a822763
📒 Files selected for processing (10)
src/main/ipc/appIpc.tssrc/main/preload.tssrc/main/settings.tssrc/renderer/components/NotificationSettingsCard.tsxsrc/renderer/lib/agentStatusStore.tssrc/renderer/types/electron-api.d.tssrc/renderer/views/Workspace.tsxsrc/test/main/appIpc.openIn.test.tssrc/test/main/settings.test.tssrc/test/renderer/agentStatusStore.test.ts
| ipcMain.on('app:set-badge-count', (_event, count: number) => { | ||
| if (count === lastBadgeCount) return; | ||
| lastBadgeCount = count; | ||
| try { | ||
| app.setBadgeCount(count); |
There was a problem hiding this comment.
Validate and normalize badge-count IPC input in main process.
Line 203 currently trusts renderer input. Please coerce to a finite non-negative integer before dedupe/update to avoid invalid values and unstable dedupe behavior.
🔧 Proposed hardening patch
- ipcMain.on('app:set-badge-count', (_event, count: number) => {
+ ipcMain.on('app:set-badge-count', (_event, rawCount: unknown) => {
+ const count =
+ typeof rawCount === 'number' && Number.isFinite(rawCount)
+ ? Math.max(0, Math.floor(rawCount))
+ : 0;
if (count === lastBadgeCount) return;
lastBadgeCount = count;
try {
app.setBadgeCount(count);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ipcMain.on('app:set-badge-count', (_event, count: number) => { | |
| if (count === lastBadgeCount) return; | |
| lastBadgeCount = count; | |
| try { | |
| app.setBadgeCount(count); | |
| ipcMain.on('app:set-badge-count', (_event, rawCount: unknown) => { | |
| const count = | |
| typeof rawCount === 'number' && Number.isFinite(rawCount) | |
| ? Math.max(0, Math.floor(rawCount)) | |
| : 0; | |
| if (count === lastBadgeCount) return; | |
| lastBadgeCount = count; | |
| try { | |
| app.setBadgeCount(count); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/ipc/appIpc.ts` around lines 203 - 207, The IPC handler for
'app:set-badge-count' currently trusts the renderer-provided count; coerce and
validate that input to a finite non-negative integer before comparing against
lastBadgeCount and calling app.setBadgeCount. Inside the ipcMain.on callback
(the handler that receives the count parameter), convert the incoming value to a
number, verify Number.isFinite, floor it (or use Math.trunc) and clamp to zero
for negatives, treat invalid/non-finite inputs as 0 (or ignore), then use this
normalized value for the dedupe check against lastBadgeCount and for the
subsequent app.setBadgeCount call (update lastBadgeCount only after successful
normalization).
|
Hi @homebysix, I replied to your issue a few minutes ago, if you haven't seen it #1722 |
|
As said, we will include this in the new version soon as well. @homebysix But also merging this here to try it out and for all the users of the current version:)) Thanks again! |
Summary
Adds a native OS badge to the app icon showing how many tasks have unread activity. The count matches the sidebar's blue-dot indicators. Controlled by a new "App badge" toggle in notification settings, off by default.
Bridges the renderer's existing
AgentStatusStoreunread state toapp.setBadgeCount()via a fire-and-forget IPC call. AddsgetUnreadCount()andonUnreadCountChange()to the store, deriving the count from the existingunreadByIdmap.Fixes
Resolves #1722
Snapshot
Type of change
Mandatory Tasks
Checklist
Summary by CodeRabbit
Release Notes
New Features
Tests