Skip to content

fix(desktop): fix notification click not opening workspace/tab#354

Merged
Kitenite merged 3 commits intomainfrom
left-crawdad-49a647
Dec 13, 2025
Merged

fix(desktop): fix notification click not opening workspace/tab#354
Kitenite merged 3 commits intomainfrom
left-crawdad-49a647

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Dec 13, 2025

Summary

  • Extract NotificationIds interface for shared type across notification system
  • Add resolveNotificationTarget utility to resolve missing IDs from state
  • Refactor useAgentHookListener to use shared resolution logic
  • Handle cases where paneId or tabId is missing by looking up from state

Test plan

  • Unit tests added for resolveNotificationTarget (10 tests)
  • Manual test: trigger notification from agent completion, click notification to navigate

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Centralized notification target resolution to ensure actions use the most up-to-date workspace/pane/tab state.
  • Bug Fixes
    • More reliable focus and attention behavior when notifications trigger workspace or tab switches.
  • Tests
    • Added comprehensive unit tests covering many missing-ID and resolution scenarios.
  • Chores
    • Minor cleanup in notification click handling.

✏️ Tip: You can customize this high-level summary in your review settings.

- Extract NotificationIds interface for shared type across notification system
- Add resolveNotificationTarget utility to resolve missing IDs from state
- Refactor useAgentHookListener to use shared resolution logic
- Handle cases where paneId or tabId is missing by looking up from state
- Add unit tests for notification target resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 13, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Introduce a shared NotificationIds type and propagate it through server types, TRPC router events, renderer notification handling, and add a resolver utility with tests to normalize pane/tab/workspace IDs before acting on notifications.

Changes

Cohort / File(s) Summary
Server types
apps/desktop/src/main/lib/notifications/server.ts
Add export interface NotificationIds (optional paneId, tabId, workspaceId); make AgentCompleteEvent extend NotificationIds and keep `eventType: "Stop"
TRPC router
apps/desktop/src/lib/trpc/routers/notifications.ts
Change NotificationEvent so focus-tab carries NotificationIds; update subscription/emit handler signatures to accept and forward the new type.
Renderer hook
apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
Use resolveNotificationTarget to normalize targets; require valid resolved target for agent-complete; after workspace switches re-derive state and resolve target before handling focus-tab; operate on fresh lookups.
Resolver utility
apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts
Add `resolveNotificationTarget(ids: NotificationIds, state: TabsState): ResolvedTarget
Resolver tests
apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
Add comprehensive unit tests covering full IDs, missing workspace/tab cases, only tabId, only workspaceId, no resolvable IDs, and pane referencing a missing tab.
Main window
apps/desktop/src/main/windows/main.ts
Remove an inline comment in the notification click handler; focus-tab emission payload unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • Correctness and edge cases in resolveNotificationTarget (fallback order, null conditions).
    • State re-derivation timing and correctness in useAgentHookListener.ts after workspace switches.
    • Type alignment between server.ts and trpc/routers/notifications.ts to ensure emit/subscribe payload compatibility.

Possibly related PRs

Poem

🐰
I hopped through panes and tiny threads,
Collected IDs where data treads;
When tabs went missing, I traced the state,
Rejoined the paths and set them straight.
A little rabbit, payloads all fed!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description includes a summary of changes and a test plan, but is missing several required template sections: Related Issues, Type of Change, Testing details, Screenshots, and Additional Notes. Complete the PR description by filling in the missing template sections, particularly Related Issues, selecting the Type of Change (appears to be a Bug fix), and confirming the manual test status.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix: addressing notification clicks failing to open the correct workspace/tab, which aligns with the PR's core objective of resolving missing IDs from state.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71a2e3d and 352cb20.

📒 Files selected for processing (2)
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts (3 hunks)
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts (1 hunks)

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
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: 0

🧹 Nitpick comments (2)
apps/desktop/src/main/lib/notifications/server.ts (1)

29-41: Consider validating query parameters.

The query parameters are cast directly to string | undefined without validation. If a client sends an array (e.g., ?paneId=a&paneId=b), req.query.paneId would be an array, and the cast would be incorrect at runtime.

 app.get("/hook/complete", (req, res) => {
-	const { paneId, tabId, workspaceId, eventType } = req.query;
+	const paneId = typeof req.query.paneId === "string" ? req.query.paneId : undefined;
+	const tabId = typeof req.query.tabId === "string" ? req.query.tabId : undefined;
+	const workspaceId = typeof req.query.workspaceId === "string" ? req.query.workspaceId : undefined;
+	const eventType = typeof req.query.eventType === "string" ? req.query.eventType : undefined;

 	const event: AgentCompleteEvent = {
-		paneId: paneId as string | undefined,
-		tabId: tabId as string | undefined,
-		workspaceId: workspaceId as string | undefined,
+		paneId,
+		tabId,
+		workspaceId,
 		eventType: eventType === "PermissionRequest" ? "PermissionRequest" : "Stop",
 	};
apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts (1)

13-16: JSDoc priority description is inconsistent with actual tabId resolution.

The JSDoc states "Priority: event data > pane's tab" but for tabId, line 27 uses pane?.tabId ?? tabId, meaning pane's tabId takes precedence over event tabId. This is likely intentional (trusting pane's relationship), but the documentation is misleading.

 /**
  * Resolves notification target IDs by looking up missing values from state.
- * Priority: event data > pane's tab > tab's workspace
+ * Priority: pane's tabId > event tabId; event workspaceId > tab's workspaceId
  */
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e22c92e and 5230819.

📒 Files selected for processing (6)
  • apps/desktop/src/lib/trpc/routers/notifications.ts (1 hunks)
  • apps/desktop/src/main/lib/notifications/server.ts (1 hunks)
  • apps/desktop/src/main/windows/main.ts (0 hunks)
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts (3 hunks)
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts (1 hunks)
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/desktop/src/main/windows/main.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/main/lib/notifications/server.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
  • apps/desktop/src/lib/trpc/routers/notifications.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/main/lib/notifications/server.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
  • apps/desktop/src/lib/trpc/routers/notifications.ts
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for code formatting and linting, running at root level for speed

Files:

  • apps/desktop/src/main/lib/notifications/server.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
  • apps/desktop/src/lib/trpc/routers/notifications.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid any type and prioritize type safety in TypeScript code

Files:

  • apps/desktop/src/main/lib/notifications/server.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
  • apps/desktop/src/lib/trpc/routers/notifications.ts
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Call IPC methods from renderer process using window.ipcRenderer.invoke with type-safe object parameters

Files:

  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts
  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
apps/desktop/**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.test.{ts,tsx,js,jsx}: Tests should have one assert per test
Tests should be readable
Tests should be fast
Tests should be independent
Tests should be repeatable

Files:

  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
🧠 Learnings (3)
📚 Learning: 2025-12-12T05:45:09.673Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T05:45:09.673Z
Learning: Applies to apps/desktop/src/main/lib/*.ts : Implement IPC handlers accepting object parameters (not positional parameters) in apps/desktop/src/main/lib/*.ts files

Applied to files:

  • apps/desktop/src/main/lib/notifications/server.ts
  • apps/desktop/src/lib/trpc/routers/notifications.ts
📚 Learning: 2025-12-12T05:45:09.673Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T05:45:09.673Z
Learning: Applies to apps/desktop/src/shared/ipc-channels.ts : Define IPC channel types in apps/desktop/src/shared/ipc-channels.ts before implementing handlers

Applied to files:

  • apps/desktop/src/main/lib/notifications/server.ts
📚 Learning: 2025-11-24T21:33:13.267Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.267Z
Learning: Applies to apps/desktop/**/*.test.{ts,tsx,js,jsx} : Tests should be independent

Applied to files:

  • apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts
🧬 Code graph analysis (3)
apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts (2)
apps/desktop/src/renderer/stores/tabs/types.ts (1)
  • TabsState (19-21)
apps/desktop/src/main/lib/notifications/server.ts (1)
  • NotificationIds (4-8)
apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts (2)
apps/desktop/src/renderer/stores/tabs/utils.ts (1)
  • createPane (46-62)
apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts (1)
  • resolveNotificationTarget (17-44)
apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts (2)
apps/desktop/src/renderer/stores/tabs/store.ts (1)
  • useTabsStore (72-615)
apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts (1)
  • resolveNotificationTarget (17-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Deploy Marketing
  • GitHub Check: Deploy Docs
  • GitHub Check: Deploy Web
  • GitHub Check: Deploy API
  • GitHub Check: Deploy Admin
  • GitHub Check: Build
🔇 Additional comments (7)
apps/desktop/src/main/lib/notifications/server.ts (1)

4-11: Clean interface extraction for shared notification types.

The NotificationIds interface and the extends pattern for AgentCompleteEvent provide good type reusability across the notification system. This aligns well with the PR objective of centralizing notification-related types.

apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.test.ts (1)

1-169: Well-structured and comprehensive test suite.

The tests cover all key resolution scenarios with clear, readable structure. Each test follows the one-assert-per-test guideline and tests are independent. The helper functions are appropriately minimal for the test context.

apps/desktop/src/renderer/stores/tabs/utils/resolve-notification-target.ts (1)

17-43: Clean resolution logic with appropriate null safety.

The function handles missing IDs gracefully and returns null when a valid target cannot be determined. The use of optional chaining and nullish coalescing is idiomatic TypeScript.

apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts (2)

15-19: Good refactor to centralized resolution logic.

The early resolution and null-check pattern cleanly handles cases where notification data is incomplete. This simplifies the downstream logic for both event types.


46-63: Re-resolving from fresh state after workspace switch is correct.

The pattern of re-fetching state after the async setActiveWorkspace.mutate completes ensures the code operates on current data, avoiding potential stale state issues. The additional validation checks (tab existence, workspace ownership, pane existence) provide good defensive coding.

apps/desktop/src/lib/trpc/routers/notifications.ts (2)

9-11: Type union updated to use shared NotificationIds.

The NotificationEvent type now consistently uses the shared interfaces from the notifications server module, improving type alignment across the notification system.


17-23: Handler signatures simplified with consistent naming.

Renaming the parameter to data and passing it directly to the emit improves clarity and reduces redundancy. The cleanup function properly removes both listeners.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Dec 13, 2025

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

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: 0

🧹 Nitpick comments (1)
apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts (1)

42-72: Consider adding error handling for workspace switch failures.

The re-resolution logic after workspace switch is well-designed and handles state changes during async operations correctly. The defensive checks for tab/pane existence prevent errors gracefully.

However, there's no onError handler for the setActiveWorkspace.mutate call. If workspace switching fails, the notification click silently does nothing. Consider adding an onError callback for better observability, even if it only logs the error:

 setActiveWorkspace.mutate(
   { id: workspaceId },
   {
+    onError: (error) => {
+      console.error("Failed to switch workspace from notification:", error);
+    },
     onSuccess: () => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5230819 and 71a2e3d.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for code formatting and linting, running at root level for speed

Files:

  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid any type and prioritize type safety in TypeScript code

Files:

  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Call IPC methods from renderer process using window.ipcRenderer.invoke with type-safe object parameters

Files:

  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Deploy Web
  • GitHub Check: Deploy Admin
  • GitHub Check: Deploy Marketing
  • GitHub Check: Deploy Docs
  • GitHub Check: Deploy API
  • GitHub Check: Build
🔇 Additional comments (3)
apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts (3)

5-5: LGTM!

The import follows the project's path conventions and the utility is correctly used throughout the file.


23-34: LGTM!

The agent-complete handler correctly guards against missing paneId and only sets the attention indicator when the user isn't already viewing the target pane. The logic is clear and defensive.


17-21: No changes required. The return type of resolveNotificationTarget is already properly typed as ResolvedTarget | null, where ResolvedTarget extends NotificationIds with a required workspaceId field. The null check on line 19 correctly guards against undefined targets, and the destructuring on line 21 is fully type-safe.

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