Skip to content

Click-to-Call: Dial Phone Numbers Directly from Any App#3325

Open
jeanfbrito wants to merge 57 commits into
masterfrom
feat/telephony-deeplink
Open

Click-to-Call: Dial Phone Numbers Directly from Any App#3325
jeanfbrito wants to merge 57 commits into
masterfrom
feat/telephony-deeplink

Conversation

@jeanfbrito
Copy link
Copy Markdown
Member

@jeanfbrito jeanfbrito commented May 8, 2026

Click-to-Call: Dial Phone Numbers Directly from Any App

Summary

You can now click phone number links (tel: and callto:) in any application — browser, email client, CRM, PDF viewer — and have Rocket.Chat open with the number ready to dial. The feature is fully opt-in: a master toggle in Settings > Voice & Video controls everything. When enabled, a new global keyboard shortcut lets you dial whatever phone number is on your clipboard from anywhere on your system.

What's New

Added

  • Click-to-Call from Any App: Clicking a phone number link anywhere on your system (browser, email, calendar, CRM, PDF) opens Rocket.Chat with the number pre-filled in the call widget. Works with both tel: and callto: links, in all common formats — international, dashed, parenthesized
  • Works When App Is Closed: Clicking a phone link launches Rocket.Chat if it isn't running, then opens the dial pad once the app finishes loading
  • Multi-Workspace Call Routing: When connected to multiple Rocket.Chat workspaces, a dialog lets you choose which workspace handles the call — with an option to remember your choice so you're not asked again
  • Global Dial Shortcut: Bind a keyboard shortcut (in Settings > Voice & Video) that focuses Rocket.Chat and opens the dial pad from anywhere. If a phone number is on your clipboard, it's pre-filled automatically
  • Preferred Workspace Setting: Choose a default workspace for all telephony calls, or leave it on "Auto" to be asked each time
  • Telephony Master Toggle: All telephony features are off by default. Enable them in the new Settings > Voice & Video tab. Disabling the toggle cleanly unregisters Rocket.Chat as the phone-link handler and removes the global shortcut
  • Conflict Detection: If another application is already registered as the phone-link handler when you turn on Telephony, Rocket.Chat asks you to confirm before taking over — so you won't silently break another app
  • Voice & Video Settings Tab: Phone-call and video-call controls are now grouped in a dedicated Settings > Voice & Video tab (previously scattered in Settings > General). The tab uses collapsible sections so you can focus on what you need
  • Default-Handler Diagnostics: An expandable panel in Settings > Voice & Video shows the real-time registration status of all phone-link checks. The panel header summarizes the status at a glance ("All checks pass", "2 issues", etc.). Use "Copy diagnostics" to share your configuration with support

Improved

  • Phone Number Compatibility: Phone numbers containing parentheses, dashes, dots, or percent-encoded characters now open correctly
  • Protocol Registration: Rocket.Chat registers as a handler for telephony URL schemes only when the Telephony toggle is enabled — a fresh install with the feature disabled does not claim those schemes
  • Settings Organization: Video call, screen-capture, and telephony controls are separated from unrelated general preferences into their own tab

Fixed

  • Special Character Phone Numbers: Numbers encoded as URL-escaped characters (e.g. %2B for +) now decode correctly before being passed to the dial pad
  • Server Selection Dialog: The workspace selection dialog now attaches correctly to the main window in all cases

Platform Notes

  • macOS: Phone links work from Safari, Mail, Contacts, and any app that renders tel: links. Rocket.Chat's Info.plist declares tel/callto so macOS lists it as a candidate even before the toggle is enabled — but it only becomes the default handler once the user enables Telephony
  • Windows: Registry keys are written by both NSIS and MSI installers; the runtime setAsDefaultProtocolClient call for tel/callto only fires when the toggle is on. Works from Outlook, Edge, Chrome, and other apps
  • Linux: Desktop entry includes MIME type handlers; works with xdg-open on both X11 and Wayland. The .desktop MimeType list is baked at install time, so the OS may list the app as a candidate before the toggle is enabled

How to Test

Voice & Video Tab

  1. Open Settings (Ctrl+, / Cmd+,)
  2. Verify a Voice & Video tab appears between Certificates and Developer
  3. Click it — verify it shows two collapsible sections: Telephony (master toggle, global shortcut, workspace picker) and Video calls (internal video, persistence, screen-capture)
  4. Verify Settings > General no longer contains any telephony or video-call controls

Master Toggle (kill switch)

  1. Fresh install — verify Telephony is off by default in Settings > Voice & Video
  2. Click a tel: link from another app — verify Rocket.Chat does not open the dial pad
  3. On Windows, check HKEY_CURRENT_USER\Software\Classes\tel — verify Rocket.Chat is not registered. On Linux, run xdg-mime query default x-scheme-handler/tel and verify it does not return Rocket.Chat
  4. Enable the Telephony toggle in Settings > Voice & Video — verify the Global Shortcut and Workspace controls become editable
  5. Repeat the tel: link click and protocol-handler checks — verify the dial pad opens and the OS now lists Rocket.Chat as the default handler
  6. Disable the toggle — verify the OS registration is removed and tel: clicks are ignored

Conflict Detection

  1. Ensure another app (e.g. Skype, FaceTime, or a browser) is already registered as the tel: handler
  2. Enable the Telephony toggle in Rocket.Chat Settings > Voice & Video
  3. Verify a dialog appears asking whether Rocket.Chat should take over phone links
  4. Dismiss the dialog — verify the previous handler remains active
  5. Re-enable and confirm — verify Rocket.Chat is now the handler

Click-to-Call (App Running)

  1. Open Rocket.Chat Desktop and ensure you're connected to a server
  2. In your browser, navigate to a page with a phone link (or type tel:+1234567890 in the address bar) and click it
  3. Verify Rocket.Chat comes to the foreground with the number ready in the call widget

Click-to-Call (App Closed)

  1. Quit Rocket.Chat Desktop completely
  2. Click a tel: or callto: link in any application
  3. Verify Rocket.Chat launches and the number appears in the call widget once loading is complete

Various Link Formats

  1. Test tel:+491234567890 — international format
  2. Test callto:+1-800-555-0199 — dashed format
  3. Test callto://+491234567890 — authority format (double-slash)
  4. Test tel:(049) 123-456.78 — formatted with parens and dots
  5. Verify all formats correctly extract the phone number

Multi-Workspace Selection

  1. Add two or more Rocket.Chat servers
  2. Click a phone link from an external application
  3. Verify a dialog appears asking which workspace handles the call
  4. Check "Remember this choice" and confirm
  5. Click another phone link — verify it goes directly to the remembered workspace
  6. Restart the app and click again — verify the remembered choice persists

Global Shortcut

  1. Enable the Telephony toggle
  2. Open Settings > Voice & Video and bind a shortcut in the Telephony Global Shortcut field
  3. Copy a phone number to your clipboard
  4. Press the bound shortcut — verify Rocket.Chat focuses and opens the dial pad pre-filled with the number
  5. Press the shortcut again with non-phone text on the clipboard — verify the dial pad opens empty

Preferred Workspace

  1. With two or more servers configured and Telephony enabled, open Settings > Voice & Video
  2. Pick a workspace in the Telephony Server dropdown
  3. Click a tel: link — verify it goes directly to that workspace without showing the selection dialog
  4. Change the dropdown back to "Auto" — verify the dialog reappears on the next call

Default-Handler Diagnostics

  1. Enable the Telephony toggle
  2. Expand the Default-handler diagnostics accordion in Settings > Voice & Video
  3. Verify all checks show color-coded status tags (blue = pass, red = fail, yellow = unknown)
  4. Verify the accordion header tag updates to match overall status ("All checks pass" / "N issues" / "N warnings")
  5. Verify the Platform footer shows the readable name (macOS / Windows / Linux)
  6. Click Copy diagnostics, paste into a text editor, and verify full handler paths appear in the JSON (even though they are hidden in the UI rows)

Related

  • Resolves DAMOVO-1
  • Depends on Rocket.Chat web app adding the dial pad listener (separate PR)

jeanfbrito added 2 commits May 8, 2026 18:43
Register Rocket.Chat as OS handler for callto: and tel: URL schemes
on Windows, macOS, and Linux. When a telephony link is clicked in any
app, RC launches or focuses and dispatches a typed IPC event to the
server webview with the parsed phone number.

- Register callto/tel schemes in electron-builder.json (all platforms)
- Add parseTelephonyLink() with number normalization and callto:// support
- Add performTelephonyCall() with multi-server dialog + remember choice
- Expose onTelephonyCallRequested callback on RocketChatDesktop API
- Persist telephonyPreferredServer via selectPersistableValues
- IPC listener registered before onReady to avoid cold-start race
Tests cover parseTelephonyLink (tel:/callto: protocols, number
normalization, callto:// double-slash format, extension syntax,
edge cases) and performTelephonyCall (0/1/2+ servers, preferred
server persistence, dialog remember checkbox).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds tel:/callto: deep-link handling: builder protocol config, multi-scheme registration, telephony URI parsing, server-selection and preference persistence, preload IPC plumbing to deliver telephony requests to renderers, UI settings and i18n, supported-version git-hash handling, and Jest tests.

Changes

Telephony Deep Links Support

Layer / File(s) Summary
Protocol Configuration & Schema
electron-builder.json
protocols converted to array with entries for "Rocket.Chat" (rocketchat) and "Rocket.Chat Telephony" (callto, tel). Linux MimeType updated to register scheme handlers.
Protocol Registration
src/app/main/app.ts
electronBuilderJsonInformation flattens configured schemes and performElectronStartup registers each scheme via app.setAsDefaultProtocolClient.
Redux State & Actions
src/telephony/actions.ts, src/telephony/reducers.ts, src/store/rootReducer.ts, src/store/actions.ts, src/app/selectors.ts
Adds TELEPHONY_PREFERRED_SERVER_SET, telephonyPreferredServer reducer, integrates slice into root reducer and action typing, and includes telephonyPreferredServer in persistable selectors.
Telephony Call Handling
src/deepLinks/main.ts
Exports TelephonyLink, parseTelephonyLink, and performTelephonyCall; prioritizes telephony parsing in processDeepLink; selects server (single/preferred/dialog), optionally persists preference, and sends telephony/call-requested with phoneNumber and rawUri.
IPC Preload Bridge & Listeners
src/preload.ts, src/telephony/preload.ts, src/servers/preload/api.ts
listenToTelephonyRequests() is started during preload; onTelephonyCallRequested exposed on RocketChatDesktop; payloads buffered until callback registration.
UI: Settings Integration
src/ui/components/SettingsView/features/TelephonyServer.tsx, src/ui/components/SettingsView/GeneralTab.tsx, src/ui/components/TelephonyServerSelectModal/*, src/ui/reducers/dialogs.ts, src/ui/components/Shell/index.tsx, src/i18n/*
Adds TelephonyServer component, server-select modal and server item, integrates into GeneralTab and Shell, wires dialog reducer/actions, and adds i18n strings across locales; dropdown persists preferred server selection.
UI Actions & Types
src/ui/actions.ts
Adds TELEPHONY_SERVER_SELECT_OPEN / TELEPHONY_SERVER_SELECT_CLOSE action constants and payload typings for open/close flows.
Supported Versions
src/servers/supportedVersions/main.ts, src/servers/supportedVersions/main.main.spec.ts
Add sha-prefixed git commit hash exception matching and dispatch WEBVIEW_GIT_COMMIT_HASH_CHANGED when commit hash available; tests added/updated.
Tests & Verification
src/deepLinks/main.spec.ts, src/servers/supportedVersions/main.main.spec.ts
Jest suites validate parse/perform flows, server selection branches, dialog remember behavior, webContents polling, deep-link routing differences, reducer unit tests, and supported-version behavior.
Docs / Misc
CLAUDE.md, .gitignore
Adds GitNexus guidance to CLAUDE.md and ignores .gitnexus.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

type: feature

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Click-to-Call: Dial Phone Numbers Directly from Any App' directly describes the main feature added in the pull request—telephony URL scheme handling (tel: and callto:) that enables phone-number deep linking from any application into Rocket.Chat Desktop.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • DAMOVO-1: Request failed with status code 401

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

🧹 Nitpick comments (1)
src/telephony/preload.ts (1)

18-29: ⚡ Quick win

Guard listenToTelephonyRequests against duplicate registration.

Calling listenToTelephonyRequests() more than once (e.g., in a hot-reload dev cycle or defensive initialization) stacks multiple ipcRenderer.on handlers. Each subsequent telephony/call-requested event would fire all of them, invoking telephonyCallback multiple times or repeatedly overwriting pendingPayload.

♻️ Proposed fix — idempotency guard
+let isListening = false;
+
 export const listenToTelephonyRequests = (): void => {
+  if (isListening) return;
+  isListening = true;
   ipcRenderer.on(
     'telephony/call-requested',
     (_event, payload: TelephonyPayload) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/telephony/preload.ts` around lines 18 - 29, listenToTelephonyRequests
currently registers an ipcRenderer.on handler every time it's called, causing
duplicate handlers; make it idempotent by guarding registration: add a
module-level flag (e.g., isTelephonyListenerRegistered) or remove existing
listeners for 'telephony/call-requested' before adding, then only call
ipcRenderer.on if not already registered; keep the handler logic using
telephonyCallback and pendingPayload unchanged and set the flag to true after
successful registration (or rely on removeAllListeners + add to ensure a single
handler).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/deepLinks/main.ts`:
- Around line 110-117: The dialog.showMessageBox call is missing the parent
window argument so the prompt isn't attached as a modal; update the call in
src/deepLinks/main.ts to pass the app's root window as the first argument (same
pattern used by askForServerAddition and warnAboutInvalidServerUrl) so the
dialog becomes a sheet/modal attached to the main window, keeping the existing
options ({ type, title, message, buttons, checkboxLabel, checkboxChecked }) as
the second parameter.

---

Nitpick comments:
In `@src/telephony/preload.ts`:
- Around line 18-29: listenToTelephonyRequests currently registers an
ipcRenderer.on handler every time it's called, causing duplicate handlers; make
it idempotent by guarding registration: add a module-level flag (e.g.,
isTelephonyListenerRegistered) or remove existing listeners for
'telephony/call-requested' before adding, then only call ipcRenderer.on if not
already registered; keep the handler logic using telephonyCallback and
pendingPayload unchanged and set the flag to true after successful registration
(or rely on removeAllListeners + add to ensure a single handler).
🪄 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: 705c516b-f939-4295-87b5-cd4aab10137e

📥 Commits

Reviewing files that changed from the base of the PR and between c2b584b and 154293f.

📒 Files selected for processing (12)
  • electron-builder.json
  • src/app/main/app.ts
  • src/app/selectors.ts
  • src/deepLinks/main.spec.ts
  • src/deepLinks/main.ts
  • src/preload.ts
  • src/servers/preload/api.ts
  • src/store/actions.ts
  • src/store/rootReducer.ts
  • src/telephony/actions.ts
  • src/telephony/preload.ts
  • src/telephony/reducers.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 (windows-latest)
  • GitHub Check: check (macos-latest)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript for all new code in this codebase unless explicitly told otherwise
Use Fuselage components from @rocket.chat/fuselage for all UI work — only create custom components when Fuselage doesn't provide the needed functionality
Check Theme.d.ts for valid color tokens when working with Fuselage components
Use optional chaining with fallbacks for platform-specific APIs instead of mocks (e.g., process.getuid?.() ?? 1000) to ensure code works across all platforms without requiring mocks
TypeScript code must use strict mode
Use React functional components with hooks instead of class components
Redux actions must follow the FSA (Flux Standard Action) pattern
Use camelCase for file naming
Use PascalCase for component file names (React components)
Write self-documenting code through clear naming — avoid unnecessary comments

Files:

  • src/store/actions.ts
  • src/telephony/reducers.ts
  • src/app/selectors.ts
  • src/telephony/preload.ts
  • src/preload.ts
  • src/store/rootReducer.ts
  • src/telephony/actions.ts
  • src/app/main/app.ts
  • src/servers/preload/api.ts
  • src/deepLinks/main.spec.ts
  • src/deepLinks/main.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.spec.ts file naming convention for Renderer process tests

Files:

  • src/deepLinks/main.spec.ts
**/*.{spec,main.spec}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{spec,main.spec}.ts: Tests must run and pass on Windows, macOS, and Linux CI environments — always verify cross-platform compatibility
Only mock Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) when defensive coding with optional chaining isn't possible

Files:

  • src/deepLinks/main.spec.ts
🔇 Additional comments (10)
src/telephony/actions.ts (1)

1-5: Clean action typing for preferred server state.

The constant and payload map are consistent and correctly model set/clear (string | null) behavior.

src/store/actions.ts (1)

12-12: Root action map integration is correct.

Including the telephony payload map in the global action type composition is done cleanly and keeps RootAction typing coherent.

Also applies to: 30-31

src/telephony/reducers.ts (1)

10-21: Reducer logic is straightforward and correct.

Initial state, set behavior, and reset support via null payload are all implemented as expected.

src/store/rootReducer.ts (1)

21-21: Root reducer wiring for telephony state looks good.

The new slice is properly registered and will be reflected in RootState.

Also applies to: 122-122

src/app/selectors.ts (1)

86-87: Persistable selector update is aligned with state changes.

Including telephonyPreferredServer here keeps persisted state in sync with the new reducer slice.

electron-builder.json (1)

5-8: Protocol packaging metadata update is consistent.

The new telephony schemes are correctly declared both in app protocol config and Linux MIME handlers.

Also applies to: 126-126

src/preload.ts (1)

11-11: Preload telephony listener wiring is solid.

The listener is integrated at an appropriate point in the preload startup sequence.

Also applies to: 68-68

src/app/main/app.ts (1)

43-47: Multi-scheme protocol registration is implemented correctly.

Flattening all configured schemes and registering each one at startup matches the new electron-builder.json protocol format.

Also applies to: 90-92

src/servers/preload/api.ts (1)

17-17: LGTM!

Clean extension of ExtendedIRocketChatDesktop following the established pattern. The type signature correctly matches src/telephony/preload.ts's export.

Also applies to: 53-55, 102-102

src/deepLinks/main.spec.ts (1)

131-335: LGTM! Thorough coverage across all server-selection branches.

The performTelephonyCall tests correctly sequence mockReturnValueOnce calls to separately control the servers and telephonyPreferredServer selectors, and the polling test places jest.useRealTimers() before the assertions so timers are always restored.

Comment thread src/deepLinks/main.ts Outdated
jeanfbrito added 4 commits May 8, 2026 19:15
…duplicate IPC listener

- Pass getRootWindow() as first argument to dialog.showMessageBox so
  the server selection prompt appears as a modal sheet attached to the
  main window (consistent with all other dialogs in the codebase)
- Add idempotency guard to listenToTelephonyRequests to prevent
  duplicate IPC handler registration during hot-reload dev cycles
Add GitNexus section with impact analysis, query, and context tools.
Gitignore .gitnexus index directory.
Dispatch WEBVIEW_GIT_COMMIT_HASH_CHANGED from server info response.
Match supportedVersions exceptions using sha:<hash> prefix against
the server's git commit hash for per-build version overrides.
Add TelephonyServer component to Settings > General tab with a
Select dropdown to choose which server handles tel:/callto: links.
Hidden when only one server exists. "Auto (ask each time)" option
clears the preference and reverts to dialog behavior.
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: 2

🧹 Nitpick comments (3)
src/servers/supportedVersions/main.ts (2)

237-238: 💤 Low value

Remove redundant trim() call.

The gitCommitHash variable is already trimmed on line 232, so the .trim() call on line 238 is redundant.

♻️ Proposed cleanup
   const normalizedGitCommitHash = gitCommitHash
-    .trim()
     .replace(/^sha-/, '')
     .toLowerCase();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/servers/supportedVersions/main.ts` around lines 237 - 238, The assignment
to normalizedGitCommitHash unnecessarily calls .trim() again; remove the
redundant .trim() so normalizedGitCommitHash is set directly from the
already-trimmed gitCommitHash (update the line that defines
normalizedGitCommitHash in main.ts to use gitCommitHash without calling
.trim()).

237-240: ⚡ Quick win

Consider case-insensitive prefix removal for robustness.

While server.gitCommitHash is unlikely to have an uppercase "SHA-" prefix in practice, using a case-insensitive regex makes the code more defensive and consistent with Git's case-insensitive treatment of commit hashes.

♻️ Proposed improvement
   const normalizedGitCommitHash = gitCommitHash
     .trim()
-    .replace(/^sha-/, '')
+    .replace(/^sha-/i, '')
     .toLowerCase();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/servers/supportedVersions/main.ts` around lines 237 - 240, Update the
normalization of gitCommitHash in normalizedGitCommitHash to remove a leading
"sha-" prefix case-insensitively: change the regex used on
gitCommitHash.trim().replace(/^sha-/, '') to a case-insensitive variant (e.g.,
use the /i flag) so any "SHA-", "Sha-", etc. prefixes are stripped consistently
before toLowerCase(); keep the rest of the flow intact.
src/servers/supportedVersions/main.main.spec.ts (1)

838-908: ⚡ Quick win

Consider adding test coverage for case variations.

While the current tests cover the core sha-prefix functionality, adding tests for case variations (e.g., "SHA-bb83777" or uppercase commit hashes) would improve robustness—especially if the case-sensitivity issues in main.ts are addressed.

📋 Suggested test cases
it('should support uppercase SHA- prefix in exception versions', async () => {
  const futureDate = new Date(Date.now() + 86400000);
  const supportedVersions: SupportedVersions = {
    enforcementStartDate: new Date(Date.now() - 86400000).toISOString(),
    timestamp: new Date().toISOString(),
    versions: [{ version: '8.4.0', expiration: futureDate }],
    exceptions: {
      domain: 'open.rocket.chat',
      uniqueId: 'test-unique-id',
      versions: [{ version: 'SHA-bb83777', expiration: futureDate }],
    },
  };

  const result = await isServerVersionSupported(
    {
      url: 'https://open.rocket.chat/',
      version: '8.5',
      title: 'Rocket.Chat Open',
      gitCommitHash: 'bb83777b51a42d',
    } as any,
    supportedVersions
  );

  expect(result.supported).toBe(true);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/servers/supportedVersions/main.main.spec.ts` around lines 838 - 908, Add
tests that cover case variations for SHA-prefixed exception matching: create
additional it(...) cases in the same spec that pass exception versions like
'SHA-bb83777' and commit hashes in uppercase (e.g., 'BB83777B51A42D') to ensure
isServerVersionSupported correctly normalizes/matches case; reference the
existing test setup (the SupportedVersions object and the
isServerVersionSupported call) and duplicate the pattern used in the two
existing tests but change the exception version prefix casing and commit-hash
casing, asserting supported === true for matching variations and supported ===
false for malformed/non-matching variations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/servers/supportedVersions/main.ts`:
- Line 221: The current if check using
trimmedExceptionVersion.startsWith('sha-') is case-sensitive and will miss
prefixes like "SHA-"; update the condition in the if that references
trimmedExceptionVersion to perform a case-insensitive check (e.g., compare
trimmedExceptionVersion.toLowerCase().startsWith('sha-') or use a
case-insensitive regex) so any "sha-" prefix in any case is recognized as a
git-hash exception.

In `@src/ui/components/SettingsView/features/TelephonyServer.tsx`:
- Around line 37-43: The options useMemo is calling new URL(s.url).hostname
which can throw on malformed URLs and crash rendering; update the mapping inside
useMemo (or compute options after the component's early return) to safely
extract hostname by catching URL parsing errors or validating s.url first—e.g.,
wrap the hostname extraction in a try/catch (or use a small helper like
safeHostname(s.url)) and fall back to s.url or an empty string if parsing fails;
ensure this change references the existing useMemo/options mapping and s.url to
avoid crashing the component.

---

Nitpick comments:
In `@src/servers/supportedVersions/main.main.spec.ts`:
- Around line 838-908: Add tests that cover case variations for SHA-prefixed
exception matching: create additional it(...) cases in the same spec that pass
exception versions like 'SHA-bb83777' and commit hashes in uppercase (e.g.,
'BB83777B51A42D') to ensure isServerVersionSupported correctly
normalizes/matches case; reference the existing test setup (the
SupportedVersions object and the isServerVersionSupported call) and duplicate
the pattern used in the two existing tests but change the exception version
prefix casing and commit-hash casing, asserting supported === true for matching
variations and supported === false for malformed/non-matching variations.

In `@src/servers/supportedVersions/main.ts`:
- Around line 237-238: The assignment to normalizedGitCommitHash unnecessarily
calls .trim() again; remove the redundant .trim() so normalizedGitCommitHash is
set directly from the already-trimmed gitCommitHash (update the line that
defines normalizedGitCommitHash in main.ts to use gitCommitHash without calling
.trim()).
- Around line 237-240: Update the normalization of gitCommitHash in
normalizedGitCommitHash to remove a leading "sha-" prefix case-insensitively:
change the regex used on gitCommitHash.trim().replace(/^sha-/, '') to a
case-insensitive variant (e.g., use the /i flag) so any "SHA-", "Sha-", etc.
prefixes are stripped consistently before toLowerCase(); keep the rest of the
flow intact.
🪄 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: b3c2f774-98af-42e8-bd5b-bfd1d5a03ff7

📥 Commits

Reviewing files that changed from the base of the PR and between ab816c0 and c83728f.

📒 Files selected for processing (7)
  • .gitignore
  • CLAUDE.md
  • src/i18n/en.i18n.json
  • src/servers/supportedVersions/main.main.spec.ts
  • src/servers/supportedVersions/main.ts
  • src/ui/components/SettingsView/GeneralTab.tsx
  • src/ui/components/SettingsView/features/TelephonyServer.tsx
✅ Files skipped from review due to trivial changes (3)
  • src/ui/components/SettingsView/GeneralTab.tsx
  • .gitignore
  • src/i18n/en.i18n.json
📜 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 (macos-latest)
  • GitHub Check: check (ubuntu-latest)
  • GitHub Check: check (windows-latest)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Fuselage components for all UI work; only create custom components when Fuselage doesn't provide what's needed. Import from @rocket.chat/fuselage

Check Theme.d.ts for valid color tokens when using Fuselage

Use optional chaining with fallbacks for platform-specific APIs instead of mocking (e.g., const uid = process.getuid?.() ?? 1000)

Use TypeScript strict mode

Use React functional components with hooks

Use camelCase for file naming

No unnecessary comments — self-documenting code through clear naming

Files:

  • src/ui/components/SettingsView/features/TelephonyServer.tsx
  • src/servers/supportedVersions/main.ts
  • src/servers/supportedVersions/main.main.spec.ts
**/*[A-Z]*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use PascalCase for component files

Files:

  • src/ui/components/SettingsView/features/TelephonyServer.tsx
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript for all new code unless explicitly told otherwise

Files:

  • src/servers/supportedVersions/main.ts
  • src/servers/supportedVersions/main.main.spec.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Name test files with *.spec.ts for renderer process tests

Files:

  • src/servers/supportedVersions/main.main.spec.ts
**/*.main.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Name test files with *.main.spec.ts for main process tests

Files:

  • src/servers/supportedVersions/main.main.spec.ts
**/*.{spec,main.spec}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Tests run on Windows, macOS, AND Linux CI — always verify cross-platform compatibility

Files:

  • src/servers/supportedVersions/main.main.spec.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: NEVER run `yarn build` directly in workspace directories — always use root commands
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: After building desktop-release-action, remove nested dist with: rm -rf workspaces/desktop-release-action/dist/dist
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Code signing for Windows builds uses Google Cloud KMS in two phases: build packages without signing first, then sign built packages using jsign
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Prefer editing existing files over creating new ones
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: NEVER commit or push without explicit user permission — 'fix this' does NOT mean 'commit it'
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: NEVER commit directly to master or dev — create a branch, test, open a PR
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Use worktrees to avoid disrupting the user's working directory when making changes
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Understand WHY code is written that way before changing it — working code is correct until proven otherwise
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Verify your work by running tests, checking types with npx tsc --noEmit, and demonstrating correctness
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Diagnose before iterating — analyze WHY approaches fail before trying the next one
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Always verify libraries by checking official docs and .d.ts files in node_modules/ — never assume props, tokens, or APIs
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Avoid subjective descriptors like 'smart', 'excellent', 'dumb' — use measurable descriptions in writing
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: Never invent metrics in PR descriptions or documentation — only include numbers from actual logs, error messages, or documented sources
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: PR descriptions should use straightforward language and focus on what changed and why
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: MUST run impact analysis with gitnexus_impact before editing any symbol
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: MUST run gitnexus_detect_changes before committing to verify changes only affect expected symbols
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: MUST warn the user if impact analysis returns HIGH or CRITICAL risk before proceeding with edits
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: NEVER edit a function, class, or method without first running gitnexus_impact on it
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: NEVER ignore HIGH or CRITICAL risk warnings from impact analysis
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-09T02:27:13.470Z
Learning: NEVER rename symbols with find-and-replace — use gitnexus_rename which understands the call graph
🪛 LanguageTool
CLAUDE.md

[style] ~118-~118: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...pected symbols and execution flows. - MUST warn the user if impact analysis retu...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~126-~126: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...L risk warnings from impact analysis. - NEVER rename symbols with find-and-replace — ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~127-~127: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...mewhich understands the call graph. - NEVER commit changes without runninggitnexu...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (9)
CLAUDE.md (1)

107-149: Solid addition: clear operational guardrails for GitNexus usage.

This section is actionable and well-structured (required steps, anti-patterns, and quick links), and it aligns with the workflow expectations for safe symbol changes and commit validation.

src/servers/supportedVersions/main.ts (3)

22-22: LGTM!

Import of WEBVIEW_GIT_COMMIT_HASH_CHANGED is properly used in the dispatch call at line 392.


390-398: LGTM!

The conditional dispatch of WEBVIEW_GIT_COMMIT_HASH_CHANGED correctly uses optional chaining to check for info.commit?.hash before dispatching, and the payload structure is consistent with Redux action patterns.


312-312: LGTM!

The refactoring to use isVersionExceptionForServer helper improves code organization and enables the new git-hash exception matching functionality.

src/servers/supportedVersions/main.main.spec.ts (5)

14-14: LGTM!

Import is correctly used in the test assertion at line 197.


179-203: LGTM!

Comprehensive test coverage for the git commit hash dispatch behavior. The test properly mocks server info with a commit hash and verifies the action payload structure.


796-796: LGTM!

Changing expiration to a Date instance improves type consistency with the expected SupportedVersions interface.


838-872: LGTM!

Excellent test coverage for the sha-prefixed exception matching feature. The test correctly verifies that a server with matching git commit hash is recognized as supported when an exception entry with sha- prefix exists.


874-908: LGTM!

Good negative test case verifying that malformed (empty) exception versions don't incorrectly match.

Comment thread src/servers/supportedVersions/main.ts Outdated
Comment thread src/ui/components/SettingsView/features/TelephonyServer.tsx
Comment thread src/deepLinks/main.ts Outdated
electron-builder v26 rejects MimeType as a direct child of
linux.desktop — only desktopActions and entry are valid properties.
Move it inside desktop.entry where it belongs.
Replace hardcoded English strings in the telephony dialog with i18n
t() calls and add telephonySelectServer translation keys to all 22
locale files.
@jeanfbrito jeanfbrito changed the title Click-to-Call: Dial Phone Numbers Directly from Any App DAMOVO-1: Click-to-Call: Dial Phone Numbers Directly from Any App May 11, 2026
@jeanfbrito jeanfbrito changed the title DAMOVO-1: Click-to-Call: Dial Phone Numbers Directly from Any App Click-to-Call: Dial Phone Numbers Directly from Any App May 11, 2026
@jeanfbrito
Copy link
Copy Markdown
Member Author

jeanfbrito commented May 11, 2026

PR 3325 TEL-QA matrix status - 2026-05-25

mOSdat OS target OS / version TEL-QA status
ubuntu2204 Ubuntu 22.04 ✅ Passed
ubuntu2404 Ubuntu 24.04 ✅ Passed
fedora42 Fedora 42 ✅ Passed
opensuse openSUSE Leap 16.0 ✅ Passed
manjaro Manjaro Linux 26.0.1 Anh-Linh ✅ Passed
windows10 Windows 10 ✅ Passed
windows11 Windows 11 ✅ Passed

All mOSdat-configured OS targets for the PR 3325 TEL-QA matrix are passing.

…selection

Replace dialog.showMessageBox with an in-app modal that shows server
favicons, names and hostnames — matching the sidebar appearance. Scales
to many servers via a scrollable list and includes a "remember this
choice" checkbox.

Also hardens the telephony flow:
- Mutex prevents concurrent tel: links from opening duplicate modals
- 120s timeout on modal promise prevents hanging if renderer crashes
- 10s timeout on webContents polling prevents infinite loop if server
  is removed between selection and view creation
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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/deepLinks/main.ts`:
- Around line 83-85: The code currently normalizes the telephony URI using the
raw value from url.pathname/url.href but doesn't decode percent-encoded
characters; update the logic that builds raw/phoneNumber so that you first run
decodeURIComponent on the raw input (derived from url.pathname or
url.href.slice(url.protocol.length)) before applying replace(/^\/+/, '') and
.replace(/[\s\-().]/g, '') so percent-encoded characters like %2B become "+";
adjust variables raw and phoneNumber in src/deepLinks/main.ts accordingly.

In `@src/ui/components/TelephonyServerSelectModal/index.tsx`:
- Around line 65-75: The checkbox label isn't programmatically associated with
the control: add an id to the CheckBox (e.g., "telephony-server-remember") and
set that id as htmlFor on the Box (which is acting as the label) so assistive
tech recognizes the relationship; then remove the Box onClick toggle (leave the
CheckBox onChange using setRememberChoice and keep the checked={rememberChoice})
to avoid double-toggling while preserving the existing rememberChoice and
setRememberChoice state handlers.

In `@src/ui/components/TelephonyServerSelectModal/ServerItem.tsx`:
- Around line 39-55: The interactive row in ServerItem is not
keyboard-accessible; update the Tile element (in ServerItem) to render as a
native button by adding is='button' (and type='button') so it receives keyboard
focus and activates with Enter/Space, keep the existing onClick={handleClick}
and hover handlers (setIsHovered/isHovered) intact, and ensure any custom styles
don't remove the native focus outline so keyboard users can see focus.
🪄 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: d79ae606-5abc-4b78-babf-4f36179624b2

📥 Commits

Reviewing files that changed from the base of the PR and between 6ddda80 and 9d0a4d3.

📒 Files selected for processing (7)
  • src/deepLinks/main.spec.ts
  • src/deepLinks/main.ts
  • src/ui/actions.ts
  • src/ui/components/Shell/index.tsx
  • src/ui/components/TelephonyServerSelectModal/ServerItem.tsx
  • src/ui/components/TelephonyServerSelectModal/index.tsx
  • src/ui/reducers/dialogs.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/deepLinks/main.spec.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

MANDATORY: Use Fuselage components from @rocket.chat/fuselage for all UI work. Only create custom components when Fuselage doesn't provide what's needed.

Check Theme.d.ts for valid color tokens when using Fuselage components.

Files:

  • src/ui/components/TelephonyServerSelectModal/index.tsx
  • src/ui/components/Shell/index.tsx
  • src/ui/actions.ts
  • src/ui/components/TelephonyServerSelectModal/ServerItem.tsx
  • src/ui/reducers/dialogs.ts
  • src/deepLinks/main.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use optional chaining with fallbacks for platform-specific APIs to ensure cross-platform compatibility without mocks: e.g., process.getuid?.() ?? 1000

Use TypeScript strict mode.

Use camelCase for file naming.

No unnecessary comments — self-documenting code through clear naming.

Always verify libraries — check official docs and .d.ts files in node_modules/. Never assume props, tokens, or APIs work without verification.

Avoid subjective descriptors ('smart', 'excellent', 'dumb') in code comments and documentation.

Use measurable descriptions in documentation and comments: 'reduced memory usage', 'improved by X%' instead of subjective terms.

Never invent metrics in code comments or documentation — no estimated time spent, no speculated user counts. Only include numbers from actual logs, error messages, or documented sources.

Files:

  • src/ui/components/TelephonyServerSelectModal/index.tsx
  • src/ui/components/Shell/index.tsx
  • src/ui/actions.ts
  • src/ui/components/TelephonyServerSelectModal/ServerItem.tsx
  • src/ui/reducers/dialogs.ts
  • src/deepLinks/main.ts
**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use React functional components with hooks.

Use PascalCase for component files.

Files:

  • src/ui/components/TelephonyServerSelectModal/index.tsx
  • src/ui/components/Shell/index.tsx
  • src/ui/components/TelephonyServerSelectModal/ServerItem.tsx
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

TypeScript codebase. Use TypeScript for all new code unless explicitly told otherwise.

Files:

  • src/ui/actions.ts
  • src/ui/reducers/dialogs.ts
  • src/deepLinks/main.ts
**/*action*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Redux actions must follow FSA (Flux Standard Action) pattern.

Files:

  • src/ui/actions.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: NEVER run `yarn build` directly in workspace directories — always use root commands to avoid creating incorrect output structures.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: After building `desktop-release-action`, remove the nested dist: `rm -rf workspaces/desktop-release-action/dist/dist` — the action only needs `workspaces/desktop-release-action/dist/index.js`.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: NEVER add `ewsjs/xhr` patches to `patches/` directory — use `.yarn/patches/` instead as configured in package.json to avoid CI failures due to conflicts.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Use patch-package for patching `kayahr/jest-electron-runner` with patches stored in `patches/` directory.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Always include all architectures for Windows builds: x64, ia32, arm64.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Code signing uses Google Cloud KMS in two phases: 1) Build packages without signing (empty env vars), 2) Sign built packages using jsign with Google Cloud KMS to prevent MSI build failures.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Prefer editing existing files over creating new ones.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: NEVER commit or push without explicit user permission — 'fix this' does NOT mean 'commit it'.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: NEVER commit directly to master or dev — create a branch, test, open a PR.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Read operations on git (status, diff, log) are always fine.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Show what will be committed before committing.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Use git worktrees to avoid disrupting the user's working directory when creating feature branches.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Understand before changing — understand WHY code is written that way. Working code is correct until proven otherwise. If unsure, ASK.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Verify your work — run tests, check types (`npx tsc --noEmit`), demonstrate correctness. Never mark a task done without proving it works.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Diagnose before iterating — when approaches fail, analyze WHY before trying the next one. Don't cycle through 3+ approaches blindly.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: PR descriptions should use straightforward language and focus on what changed and why.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: MUST run impact analysis before editing any symbol using gitnexus_impact to understand blast radius.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: MUST run `gitnexus_detect_changes()` before committing to verify changes only affect expected symbols.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: MUST warn the user if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: Use gitnexus_query to find execution flows instead of grepping when exploring unfamiliar code.
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron

Timestamp: 2026-05-12T00:50:52.404Z
Learning: NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph.
🔇 Additional comments (3)
src/ui/actions.ts (1)

159-160: LGTM!

Also applies to: 312-319

src/ui/components/Shell/index.tsx (1)

20-20: LGTM!

Also applies to: 106-106

src/ui/reducers/dialogs.ts (1)

4-9: LGTM!

Also applies to: 24-33, 35-40, 65-83, 100-108

Comment thread src/deepLinks/main.ts Outdated
Comment thread src/ui/components/TelephonyServerSelectModal/index.tsx Outdated
Comment thread src/ui/components/TelephonyServerSelectModal/ServerItem.tsx Outdated
Drop Margins wrapper from the modal and the Tile container from rows.
Title→message margin x8→x4, message→list x16→x12, rows now use
paddingBlock x6 / paddingInline x8 instead of Tile padding x12.
…ver modal

Adds 20 tests across three new spec files covering the telephony deep-link
runtime path that was previously only validated by deepLinks/main.spec.ts.

- src/telephony/renderer/preload.spec.ts (6 tests):
  IPC bridge state machine — listenToTelephonyRequests guard, pendingPayload
  buffer/replay, callback replacement, ipcRenderer.on registration.

- src/ui/components/SettingsView/features/TelephonyServer.spec.tsx (8 tests):
  Settings dropdown — hide when servers.length <= 1, option generation
  (auto + per-server), value binding to telephonyPreferredServer, dispatch
  of TELEPHONY_PREFERRED_SERVER_SET (null for auto, URL string otherwise),
  hostname fallback when server title missing.

- src/ui/components/TelephonyServerSelectModal/index.spec.tsx (6 tests):
  Modal flow — visibility gating on dialogs.telephonyServerSelect.isOpen,
  ServerItem rendering per server, dispatch payload shape on click with
  rememberChoice on/off, close dispatch with null payload, rememberChoice
  reset after close.

Adds @testing-library/react, @testing-library/jest-dom, and
@testing-library/dom (peer) as devDependencies. Fuselage Select and Dialog
are mocked at module level since they rely on React-Aria and native
<dialog>.showModal() respectively, which don't drive cleanly in
@kayahr/jest-electron-runner's renderer environment.

Spec paths follow the existing renderer testMatch convention:
src/<module>/<subdir>/<file>.spec.tsx — a flat src/telephony/preload.spec.ts
would be silently dropped by jest's testMatch globs.
tel:%2B15551234 left %2B encoded, producing phoneNumber '%2B15551234'
instead of '+15551234'. decodeURIComponent runs before strip pass;
malformed escapes return null (treated same as other invalid input).
…tive

Git commit hashes are conventionally case-insensitive. SHA-bb83777
should match same as sha-bb83777.
- TelephonyServer: extract hostname via safeHostname helper to prevent
  settings page crash on malformed server URLs (new URL() throws).
- TelephonyServerSelectModal: associate 'Remember this choice' label
  with checkbox via htmlFor/id for assistive tech.
- ServerItem: render Tile as native button (is='button' type='button')
  so keyboard users get Tab focus and Enter/Space activation.
* feat(telephony): add global shortcut to dial clipboard number

* fix(telephony): harden global shortcut handling

* refactor(telephony): share dialpad opener

* test(telephony): stabilize shortcut notification click (#3331)

* test(telephony): stabilize shortcut notification click (#3333)
* feat(telephony): add global shortcut to dial clipboard number

* fix(telephony): harden global shortcut handling

* refactor(telephony): share dialpad opener

* test(telephony): stabilize shortcut notification click
@github-actions
Copy link
Copy Markdown

jeanfbrito added 24 commits May 20, 2026 18:15
…copy

Introduces formatAcceleratorForDisplay so the shortcut input and
validation error render Cmd/Ctrl labels (with macOS-aware overrides)
instead of leaking the raw Electron accelerator syntax. The input
becomes capture-only (readOnly) so manual typing cannot desync from
the stored value, and the reserved-accelerator key is renamed to
reservedByApp with a new reservedByOS sibling. Several telephony
strings (modal, settings descriptions, diagnostics labels, select
server dialog) are rewritten for clarity and consistency.
…cing call

openTelephonyDialpad sent telephony/call-requested to the resolved
server's webContents but never updated currentView, so the call landed
in a workspace the user was not looking at. Dispatch
DEEP_LINKS_SERVER_FOCUSED (same action the rocketchat:// deep-link path
uses) with the resolved URL before contacting the webview so the
visible view follows the call across the single-server, preferred-server,
and modal-selection paths.
app.isDefaultProtocolClient on Windows reports true when the
RocketChat.tel / RocketChat.callto ProgIDs are registered, regardless
of which handler the user actually picked via Default Apps. This made
isDefault.tel pass even when Windows Settings still showed "Choose a
default" for tel. Read the authoritative
HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\URLAssociations\\<scheme>\\UserChoice
ProgId and compare it to RocketChat.<scheme> instead. Non-Windows
platforms keep using isDefaultProtocolClient.
…c messages

Windows blocks apps from writing the UserChoice ProgId, so the user
has to pick Rocket.Chat per scheme on the Default Apps page. Reword
the default-handler modal to spell out that each link type (tel and
callto) must be picked individually, mention that Windows itself
prevents apps from setting it, and rename the action button to point
at the Rocket.Chat default-apps page.

Diagnostic details for the isDefault check now read as user-facing
guidance instead of registry jargon: "Windows has not been told which
app to use..." when UserChoice is missing, and "Currently handled by
<app>. Open default apps to switch to Rocket.Chat." when another
handler is set.
body2 and the action button render on both Windows and Linux, so the
prior Windows-specific text leaked onto Linux installs. Split into
bodyWindows / bodyLinux and openSettingsWindows / openSettingsLinux
keys and pick the right pair in the modal based on process.platform.
…in policy flag

Windows blocks user-mode writes to UserChoice (UCPD since March 2024) so
the installer cannot make Rocket.Chat the default tel:/callto: handler
on its own. Ship the canonical DefaultAssociations XML alongside the
app and expose a new MSI public property SET_DEFAULT_ASSOCIATIONS=1
that, when explicitly passed, writes the GPO-equivalent registry value
(HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\System!DefaultAssociationsConfiguration)
pointing at the bundled XML. A sentinel under HKLM\\SOFTWARE\\Rocket.Chat\\InstallState
lets uninstall remove just the value we wrote without touching other
policies in that key.

Documents GPO / Intune / DISM paths so admins who already manage default
associations centrally use those channels instead of the installer flag
(real AD GPOs win at the next gpupdate cycle anyway).

A small spec guards against the XML and installer ProgIds drifting apart.
… upgrades

The cleanup CA also fires during RemoveExistingProducts on a major upgrade,
which would wipe HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\System!DefaultAssociationsConfiguration
and the sentinel before the new MSI installs. The new MSI only rewrites
when SET_DEFAULT_ASSOCIATIONS=1 is re-passed, and admins typically forget
that on routine upgrades — so policy would silently disappear after a
version bump. Gate the uninstall condition on UPGRADINGPRODUCTCODE="" so
cleanup runs only on real uninstalls.

Add an automated WiX-injection spec covering the property declaration,
deferred + Impersonate="no" CA attributes, type-51 immediate setters,
install/uninstall scheduling conditions (including the new upgrade
guard), placement of CustomAction/Property elements as children of
<Product>, and a regression check that backslashes in VBScript registry
paths render as single backslashes after JS template-literal expansion.
Read Windows UserChoiceLatest when UserChoice is absent and treat explicit Windows handler choices as authoritative so another app cannot be reported as pass through protocol registration fallback.

Hide the default-app CTA when diagnostics are healthy, add per-check settings actions for actionable failures, and cover the Windows/Linux diagnostic flows with focused tests.
Keep the telephony server selector aligned with the settings select width while preventing mid-word wrapping, and rename the prompt option to describe the ask-each-time behavior.
jeanfbrito added a commit to jeanfbrito/mOSdat that referenced this pull request May 24, 2026
…server, link formats, cold start

Five new functional scenarios fill the coverage gaps versus
RocketChat/Rocket.Chat.Electron#3325 (Click-to-Call):

- 3325-master-toggle.yaml: kill switch — OFF default, toggle ON,
  registration cycle, xdg-mime checks per state, sub-controls
  disabled when off.
- 3325-global-shortcut.yaml: configurable shortcut field, capture,
  Save/Clear, trigger from unfocused window, clipboard ≥3-digit
  prefill rule, empty dial pad on non-phone text, unregistration
  when master toggle disabled.
- 3325-auto-and-single-server.yaml: "Auto (ask each time)" resets
  persisted preference (modal reappears); single-server config
  hides dropdown and skips modal entirely.
- 3325-link-formats.yaml: tel: E.164, callto: dashed, callto://
  authority form, tel:(049) 123-456.78 parens+dots, tel: with
  ;ext=, malformed tel:abc graceful handling.
- 3325-cold-start.yaml: RC fully quit, tel: cold-launches RC and
  queues number until UI ready; toggle-OFF negative path verifies
  RC starts but ignores the deep-link arg.

All five use the canonical printf-array JSON pattern (not
heredocs) for servers.json/config.json to keep YAML scalar
indentation valid, the canonical TERM-loop pkill cleanup, and
localize: + click: true for Settings UI elements rather than
hardcoded coordinates.
jeanfbrito added a commit to jeanfbrito/mOSdat that referenced this pull request May 24, 2026
Covers PR RocketChat/Rocket.Chat.Electron#3325 QA flow TEL-QA-004
(telephony diagnostics panel). End-to-end AT-SPI: cleanup → userData
pre-stage → inline launch → server picker → kebab → Settings →
Voice & Video → enable Telephony (probe-by-modal) → expand diagnostics
→ Refresh → Copy → clipboard JSON assertion.

Live-verified PASS 27/27 against ubuntu2204@192.168.13.81 with the
fresh feat/telephony-deeplink PR build deployed.

- shared/scenarios/functional/3325-diagnostics-panel.yaml: new scenario
  (272 LOC). Inline-shell launch (routine bypass), userData inlined,
  probe-by-modal for Fuselage ToggleSwitch state (Got it modal fires
  only on OFF→ON), frame wait_for relaxed to role-only since post-
  pre-stage frame name is the workspace title.
- shared/routines/launch-rocketchat.yaml: XAUTH fallback chain
  (mutter → gdm → \$HOME/.Xauthority → bare DISPLAY=:0). Routine
  previously assumed Wayland mutter-Xwaylandauth file; silently failed
  on Xorg.
- docs/KNOWN_ISSUES.md: two new entries — Wayland-only XAUTH path and
  Fuselage ToggleSwitch action_name decoupled from React state.
- AGENTS.md, CLAUDE.md: GitNexus stats counter refresh (auto-regen
  after swiss-knife epic reindex).

Test counts: 1056 passed / 5 skipped / 3 xfailed / 0 failed.
The TelephonyServerSelectModal kept `rememberChoice` local state alive
across close/reopen cycles when the modal closed via a Redux state
update (e.g., external dispatch) rather than the local close handlers,
leaking the prior `true` value into the next dispatched payload.

Add a useEffect keyed on `isVisible` that resets `rememberChoice` when
the modal becomes hidden. The existing in-handler resets stay in place
for stores that do not propagate state changes (notably the stub
reducers in unit tests).

Fixes the failing `rememberChoice resets when the dialog is closed by
state update` spec that blocked all 6 PR #3325 CI jobs.
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.

3 participants