Skip to content

fix(desktop): warn before closing app during active upload#3262

Open
Ram-sah19 wants to merge 13 commits intoRocketChat:developfrom
Ram-sah19:fix/upload-close-warning
Open

fix(desktop): warn before closing app during active upload#3262
Ram-sah19 wants to merge 13 commits intoRocketChat:developfrom
Ram-sah19:fix/upload-close-warning

Conversation

@Ram-sah19
Copy link
Copy Markdown

@Ram-sah19 Ram-sah19 commented Mar 12, 2026

Fix #3261

Description

This PR prevents the Rocket.Chat Desktop application from closing while a file upload is in progress.

If the user attempts to close the application during an active upload, a confirmation dialog appears asking whether they want to quit or cancel.

Changes

  • Added upload tracking system
  • Prevent app closure when uploads are active
  • Show confirmation dialog if user tries to quit
  • Support multiple simultaneous uploads

How to Test

  1. Open Rocket.Chat Desktop.
  2. Upload a large file in any channel.
  3. Attempt to close the application before the upload finishes.

Expected result:
A confirmation dialog appears warning that a file upload is still in progress.

Fixes #ISSUE_NUMBER

Summary by CodeRabbit

  • New Features

    • Prevent accidental app closure while file uploads are active — shows a confirmation dialog with Cancel/Quit.
    • Real-time upload tracking with start/finish/fail notifications available to renderer and main processes.
    • macOS: Add Kerberos/SPNEGO authentication support for .local and .domain.local domains.
    • Enable plugin support in webviews for guest content and during video calls.
  • Bug Fixes

    • Notification sound behavior fixed to honor explicit silent settings.
  • Chores

    • Removed legacy dev-engines requirement from the manifest.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 12, 2026

Walkthrough

Adds upload-tracking with renderer preload APIs and a main-process quit guard that prompts when uploads are active; integrates tracking into Redux and app startup, adjusts notification silent mapping, enables macOS Kerberos switches, allows plugins for specific webviews, and removes package.json devEngines.

Changes

Cohort / File(s) Summary
Upload tracking core
src/uploads/actions.ts, src/uploads/reducer.ts, src/uploads/preload.ts, src/uploads/main.ts
New upload action constants and payload types, reducer tracking active upload count, renderer preload helpers to emit upload events, and main-process setup with setupUploadTracking() plus checkActiveUploads() (quit confirmation dialog).
Integration & IPC
src/store/rootReducer.ts, src/store/actions.ts, src/main.ts, src/servers/preload/api.ts
Register activeUploads in root reducer and action map, initialize upload tracking at startup, and expose notifyUploadStarted/Finished/Failed to renderer via preload API.
Window close guard & menus
src/ui/main/rootWindow.ts, src/ui/main/menuBar.ts, src/ui/main/trayIcon.ts
Add exported guardedQuit() and call checkActiveUploads() from window close, menu, and tray quit paths to prevent quitting while uploads are active.
Notification sound handling
src/notifications/main.ts
Change mapping of silent option to preserve explicit booleans only (typeof silent === 'boolean' ? silent : undefined).
macOS auth switches
src/app/main/app.ts
Append auth-server-whitelist and auth-negotiate-delegate-whitelist switches for *.local,*.domain.local when running on darwin.
Webview plugin support
src/ui/main/serverView/index.ts
Enable webPreferences.plugins = true for guest webviews and for new-window overrides (e.g., video call windows).
Manifest / config
package.json
Remove top-level devEngines field.
Documentation / notes
NOTIFICATION_SOUND_FIX.md, UPLOAD_TRACKING_FEATURE.md
Added/updated docs describing the notification sound fix and the upload-tracking/close-prevention feature, usage, and testing guidance.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Renderer as Renderer
    participant Redux as Redux
    participant Main as Main
    participant Dialog as Dialog

    User->>Renderer: Start upload
    Renderer->>Redux: dispatch(UPLOAD_STARTED {id, fileName})
    Redux->>Main: preload/IPC -> notifyUploadStarted(id, fileName)
    Main->>Main: add id to activeUploads set

    User->>Main: Attempt to close app/window
    Main->>Main: on-close -> await checkActiveUploads()
    alt active uploads exist
        Main->>Dialog: show "Upload in progress" (Quit / Cancel)
        Dialog->>User: prompt
        User-->>Dialog: Cancel or Quit
        alt Cancel
            Dialog->>Main: return false
            Main->>Main: abort close
        else Quit
            Dialog->>Main: return true
            Main->>Main: proceed to quit
        end
    else no active uploads
        Main->>Main: proceed to quit
    end

    Renderer->>Redux: dispatch(UPLOAD_FINISHED/FAILED {id})
    Redux->>Main: preload/IPC -> notifyUploadFinished/Failed(id)
    Main->>Main: remove id from activeUploads set
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive Most changes align with linked issue objectives. However, several modifications appear tangential: notification sound fix, macOS Kerberos authentication, plugin enablement for webviews, and devEngines removal lack direct connection to upload tracking. Clarify whether notification fix, Kerberos auth, plugin enablement, and devEngines changes are essential to the upload warning feature or should be submitted separately.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(desktop): warn before closing app during active upload' accurately and concisely describes the main change: preventing app closure during active uploads with a warning dialog.
Linked Issues check ✅ Passed The PR implements all primary objectives from issue #3261: tracks active uploads, presents a confirmation dialog during quit attempts with upload in progress, and prevents app closure without user confirmation.
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.

📝 Coding Plan for PR comments
  • Generate coding plan

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/notifications/main.ts (1)

61-67: ⚠️ Potential issue | 🟠 Major

Notifications silenced by default when silent is not explicitly provided.

With silent !== false, when callers omit the silent parameter (it's undefined), the expression evaluates to true, making all notifications silent. This overrides Electron's default behavior where undefined respects OS notification settings. Calls from src/downloads/main.ts and src/injected.ts:269-273 do not provide silent, so they will be affected.

🔧 Suggested fix
-    silent: silent !== false,
+    silent: typeof silent === 'boolean' ? silent : undefined,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/notifications/main.ts` around lines 61 - 67, The Notification is being
created with "silent: silent !== false", which makes notifications silent when
callers omit the silent parameter; update the Notification creation in
src/notifications/main.ts so the silent property is only set when the caller
explicitly provides it (i.e., preserve undefined to let Electron/OS defaults
apply). Concretely, change the Notification instantiation (the object with
title, subtitle, body, icon, silent, hasReply) so that you either omit the
silent key when silent is undefined or assign silent directly only if provided
(ensure callers that pass true/false still work), leaving resolveIcon(...) and
other fields unchanged.
🧹 Nitpick comments (3)
src/ui/main/serverView/index.ts (1)

213-213: Scope plugins more narrowly.

This turns plugin loading on for every server webview/popup, which increases the capabilities of untrusted remote content globally. If this is only needed for a specific surface, gate it there instead of enabling it on the default attach path.

Also applies to: 254-254

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

In `@src/ui/main/serverView/index.ts` at line 213, The code currently enables
plugins globally by setting webPreferences.plugins = true; instead make plugins
opt-in: set webPreferences.plugins = false by default and only set it to true in
the specific webview creation path that requires plugins (e.g., inside the
popup/server webview factory or the handler that creates the trusted surface) by
checking an explicit flag or trust/origin check (for example use an
options.enablePlugins or options.trusted check when creating the webview);
update both occurrences of webPreferences.plugins (the instances flagged) so
untrusted/default attach paths remain false.
UPLOAD_TRACKING_FEATURE.md (2)

189-200: Add language specifier to ASCII diagram code block.

The dialog mockup should have a language specifier.

📝 Proposed fix
-```
+```text
 ┌─────────────────────────────────────────┐
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@UPLOAD_TRACKING_FEATURE.md` around lines 189 - 200, The ASCII dialog mockup
code block is missing a language specifier; update the triple-backtick fence
that surrounds the box diagram in UPLOAD_TRACKING_FEATURE.md to include a
language tag (use "text") so the block becomes ```text and the diagram (the box
starting with "┌─────────────────────────────────────────┐") is rendered
correctly as plain text.

32-42: Add language specifier to fenced code blocks.

The ASCII flow diagrams should have a language specifier (e.g., text or plaintext) to satisfy markdown linting rules.

📝 Proposed fix
-```
+```text
 Rocket.Chat Web Client starts upload

Apply similarly to lines 46 and 62.

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

In `@UPLOAD_TRACKING_FEATURE.md` around lines 32 - 42, The fenced ASCII flow
diagrams (the blocks showing "Rocket.Chat Web Client starts upload" through
"window.RocketChatDesktop.notifyUploadStarted(id, fileName)" and the subsequent
flows referencing symbols like notifyUploadStarted, UPLOAD_STARTED, and
activeUploadsCount++) lack a language specifier and fail markdown linting;
update each triple-backtick fence for those diagrams to include a language
(e.g., ```text or ```plaintext) so the blocks are valid Markdown—apply the same
change to the other diagram fences in the file (the ones corresponding to the
other flows).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@NOTIFICATION_SOUND_FIX.md`:
- Around line 10-13: Update the documentation and tests to reflect correct
JavaScript semantics and the implemented behavior: change the root cause text to
state that "false ?? undefined" evaluates to false (the nullish coalescing
operator returns the left operand if it's not null/undefined), and explain that
the fix uses "silent !== false" so non‑false values (including undefined) will
result in a silent-enabled behavior only when explicitly false; then align Test
3 ("Non-Silent Notification (Explicitly with Sound)" / the test titled with
explicit sound) to expect a notification WITH sound and update the checklist
entry that currently reads "No sound plays when silent is false" to assert that
sound does play when silent is false.

In `@src/app/main/app.ts`:
- Around line 69-79: The Kerberos/SPNEGO whitelist is being set unconditionally
on macOS via process.platform === 'darwin' and
app.commandLine.appendSwitch('auth-server-whitelist', ...) and
app.commandLine.appendSwitch('auth-negotiate-delegate-whitelist', ...); instead,
gate these calls behind the same domain opt-in checks used for NTLM in
setupApp(): consult isNTLMCredentialsEnabled and allowedNTLMCredentialsDomains
and only call app.commandLine.appendSwitch with the whitelisted domains when
isNTLMCredentialsEnabled is true and allowedNTLMCredentialsDomains contains the
target domains (or otherwise follows the same opt-in logic), ensuring identical
per-domain opt-in behavior for Kerberos/SPNEGO and NTLM.

In `@src/main.ts`:
- Line 39: Move the import of setupUploadTracking so it appears before the
import of ./userPresence/main to satisfy ESLint import ordering; specifically,
in src/main.ts reorder the import statement "import { setupUploadTracking } from
'./uploads/main';" to precede the import that brings in ./userPresence/main
(adjust any grouped imports accordingly) and run lint to ensure ordering is now
correct.

In `@src/ui/main/rootWindow.ts`:
- Line 19: Move the import of checkActiveUploads so it appears after (or before,
per project convention) the import from ../actions to satisfy ESLint
import-order; specifically, in src/ui/main/rootWindow.ts reorder the import
statements so the import that references ../actions appears in the proper
position relative to the import { checkActiveUploads } from
'../../uploads/main', ensuring the symbol checkActiveUploads is still referenced
correctly and tests/compilation pass.

In `@src/uploads/main.ts`:
- Line 3: The import statement brings in unused symbols dispatch and select
which ESLint flags; edit the import to remove dispatch and select and only
import listen (i.e., drop dispatch and select from the import list in
src/uploads/main.ts), or if those functions are actually needed, use them where
appropriate; ensure the final import only contains used symbols to satisfy
ESLint.

In `@src/uploads/reducer.ts`:
- Around line 10-13: The reducer uses Upload action types (UPLOAD_STARTED,
UPLOAD_FINISHED, UPLOAD_FAILED) via ActionOf<...> but their
UploadsActionTypeToPayloadMap is not registered in the global action registry;
import UploadsActionTypeToPayloadMap from the uploads actions module and merge
it into the root ActionTypeToPayloadMap (e.g., via a union/augmentation so
ActionTypeToPayloadMap includes UploadsActionTypeToPayloadMap) so TypeScript
strict FSA typing satisfies the reducer's ActionOf constraint.

In `@UPLOAD_TRACKING_FEATURE.md`:
- Line 300: Update the placeholder created date string "**Created**: 2025-01-XX"
to the actual creation date (replace "2025-01-XX" with the real YYYY-MM-DD) in
the UPLOAD_TRACKING_FEATURE.md file so the metadata is accurate; locate the line
containing the bold "Created" label and substitute the placeholder with the
correct date.

---

Outside diff comments:
In `@src/notifications/main.ts`:
- Around line 61-67: The Notification is being created with "silent: silent !==
false", which makes notifications silent when callers omit the silent parameter;
update the Notification creation in src/notifications/main.ts so the silent
property is only set when the caller explicitly provides it (i.e., preserve
undefined to let Electron/OS defaults apply). Concretely, change the
Notification instantiation (the object with title, subtitle, body, icon, silent,
hasReply) so that you either omit the silent key when silent is undefined or
assign silent directly only if provided (ensure callers that pass true/false
still work), leaving resolveIcon(...) and other fields unchanged.

---

Nitpick comments:
In `@src/ui/main/serverView/index.ts`:
- Line 213: The code currently enables plugins globally by setting
webPreferences.plugins = true; instead make plugins opt-in: set
webPreferences.plugins = false by default and only set it to true in the
specific webview creation path that requires plugins (e.g., inside the
popup/server webview factory or the handler that creates the trusted surface) by
checking an explicit flag or trust/origin check (for example use an
options.enablePlugins or options.trusted check when creating the webview);
update both occurrences of webPreferences.plugins (the instances flagged) so
untrusted/default attach paths remain false.

In `@UPLOAD_TRACKING_FEATURE.md`:
- Around line 189-200: The ASCII dialog mockup code block is missing a language
specifier; update the triple-backtick fence that surrounds the box diagram in
UPLOAD_TRACKING_FEATURE.md to include a language tag (use "text") so the block
becomes ```text and the diagram (the box starting with
"┌─────────────────────────────────────────┐") is rendered correctly as plain
text.
- Around line 32-42: The fenced ASCII flow diagrams (the blocks showing
"Rocket.Chat Web Client starts upload" through
"window.RocketChatDesktop.notifyUploadStarted(id, fileName)" and the subsequent
flows referencing symbols like notifyUploadStarted, UPLOAD_STARTED, and
activeUploadsCount++) lack a language specifier and fail markdown linting;
update each triple-backtick fence for those diagrams to include a language
(e.g., ```text or ```plaintext) so the blocks are valid Markdown—apply the same
change to the other diagram fences in the file (the ones corresponding to the
other flows).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: db1b1b42-4b76-498e-903a-e9c6b5f05d8b

📥 Commits

Reviewing files that changed from the base of the PR and between 4abd69c and a9ef105.

📒 Files selected for processing (13)
  • NOTIFICATION_SOUND_FIX.md
  • UPLOAD_TRACKING_FEATURE.md
  • src/app/main/app.ts
  • src/main.ts
  • src/notifications/main.ts
  • src/servers/preload/api.ts
  • src/store/rootReducer.ts
  • src/ui/main/rootWindow.ts
  • src/ui/main/serverView/index.ts
  • src/uploads/actions.ts
  • src/uploads/main.ts
  • src/uploads/preload.ts
  • src/uploads/reducer.ts
📜 Review details
🧰 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/uploads/main.ts
  • src/uploads/actions.ts
  • src/uploads/preload.ts
  • src/store/rootReducer.ts
  • src/ui/main/serverView/index.ts
  • src/ui/main/rootWindow.ts
  • src/main.ts
  • src/uploads/reducer.ts
  • src/servers/preload/api.ts
  • src/notifications/main.ts
  • src/app/main/app.ts
🧠 Learnings (4)
📓 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`.
📚 Learning: 2026-03-06T19:31:11.433Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-03-06T19:31:11.433Z
Learning: Applies to src/outlookCalendar/**/preload.ts : Keep preload.ts logging minimal since it cannot access the verbose logging toggle from Redux Store and all logs always appear

Applied to files:

  • src/uploads/preload.ts
  • src/servers/preload/api.ts
📚 Learning: 2026-03-06T19:31:11.433Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-03-06T19:31:11.433Z
Learning: Applies to src/outlookCalendar/**/*(!preload).ts?(x) : Always use the centralized logger from `logger.ts` (outlookLog, outlookDebug, outlookError, outlookWarn, outlookEventDetail) instead of console.log() for Outlook Calendar module logging

Applied to files:

  • src/servers/preload/api.ts
📚 Learning: 2026-03-06T19:31:11.433Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-03-06T19:31:11.433Z
Learning: Applies to src/outlookCalendar/**/*.{ts,tsx} : Always use outlookError() for errors as it logs regardless of verbose mode settings, ensuring errors are always visible to users

Applied to files:

  • src/servers/preload/api.ts
🪛 ESLint
src/uploads/main.ts

[error] 3-3: 'dispatch' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 3-3: 'select' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 34-34: Insert ⏎·····

(prettier/prettier)

src/ui/main/rootWindow.ts

[error] 19-19: ../../uploads/main import should occur before import of ../actions

(import/order)

src/main.ts

[error] 39-39: ./uploads/main import should occur before import of ./userPresence/main

(import/order)

src/uploads/reducer.ts

[error] 12-12: Replace typeof·UPLOAD_STARTED·|·typeof·UPLOAD_FINISHED·|·typeof·UPLOAD_FAILED with ⏎····typeof·UPLOAD_STARTED·|·typeof·UPLOAD_FINISHED·|·typeof·UPLOAD_FAILED⏎··

(prettier/prettier)

🪛 markdownlint-cli2 (0.21.0)
NOTIFICATION_SOUND_FIX.md

[warning] 82-82: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

UPLOAD_TRACKING_FEATURE.md

[warning] 32-32: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 62-62: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 189-189: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (7)
src/servers/preload/api.ts (3)

13-17: LGTM!

The new upload tracking functions are correctly imported and follow the established pattern used by other preload modules in this file.


84-86: LGTM!

Type declarations for the upload tracking API methods are correctly added to RocketChatDesktopAPI. The signatures match the implementations in src/uploads/preload.ts.


122-124: LGTM!

The new methods are correctly wired into the RocketChatDesktop export object, following the same pattern as other API methods.

src/ui/main/rootWindow.ts (1)

264-269: LGTM!

The upload check is correctly integrated into the close handler. The guard returns early if checkActiveUploads() returns false (user cancelled), preventing the window from closing during active uploads.

src/main.ts (1)

79-79: LGTM!

The placement of setupUploadTracking() is correct — it's called after createMainReduxStore() (line 54), which is required since setupUploadTracking uses listen() that depends on the Redux store being initialized.

src/uploads/main.ts (2)

9-21: LGTM!

The upload tracking setup is well-implemented:

  • Listeners correctly increment/decrement the counter
  • Math.max(0, ...) prevents underflow for edge cases where finish/fail might be called without a corresponding start

23-38: LGTM with minor formatting fix needed.

The dialog logic is correct. Using showMessageBoxSync is appropriate here since it blocks the close event handler until the user responds.

Note: Prettier flags line 34 as too long. Consider breaking the message string.

📝 Optional formatting fix for line 34
   const choice = dialog.showMessageBoxSync(rootWindow, {
     type: 'warning',
     buttons: ['Cancel', 'Quit'],
     defaultId: 0,
     title: 'Upload in Progress',
-    message: 'A file upload is currently in progress. Are you sure you want to quit?',
+    message:
+      'A file upload is currently in progress. Are you sure you want to quit?',
   });

Comment on lines +10 to +13
**Root Cause**: The `silent` flag in notification options was not being properly enforced. The code used `silent ?? undefined` which meant:
- If `silent` was `false`, it became `undefined`
- Electron would then use the system default (play sound)
- This caused unwanted notification sounds
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the NOTIFICATION_SOUND_FIX.md file
fd -t f NOTIFICATION_SOUND_FIX.md

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 100


🏁 Script executed:

# Read the NOTIFICATION_SOUND_FIX.md file to verify the claims
cat -n NOTIFICATION_SOUND_FIX.md

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 11165


🏁 Script executed:

# Verify the JavaScript semantics with a quick test
node -e "console.log('false ?? undefined =', false ?? undefined)"

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 101


The root cause explanation and test expectations contradict the implementation.

Lines 10–13 incorrectly state that false ?? undefined becomes undefined. In JavaScript, the nullish coalescing operator returns the left operand if it is not null or undefined, so false ?? undefined evaluates to false.

Additionally, line 45 shows the fix changes this to silent !== false. When silent is false, this evaluates to false, meaning Electron should play the sound. However, Test 3 (lines 138–141) is titled "Non-Silent Notification (Explicitly with Sound)" but expects "WITHOUT sound," and the checklist at line 153 states "No sound plays when silent is false"—both directly contradicting the implemented logic.

Correct the root cause explanation to reflect actual JavaScript semantics and align the test expectations with the code behavior.

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

In `@NOTIFICATION_SOUND_FIX.md` around lines 10 - 13, Update the documentation and
tests to reflect correct JavaScript semantics and the implemented behavior:
change the root cause text to state that "false ?? undefined" evaluates to false
(the nullish coalescing operator returns the left operand if it's not
null/undefined), and explain that the fix uses "silent !== false" so non‑false
values (including undefined) will result in a silent-enabled behavior only when
explicitly false; then align Test 3 ("Non-Silent Notification (Explicitly with
Sound)" / the test titled with explicit sound) to expect a notification WITH
sound and update the checklist entry that currently reads "No sound plays when
silent is false" to assert that sound does play when silent is false.

Comment on lines +69 to +79
// Enable Kerberos/SPNEGO authentication for SAML on macOS
if (process.platform === 'darwin') {
app.commandLine.appendSwitch(
'auth-server-whitelist',
'*.local,*.domain.local'
);
app.commandLine.appendSwitch(
'auth-negotiate-delegate-whitelist',
'*.local,*.domain.local'
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and examine the structure around the target lines
cat -n src/app/main/app.ts | head -200

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 7076


🏁 Script executed:

# Verify function call order and when settings can be read
rg -A 5 "readSetting\(" src/app/main/app.ts | head -40

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 933


Gate the Kerberos whitelist behind the existing domain opt-in settings.

The hardcoded auth-server-whitelist and auth-negotiate-delegate-whitelist switches for *.local,*.domain.local are unconditionally enabled on macOS at startup, while NTLM credentials are gated behind isNTLMCredentialsEnabled and allowedNTLMCredentialsDomains checks later in setupApp(). This creates an inconsistent and broader credential surface for Kerberos/SPNEGO than for NTLM. Both authentication mechanisms should respect the same per-domain opt-in model.

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

In `@src/app/main/app.ts` around lines 69 - 79, The Kerberos/SPNEGO whitelist is
being set unconditionally on macOS via process.platform === 'darwin' and
app.commandLine.appendSwitch('auth-server-whitelist', ...) and
app.commandLine.appendSwitch('auth-negotiate-delegate-whitelist', ...); instead,
gate these calls behind the same domain opt-in checks used for NTLM in
setupApp(): consult isNTLMCredentialsEnabled and allowedNTLMCredentialsDomains
and only call app.commandLine.appendSwitch with the whitelisted domains when
isNTLMCredentialsEnabled is true and allowedNTLMCredentialsDomains contains the
target domains (or otherwise follows the same opt-in logic), ensuring identical
per-domain opt-in behavior for Kerberos/SPNEGO and NTLM.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/ui/main/rootWindow.ts (1)

264-299: ⚠️ Potential issue | 🟠 Major

Guard incomplete—other quit paths bypass upload check.

checkActiveUploads() only blocks the window 'close' listener (line 266). Other app-exit paths bypass it entirely:

  • Menu Cmd+Q and tray "Quit" call app.quit() directly without checking
  • Update installations call quitAndInstall() or destroy() windows after removing the close listener
  • Window-all-closed listener (app.ts:126) calls app.quit() unconditionally

Users can lose in-flight uploads via any quit path except the window close button.

🤖 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 264 - 299, The close-handler
currently uses checkActiveUploads() but other quit paths (direct app.quit(),
quitAndInstall(), window-all-closed handler, tray/menu Quit) bypass it; create a
single guarded quit flow (e.g., guardQuit or performQuit) that calls
checkActiveUploads() and only proceeds to
app.quit()/app.quitAndInstall()/destroy windows when uploads are clear, then
replace all direct calls to app.quit(), quitAndInstall(), and any window destroy
or window-all-closed logic to call this guarded function (also use it from the
rootWindow.close listener instead of calling app.quit() there); ensure symbols
referenced include checkActiveUploads, rootWindow.addListener('close', ...),
app.quit, quitAndInstall, and the window-all-closed handler so you update every
exit path to use the new guarded quit routine.
🤖 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/uploads/main.ts`:
- Around line 29-35: The warning message string passed to
dialog.showMessageBoxSync (in the call using rootWindow) is too long for
Prettier; split or wrap the message value across lines so it conforms to
line-length rules (e.g., convert the message to a multi-line template literal or
concatenate shorter strings) inside the same dialog.showMessageBoxSync call and
update only the message property so ESLint/Prettier will pass.
- Around line 7-25: Replace the scalar counter with a Set<string> to track
active upload ids: change activeUploadsCount to activeUploads (a Set), update
setupUploadTracking to listen for UPLOAD_STARTED and add payload.id to
activeUploads, and on UPLOAD_FINISHED and UPLOAD_FAILED remove payload.id from
the Set; update checkActiveUploads to return activeUploads.size === 0 (or
true/false accordingly). Ensure the listeners for UPLOAD_STARTED,
UPLOAD_FINISHED, and UPLOAD_FAILED extract the id from the event payload and
guard for missing ids so removals/additions are safe.

In `@UPLOAD_TRACKING_FEATURE.md`:
- Around line 189-200: The fenced code block in UPLOAD_TRACKING_FEATURE.md is
missing a language tag (triggering markdownlint MD040); update the
triple-backtick fence that wraps the ASCII UI diagram to include a language
identifier such as text (e.g., change ``` to ```text) so the block is explicitly
marked as plain text and the linter warning is resolved.

---

Outside diff comments:
In `@src/ui/main/rootWindow.ts`:
- Around line 264-299: The close-handler currently uses checkActiveUploads() but
other quit paths (direct app.quit(), quitAndInstall(), window-all-closed
handler, tray/menu Quit) bypass it; create a single guarded quit flow (e.g.,
guardQuit or performQuit) that calls checkActiveUploads() and only proceeds to
app.quit()/app.quitAndInstall()/destroy windows when uploads are clear, then
replace all direct calls to app.quit(), quitAndInstall(), and any window destroy
or window-all-closed logic to call this guarded function (also use it from the
rootWindow.close listener instead of calling app.quit() there); ensure symbols
referenced include checkActiveUploads, rootWindow.addListener('close', ...),
app.quit, quitAndInstall, and the window-all-closed handler so you update every
exit path to use the new guarded quit routine.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2cbbdcb8-82ee-44a4-8c22-050aabe2525a

📥 Commits

Reviewing files that changed from the base of the PR and between a9ef105 and f9f5ab0.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • UPLOAD_TRACKING_FEATURE.md
  • package.json
  • src/main.ts
  • src/notifications/main.ts
  • src/store/actions.ts
  • src/ui/main/rootWindow.ts
  • src/uploads/main.ts
💤 Files with no reviewable changes (1)
  • package.json
📜 Review details
🧰 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/main.ts
  • src/ui/main/rootWindow.ts
  • src/notifications/main.ts
  • src/store/actions.ts
  • src/uploads/main.ts
🧠 Learnings (2)
📓 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`.
📚 Learning: 2026-03-11T06:38:40.426Z
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`.

Applied to files:

  • src/ui/main/rootWindow.ts
🪛 ESLint
src/uploads/main.ts

[error] 34-34: Insert ⏎·····

(prettier/prettier)

🪛 markdownlint-cli2 (0.21.0)
UPLOAD_TRACKING_FEATURE.md

[warning] 189-189: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/ui/main/rootWindow.ts (1)

271-305: ⚠️ Potential issue | 🟠 Major

Move the upload check to only prompt when the app will actually quit.

The checkActiveUploads() call at the start shows a "Quit" dialog but executes before platform checks. On macOS or with tray enabled, the window only hides (uploads continue); on Windows with minimize enabled, it minimizes. Users are misled about what "Quit" means. Additionally, if execution reaches guardedQuit(), checkActiveUploads() runs again, allowing users to be prompted twice about the same uploads.

Restructure the listener: only call checkActiveUploads() on the path that actually quits (when all platform conditions that hide/minimize are false).

🤖 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 271 - 305, Remove the initial await
checkActiveUploads() at the top of the close listener and instead only call
await checkActiveUploads() on the path that actually performs a quit (i.e., just
before guardedQuit()). Keep the full-screen exit (rootWindow.isFullScreen /
leave-full-screen / setFullScreen(false)) and blur behavior as-is, evaluate
isTrayIconEnabled and isMinimizeOnCloseEnabled to decide hide/minimize, and if
those conditions would not short-circuit (hide or minimize), then call
checkActiveUploads(); if it returns false, return; otherwise call guardedQuit();
this prevents prompting on hide/minimize and avoids a double prompt before
guardedQuit().
🤖 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/ui/main/rootWindow.ts`:
- Around line 22-27: Three direct calls to app.quit() bypass the upload-check
flow; replace those direct quits (the Cmd/Ctrl+Q handler in menuBar.ts, the tray
quit in trayIcon.ts, and the window-all-closed handler in app.ts) so they invoke
guardedQuit() instead of calling app.quit() directly, and modify the before-quit
listener (which currently removes the window close listener) to stop removing
the close handler before upload checks run — alternatively move the upload check
into the before-quit flow so the check runs for all quit paths; ensure
references to guardedQuit, app.quit, the before-quit listener and the window
close handler are updated accordingly.

In `@src/uploads/main.ts`:
- Around line 34-44: getRootWindow() can reject when no window exists, so wrap
the call in a try/catch (or handle the rejection) and fall back to
undefined/null for the parent window before calling dialog.showMessageBoxSync;
this ensures the confirmation flow still runs instead of letting the promise
reject. Update the code that calls getRootWindow() (reference getRootWindow and
dialog.showMessageBoxSync in this module) to catch errors from getRootWindow(),
set rootWindow to undefined/null on failure, then call dialog.showMessageBoxSync
with that value and return the same boolean result (choice === 1).

In `@UPLOAD_TRACKING_FEATURE.md`:
- Around line 30-70: The documentation still describes counter-based tracking
(activeUploadsCount++, activeUploadsCount > 0 and underflow handling) but the
implementation uses a Set<string> (activeUploads) and dedupes by upload id via
notifyUploadStarted and notifyUploadFinished; update the diagrams and prose to
reflect this: replace counter increments/decrements with Set operations (add(id)
/ delete(id)), replace "activeUploadsCount > 0" checks with "activeUploads.size
> 0" or "activeUploads not empty", and remove any mentions of counter underflow
or numeric race conditions; also update the Close Prevention Flow to state
membership/size-based checks and reference the actual handlers
notifyUploadStarted, notifyUploadFinished and checkActiveUploads.

---

Outside diff comments:
In `@src/ui/main/rootWindow.ts`:
- Around line 271-305: Remove the initial await checkActiveUploads() at the top
of the close listener and instead only call await checkActiveUploads() on the
path that actually performs a quit (i.e., just before guardedQuit()). Keep the
full-screen exit (rootWindow.isFullScreen / leave-full-screen /
setFullScreen(false)) and blur behavior as-is, evaluate isTrayIconEnabled and
isMinimizeOnCloseEnabled to decide hide/minimize, and if those conditions would
not short-circuit (hide or minimize), then call checkActiveUploads(); if it
returns false, return; otherwise call guardedQuit(); this prevents prompting on
hide/minimize and avoids a double prompt before guardedQuit().
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eea27b2b-ba89-43ae-b72c-91f97572721b

📥 Commits

Reviewing files that changed from the base of the PR and between f9f5ab0 and d54c920.

📒 Files selected for processing (3)
  • UPLOAD_TRACKING_FEATURE.md
  • src/ui/main/rootWindow.ts
  • src/uploads/main.ts
📜 Review details
🧰 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/uploads/main.ts
  • src/ui/main/rootWindow.ts
🧠 Learnings (2)
📓 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`.
📚 Learning: 2026-03-11T06:38:40.426Z
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`.

Applied to files:

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

9-27: Nice change: upload tracking is now keyed by upload id.

Using a Set<string> here avoids the drift problems from duplicate start/finish events and keeps concurrent uploads isolated cleanly.

Comment on lines +22 to +27
export const guardedQuit = async (): Promise<void> => {
const canQuit = await checkActiveUploads();
if (canQuit) {
app.quit();
}
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -nP --type=ts '\bapp\.quit\s*\(' \
  src/ui/main/rootWindow.ts \
  src/ui/main/menuBar.ts \
  src/ui/main/trayIcon.ts \
  src/app/main/app.ts

echo
rg -n -C2 --type=ts 'before-quit|removeAllListeners\(|guardedQuit|checkActiveUploads' \
  src/ui/main/rootWindow.ts

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 1326


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check menuBar.ts quit path
echo "=== menuBar.ts context ==="
rg -n -B5 -A5 'app\.quit\(' src/ui/main/menuBar.ts | head -20

echo
echo "=== trayIcon.ts context ==="
rg -n -B5 -A5 'app\.quit\(' src/ui/main/trayIcon.ts | head -20

echo
echo "=== app.ts context ==="
rg -n -B5 -A5 'app\.quit\(' src/app/main/app.ts | head -20

echo
echo "=== Checking if close listener prevents window close when canClose=false ==="
sed -n '271,310p' src/ui/main/rootWindow.ts

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 2093


guardedQuit() and upload checks are bypassed by three direct quit paths.

Cmd/Ctrl+Q (menuBar.ts:118), tray quit (trayIcon.ts:156), and window-all-closed (app.ts:126) all call app.quit() directly. This triggers the before-quit listener at line 409, which removes the window's close listener before the upload check in the close handler (line 273) can run. Only window close via UI (clicking the X button) reaches the close listener; direct app.quit() paths skip both the upload prompt and guardedQuit() entirely.

🤖 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 22 - 27, Three direct calls to
app.quit() bypass the upload-check flow; replace those direct quits (the
Cmd/Ctrl+Q handler in menuBar.ts, the tray quit in trayIcon.ts, and the
window-all-closed handler in app.ts) so they invoke guardedQuit() instead of
calling app.quit() directly, and modify the before-quit listener (which
currently removes the window close listener) to stop removing the close handler
before upload checks run — alternatively move the upload check into the
before-quit flow so the check runs for all quit paths; ensure references to
guardedQuit, app.quit, the before-quit listener and the window close handler are
updated accordingly.

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

♻️ Duplicate comments (1)
UPLOAD_TRACKING_FEATURE.md (1)

165-186: ⚠️ Potential issue | 🟡 Minor

Keep the tracking model consistent throughout the doc.

Earlier sections describe Set-based tracking (add(id), delete(id), size > 0), but these sections switch back to a numeric counter, underflow handling, and activeUploadsCount. That makes the design doc self-contradictory and easy to implement against the wrong model.

Also applies to: 209-245, 275-292

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

In `@UPLOAD_TRACKING_FEATURE.md` around lines 165 - 186, The doc mixes two
tracking models—Set-based operations (add(id), delete(id), size) and a numeric
counter (activeUploadsCount, increment/decrement on
UPLOAD_STARTED/UPLOAD_FINISHED, underflow logic)—causing contradictions;
standardize on one model across the file by updating tests, examples, and
references to match the chosen model (either convert tests and functions like
UPLOAD_STARTED/UPLOAD_FINISHED and checkActiveUploads to operate on a Set with
add(id)/delete(id)/size > 0, or change earlier sections to describe a numeric
counter and remove Set APIs), and ensure all mentions (e.g., activeUploads,
activeUploadsCount, checkActiveUploads) use the same API and semantics
throughout the doc.
🤖 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/ui/main/rootWindow.ts`:
- Around line 271-278: The close handler deadlocks because it awaits
'leave-full-screen' before calling rootWindow.setFullScreen(false); change the
sequence in the rootWindow.addListener('close', ...) branch that checks
rootWindow.isFullScreen(): first call rootWindow.setFullScreen(false), then
preventDefault() and (optionally) await the once('leave-full-screen') event
before letting the close continue (or call rootWindow.close() after the event),
so the window actually exits fullscreen and the close path can complete.

---

Duplicate comments:
In `@UPLOAD_TRACKING_FEATURE.md`:
- Around line 165-186: The doc mixes two tracking models—Set-based operations
(add(id), delete(id), size) and a numeric counter (activeUploadsCount,
increment/decrement on UPLOAD_STARTED/UPLOAD_FINISHED, underflow logic)—causing
contradictions; standardize on one model across the file by updating tests,
examples, and references to match the chosen model (either convert tests and
functions like UPLOAD_STARTED/UPLOAD_FINISHED and checkActiveUploads to operate
on a Set with add(id)/delete(id)/size > 0, or change earlier sections to
describe a numeric counter and remove Set APIs), and ensure all mentions (e.g.,
activeUploads, activeUploadsCount, checkActiveUploads) use the same API and
semantics throughout the doc.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 29c83a5c-610c-4160-9e7c-554e57fa54cc

📥 Commits

Reviewing files that changed from the base of the PR and between d54c920 and 2d0400c.

📒 Files selected for processing (5)
  • UPLOAD_TRACKING_FEATURE.md
  • src/ui/main/menuBar.ts
  • src/ui/main/rootWindow.ts
  • src/ui/main/trayIcon.ts
  • src/uploads/main.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/uploads/main.ts
📜 Review details
🧰 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
  • src/ui/main/menuBar.ts
  • src/ui/main/trayIcon.ts
🧠 Learnings (2)
📓 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`.
📚 Learning: 2026-03-11T06:38:40.426Z
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`.

Applied to files:

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

155-156: Nice centralization of the tray quit path.

Routing the tray menu through guardedQuit() keeps the upload confirmation in the same quit flow as the other entry points.

src/ui/main/menuBar.ts (1)

117-118: Nice: Cmd/Ctrl+Q now uses the guarded quit flow.

This makes the menu shortcut respect the active-upload confirmation instead of quitting unconditionally.

Comment on lines +271 to +278
rootWindow.addListener('close', async (event) => {
if (rootWindow?.isFullScreen()) {
await new Promise<void>((resolve) =>
rootWindow.once('leave-full-screen', () => resolve())
);
rootWindow.setFullScreen(false);
event.preventDefault();
return;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't deadlock the fullscreen close path.

Line 273 waits for leave-full-screen before calling setFullScreen(false), so this branch never resolves and the window can't close from fullscreen.

Suggested fix
     rootWindow.addListener('close', async (event) => {
       if (rootWindow?.isFullScreen()) {
-        await new Promise<void>((resolve) =>
-          rootWindow.once('leave-full-screen', () => resolve())
-        );
-        rootWindow.setFullScreen(false);
         event.preventDefault();
+        rootWindow.setFullScreen(false);
         return;
       }
🤖 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 271 - 278, The close handler
deadlocks because it awaits 'leave-full-screen' before calling
rootWindow.setFullScreen(false); change the sequence in the
rootWindow.addListener('close', ...) branch that checks
rootWindow.isFullScreen(): first call rootWindow.setFullScreen(false), then
preventDefault() and (optionally) await the once('leave-full-screen') event
before letting the close continue (or call rootWindow.close() after the event),
so the window actually exits fullscreen and the close path can complete.

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