Skip to content

fix: add context menu to root window for deep link launch flow#3271

Merged
jeanfbrito merged 2 commits intodevfrom
fix/root-window-context-menu
Mar 23, 2026
Merged

fix: add context menu to root window for deep link launch flow#3271
jeanfbrito merged 2 commits intodevfrom
fix/root-window-context-menu

Conversation

@jeanfbrito
Copy link
Copy Markdown
Member

@jeanfbrito jeanfbrito commented Mar 20, 2026

Summary

Fixes the right-click context menu being unresponsive on the "Enter your server URL" screen when the app is launched via a deep link.

https://rocketchat.atlassian.net/browse/CORE-1600

  • Add context-menu event listener on the root window's webContents with standard edit actions (Undo, Redo, Cut, Copy, Paste, Select All)
  • Root cause: context menus were only registered on server webview (guest) webContents, but the AddServerView renders in the root window which had no context menu handler

Test plan

  • Launch app via a deep link (e.g., rocketchat:// URL)
  • Wait for the "Enter your server URL" screen
  • Right-click on the URL input field — context menu should appear with Paste, Cut, Copy, Select All
  • Verify Ctrl+V / Cmd+V still works as before
  • Verify server webview context menus (spell check, image, link actions) are unaffected

Summary by CodeRabbit

  • New Features

    • Added an edit-focused context menu (undo, redo, cut, copy, paste, select all) with localized labels and platform-specific shortcuts.
  • Bug Fixes

    • Improved update-check behavior: user-initiated update checks bypass skipped-version filtering so users see available updates they previously skipped.

The right-click context menu was only attached to server webview
webContents, not to the root window's own webContents. This meant
the "Enter your server URL" screen (rendered in the root window)
had no context menu, preventing users from pasting via right-click
when the app was launched through a deep link.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 20, 2026

Walkthrough

Added a custom edit-focused context menu to the root window and registered a webContents 'context-menu' handler to build and popup that menu. Introduced an isUserInitiatedCheck flag in the updates flow to distinguish user-initiated vs. automatic update checks and adjust skipped-version handling accordingly.

Changes

Cohort / File(s) Summary
Context Menu Implementation
src/ui/main/rootWindow.ts
Imported Menu and added createRootWindowContextMenu(params: ContextMenuParams): Menu which builds an edit menu (undo/redo/cut/copy/paste/selectAll) using params.editFlags and translated labels; registered 'context-menu' on webContents to prevent default and menu.popup({ window }).
Update Check Control Flow
src/updates/main.ts
Added module-level isUserInitiatedCheck flag; reset before startup auto-check and set to true on user-requested checks. Modified update-available handling to skip dispatch suppression for user-initiated checks so skipped-version filtering is bypassed when the user explicitly requests an update check.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The changes in src/updates/main.ts appear out-of-scope for fixing root window context menus; the user-initiated update check flag modification is unrelated to the stated objective of addressing CORE-1600's right-click context menu issue. Remove changes from src/updates/main.ts or clarify their necessity in addressing the deep link context menu flow; these modifications are not mentioned in the PR description or issue requirements.
✅ 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: adding a context menu to the root window for the deep link launch flow, which directly addresses the PR's primary objective.
Linked Issues check ✅ Passed The changes to src/ui/main/rootWindow.ts fully satisfy CORE-1600 requirements by adding context menu support with edit actions (Undo, Redo, Cut, Copy, Paste, Select All) to the root window's webContents, restoring right-click functionality on the server URL input screen.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

🧹 Nitpick comments (1)
src/ui/main/rootWindow.ts (1)

584-588: The context-menu listener registration is called only once during app initialization, so multiple listener accumulation is not a practical concern.

showRootWindow() is invoked a single time at startup (src/main.ts:104), and the context-menu listener at lines 584–588 is registered once per application lifecycle. The singleton pattern used for _rootWindow ensures the listener is not duplicated.

Additionally, event.preventDefault() on the context-menu event is unnecessary—the event is informational in Electron and has no default behavior to prevent. It can be safely removed.

If you prefer to add defensive guard logic or move listener registration elsewhere for consistency, that would be an optional improvement. The current code functions correctly as-is.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/main/rootWindow.ts` around lines 584 - 588, The context-menu handler
registered via browserWindow.webContents.on('context-menu', ...) calls
event.preventDefault(), which is unnecessary for Electron's informational
'context-menu' event; remove the event.preventDefault() call and leave the
listener registration as-is (it is only created once when showRootWindow()
initializes the singleton _rootWindow). Ensure
createRootWindowContextMenu(params) is still invoked and menu.popup({ window:
browserWindow }) remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/ui/main/rootWindow.ts`:
- Around line 584-588: The context-menu handler registered via
browserWindow.webContents.on('context-menu', ...) calls event.preventDefault(),
which is unnecessary for Electron's informational 'context-menu' event; remove
the event.preventDefault() call and leave the listener registration as-is (it is
only created once when showRootWindow() initializes the singleton _rootWindow).
Ensure createRootWindowContextMenu(params) is still invoked and menu.popup({
window: browserWindow }) remains unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2625569-6668-4646-8dcd-a065d644072b

📥 Commits

Reviewing files that changed from the base of the PR and between 0790d9f and c0415f4.

📒 Files selected for processing (1)
  • src/ui/main/rootWindow.ts
📜 Review details
⏰ 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). (4)
  • GitHub Check: build (windows-latest, windows)
  • GitHub Check: build (ubuntu-latest, linux)
  • GitHub Check: check (ubuntu-latest)
  • GitHub Check: check (windows-latest)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript strict mode enabled in TypeScript configuration
Use React functional components with hooks instead of class components
Follow FSA (Flux Standard Action) pattern for Redux actions
Use camelCase for file names and PascalCase for component file names
All code must pass ESLint and TypeScript checks
Write self-documenting code with clear naming; avoid unnecessary comments except for complex business logic or non-obvious decisions
Use Fuselage components from @rocket.chat/fuselage for all UI work and only create custom components when Fuselage doesn't provide what's needed
Check Theme.d.ts for valid color tokens when using Fuselage components
Use defensive coding with optional chaining and fallbacks for Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) to ensure cross-platform compatibility across Windows, macOS, and Linux

Files:

  • src/ui/main/rootWindow.ts
🔇 Additional comments (2)
src/ui/main/rootWindow.ts (2)

3-16: LGTM!

The import additions are well-organized, correctly separating type-only imports (ContextMenuParams) from runtime imports (Menu). Both are required for the new context menu functionality.


528-579: LGTM!

Well-structured implementation with:

  • Defensive defaults in destructuring preventing runtime errors if editFlags properties are missing
  • Proper i18n integration for translated labels (all keys exist in i18n files)
  • Correct platform-specific redo accelerator handling (Windows uses Ctrl+Y by convention)

@github-actions
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

macOS installer download

@github-actions
Copy link
Copy Markdown

The update-available handler unconditionally honored skippedUpdateVersion,
silently suppressing skipped versions even when the user manually triggered
Check for Updates from the About dialog. This left no recovery path for
users who skipped a version and later changed their mind.

Add an isUserInitiatedCheck flag so the skip preference only applies to
automatic startup checks, not user-initiated ones.
@coderabbitai coderabbitai bot removed the type: bug label Mar 20, 2026
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.

🧹 Nitpick comments (1)
src/updates/main.ts (1)

349-366: The try/catch cannot catch errors from checkForUpdates() inside setTimeout.

The checkForUpdates() call is asynchronous within the setTimeout callback, so any thrown error or rejected promise won't be caught by the outer try/catch. While the autoUpdater.addListener('error', ...) at lines 321-330 handles update errors, the try/catch here is misleading.

Additionally, the purpose of the 100ms delay is unclear—consider adding a comment explaining why it's needed.

♻️ Suggested refactor: Move error handling inside setTimeout or remove misleading try/catch
 listen(UPDATES_CHECK_FOR_UPDATES_REQUESTED, async () => {
-  try {
-    isUserInitiatedCheck = true;
-    setTimeout(() => {
+  isUserInitiatedCheck = true;
+  // Delay check to allow UI state to settle (e.g., dialog animation)
+  setTimeout(async () => {
+    try {
       autoUpdater.checkForUpdates();
-    }, 100);
-  } catch (error) {
-    error instanceof Error &&
-      dispatch({
-        type: UPDATES_ERROR_THROWN,
-        payload: {
-          message: error.message,
-          stack: error.stack,
-          name: error.name,
-        },
-      });
-  }
+    } catch (error) {
+      error instanceof Error &&
+        dispatch({
+          type: UPDATES_ERROR_THROWN,
+          payload: {
+            message: error.message,
+            stack: error.stack,
+            name: error.name,
+          },
+        });
+    }
+  }, 100);
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/updates/main.ts` around lines 349 - 366, The try/catch around the
listen(UPDATES_CHECK_FOR_UPDATES_REQUESTED, ...) handler cannot catch errors
thrown inside the setTimeout callback; move error handling into that callback
(or remove the outer try/catch) so failures from autoUpdater.checkForUpdates are
caught and dispatched: inside the setTimeout wrap autoUpdater.checkForUpdates in
a try/catch or call autoUpdater.checkForUpdates().catch(...) and dispatch
UPDATES_ERROR_THROWN with error.message/name/stack (use the same payload shape
currently used); also add a short comment explaining why the 100ms delay exists
(or remove the delay if unnecessary) and keep isUserInitiatedCheck assignment
and existing autoUpdater.addListener('error', ...) intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/updates/main.ts`:
- Around line 349-366: The try/catch around the
listen(UPDATES_CHECK_FOR_UPDATES_REQUESTED, ...) handler cannot catch errors
thrown inside the setTimeout callback; move error handling into that callback
(or remove the outer try/catch) so failures from autoUpdater.checkForUpdates are
caught and dispatched: inside the setTimeout wrap autoUpdater.checkForUpdates in
a try/catch or call autoUpdater.checkForUpdates().catch(...) and dispatch
UPDATES_ERROR_THROWN with error.message/name/stack (use the same payload shape
currently used); also add a short comment explaining why the 100ms delay exists
(or remove the delay if unnecessary) and keep isUserInitiatedCheck assignment
and existing autoUpdater.addListener('error', ...) intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 639f26fd-db66-488a-ab81-19b71f7da6a9

📥 Commits

Reviewing files that changed from the base of the PR and between c0415f4 and 7818d3b.

📒 Files selected for processing (1)
  • src/updates/main.ts
📜 Review details
⏰ 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). (3)
  • GitHub Check: check (ubuntu-latest)
  • GitHub Check: check (macos-latest)
  • GitHub Check: check (windows-latest)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript strict mode enabled in TypeScript configuration
Use React functional components with hooks instead of class components
Follow FSA (Flux Standard Action) pattern for Redux actions
Use camelCase for file names and PascalCase for component file names
All code must pass ESLint and TypeScript checks
Write self-documenting code with clear naming; avoid unnecessary comments except for complex business logic or non-obvious decisions
Use Fuselage components from @rocket.chat/fuselage for all UI work and only create custom components when Fuselage doesn't provide what's needed
Check Theme.d.ts for valid color tokens when using Fuselage components
Use defensive coding with optional chaining and fallbacks for Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) to ensure cross-platform compatibility across Windows, macOS, and Linux

Files:

  • src/updates/main.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: Ram-sah19
Repo: RocketChat/Rocket.Chat.Electron PR: 3254
File: .github/workflows/build-release.yml:80-94
Timestamp: 2026-03-11T06:38:40.426Z
Learning: In the RocketChat/Rocket.Chat.Electron repository, the issues flagged in `.github/workflows/build-release.yml` (e.g., `node12` runtime in the release action and missing `snapcraft_token` input), i18n files, and `electron-builder.json` are pre-existing in the `develop` branch and are pulled in during merge conflict resolution. Do not flag these as new issues introduced by PRs that only modify `src/injected.ts` and `src/ui/main/rootWindow.ts`.
🔇 Additional comments (3)
src/updates/main.ts (3)

165-166: LGTM, but consider resetting the flag after check completion.

The module-level flag correctly differentiates user-initiated vs automatic checks. While current code paths set it appropriately before each checkForUpdates() call, consider resetting isUserInitiatedCheck = false in the update-available and update-not-available handlers to prevent accidental misuse if future code adds additional check triggers.


249-252: LGTM - Logic correctly bypasses skip filter for user-initiated checks.

The condition properly allows users who manually click "Check for Updates" to re-discover a previously skipped version, while automatic startup checks continue to respect the skip preference.


332-346: LGTM - Startup check correctly marked as automatic.

The flag is appropriately set to false before the awaited check, and errors are properly caught.

@jeanfbrito jeanfbrito merged commit d12da77 into dev Mar 23, 2026
9 of 16 checks passed
@jeanfbrito jeanfbrito deleted the fix/root-window-context-menu branch March 23, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant