feat(menu): register CmdOrCtrl+, accelerator for Settings on all platforms#3336
Draft
jeanfbrito wants to merge 27 commits into
Draft
feat(menu): register CmdOrCtrl+, accelerator for Settings on all platforms#3336jeanfbrito wants to merge 27 commits into
jeanfbrito wants to merge 27 commits into
Conversation
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).
…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.
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.
…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
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
…at/Rocket.Chat.Electron into feat/telephony-deeplink
Updated the AvailableBrowsers, TelephonyGlobalShortcut, TelephonyServer, and ThemeAppearance components to include a marginBlock of 'x16' on the Field components for improved spacing and layout consistency.
…at/Rocket.Chat.Electron into feat/telephony-deeplink
Add `isTelephonyEnabled` setting (default off) to gate the telephony feature end-to-end: - New persisted `isTelephonyEnabled` boolean with action, reducer, and selector entry; surfaces as a master toggle in Settings > General. - `TelephonyServer` and `TelephonyGlobalShortcut` controls remain visible but disabled while the master toggle is off. - Global shortcut config selector returns the disabled config when the master toggle is off, so the existing watcher auto-unregisters any active accelerator on toggle-off. - `tel:`/`callto:` deep links short-circuit when the master toggle is off. - OS-level protocol registration for `tel`/`callto` moves out of the unconditional startup loop into a new reactive `setupTelephonyProtocolHandlers`, which calls `setAsDefaultProtocolClient` / `removeAsDefaultProtocolClient` in response to toggle changes. `rocketchat:` continues to register at startup unchanged. The macOS `Info.plist` and Linux `.desktop` files declared by electron-builder will still list the app as a candidate handler for `tel`/`callto`, but it will never be set as default unless the user opts in at runtime.
DMV-1 calls for a first-run prompt warning the user that Teams, Zoom,
or Skype may already own the tel:/callto: handler and that they must
confirm Rocket.Chat as default in OS settings themselves. Windows 10/11
hash-protects UserChoice so `setAsDefaultProtocolClient` only registers
the app as a candidate; without the prompt, users have no way to know
the OS silently kept the prior default.
Trigger every off->on transition of the master `isTelephonyEnabled`
toggle (not literal first run — the toggle is opt-in and is the natural
moment of user intent). Seed the transition tracker via a synchronous
`select` before subscribing, so returning users who reopen the app
with telephony already enabled are not re-prompted.
- New `TelephonyDefaultHandlerPromptModal` Fuselage modal (title, two
body paragraphs, "Open System Settings" + "Got it" buttons), mounted
in Shell next to the existing telephony modal.
- Three new void actions (`_OPEN`, `_CLOSE`, `_OPEN_SETTINGS_CLICKED`)
and a `telephonyDefaultHandlerPrompt` sub-reducer in `dialogs.ts`.
- Main-process `setupTelephonyDefaultHandlerPrompt` watches the master
toggle and dispatches OPEN on each off->on flip. Listens for the
settings-button click and routes per platform:
- Windows: `shell.openExternal('ms-settings:defaultapps')`
- macOS: opens FaceTime preferences (where tel: default lives)
- Linux: spawns `gnome-control-center default-apps` or
`kcmshell5/6 componentchooser` based on `XDG_CURRENT_DESKTOP`;
unknown DEs log a tip and rely on the modal's verbal instructions.
- i18n keys under `telephony.defaultHandlerPrompt`.
- 13 new tests covering transition detection, idempotency, teardown,
and each platform branch.
The renderer Jest project's `testMatch` requires at least one subdirectory between `src/<module>/` and the spec, so `src/app/PersistableValues.spec.ts` was silently skipped. Moved the file under `src/app/__tests__/`, fixed the relative import, and expanded the migration assertion to cover `isTelephonyEnabled`. Documented the constraint in `CLAUDE.md` so future renderer specs are placed correctly.
…forms Previously Settings had no accelerator field, so the macOS-convention Preferences shortcut (Cmd+,) was unbound and Linux/Windows users had no keyboard shortcut. Add 'CmdOrCtrl+,' so the standard shortcut works everywhere. Surfaced by external test tooling (mOSdat) that needed a deterministic keyboard path to open Settings on Linux.
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upstream Asks: RocketChat/Rocket.Chat.Electron
Formal proposal for RC Electron maintainers — suitable as a GitHub issue or PR cover letter.
1. Context
We maintain mOSdat — an automated multi-OS desktop UI test harness for
RocketChat/Rocket.Chat.Electron. We run full end-to-end functional scenarios against
built Electron packages on Ubuntu 22.04, Ubuntu 24.04, and Fedora 40 VMs, driven by a
VLM (vision-language model) for visual verification and
xdotool/xdg-openforinteraction.
The catalyst for these asks is the PR3325 telephony feature test campaign
(2026-05-16), which exposed three systemic friction points that cost us ~3.5 person-hours
of debug across 6 rerun cycles. We went 0/5 → 5/5 green only after building a
workaround layer (
--inject-config, ~340 LOC + 27 tests) to bypass the Settings UIentirely. The asks below would let us delete that layer.
2. Problem Statement
Ctrl+,accelerator on LinuxmenuBar.tsSettings item has noaccelerator:field; keypress silently ignored on Linuxlocalizecall returns coords; by the timexdotool clickfires, popup has dismissed; scenario retries loopalt+walt+menusequence when a form (login) holds focus; Settings never opensmosdat functional --inject-configlayer (I1: 5 flags, ~340 LOC, 27 tests) to write Redux-persisted values before app launchAll four issues share a root cause: the only supported path to set persisted
Electron state is through the in-app Settings UI, which is too transient and
keyboard-inaccessible for automated testing on Linux.
3. Three Asks (Ranked by ROI)
A. Register
CmdOrCtrl+,accelerator on the Settings menu itemImpact: Eliminates the
Ctrl+,-has-no-binding footgun on Linux. macOS usersalready expect this convention; Linux gets it as a free backfill.
Effort: 1 line in
menuBar.ts(or equivalent menu registration file). No behaviorchange — the click handler stays identical.
Blocks our current
alt+w → Down → Returnfallback nav, which we had to abandonbecause
alt+wis consumed by the webview when a form is focused.B. Add
data-testidattributes to key interactive elementsImpact: Eliminates VLM coordinate guessing for stable UI elements. Current
workflow: VLM
localizeis asked to find an element, returns pixel coordinates, thenxdotool clickfires. For transient elements (kebab popup, toggle buttons) this races.With stable
data-testidselectors we can usexdotool search --nameor Playwrightpage.getByTestId()instead.Effort: Approximately 1 day — add
data-testidstrings, no logic changes.Elements needed (intended DOM target in parentheses):
sidebar-kebab-button— the…/ kebab icon in the sidebar headersettings-menu-item— the Settings entry in the kebab/app menutelephony-toggle— the master enable/disable toggle in Telephony settingstelephony-shortcut-field— the global shortcut input fieldtelephony-server-dropdown— the preferred-server<select>or custom dropdown triggertelephony-server-select-modal— the root node of the server-selection modaltelephony-server-option— each server row inside that modal (index or name variant)remember-this-choice-checkbox— the checkbox in the server-select modalC. Optional state-seed CLI:
--load-state <json>and--export-state <path>Impact: Would eliminate the entire
mosdat --inject-configlayer. Instead ofwriting
config.jsonbefore launch (which requires knowing the correctmigrations.versionto avoid a migration wipe), we could pass Redux state directlyto the Electron binary.
Effort: Medium. Requires hooking into the Redux store boot sequence before the
first
persistReducerrehydration. Main risk: ordering — state must be seeded beforethe store hydrates, not after.
--load-state <json>: Merge the given JSON object into the persisted Redux stateat startup, before the store rehydrates. Allows tests to declare initial state without
touching the filesystem.
--export-state <path>: After the app reaches ready state, write the currentRedux-persisted slice to
<path>as JSON. Allows snapshot-based assertions.This is the biggest ask and we understand it may not fit near-term roadmap. A and B
alone would meaningfully reduce our test friction.
4. Concrete Code Suggestion for Ask A
In
menuBar.ts(or wherever the SettingsMenuItemis constructed), add theacceleratorfield:CmdOrCtrlmaps toCommandon macOS andControlon Linux/Windows.No platform guard needed — Electron handles the mapping.
If a global shortcut conflict exists on any platform,
CommandOrControl+,is thestandard Electron convention for Preferences (used by VS Code, Slack, Discord on macOS
and increasingly on Linux).
5. Concrete
data-testidTargets for Ask Bsidebar-kebab-button<button>that opens the sidebar overflow / kebab menusettings-menu-item<li>or<button>for the Settings entry in that menutelephony-toggle<input type="checkbox">or toggle root for the Enable Telephony settingtelephony-shortcut-field<input type="text">for the keyboard shortcut accelerator stringtelephony-server-dropdowntelephony-server-select-modal<div>of the TelephonyServerSelectModaltelephony-server-option<li>or<button>inside the modalremember-this-choice-checkbox<input type="checkbox">for the "remember this choice" optionWe are not prescribing attribute format —
data-testid,data-qa-id, or anyconsistent naming convention your codebase already uses would work.
6. What We'll Do If Accepted
If asks A and B are merged upstream we will open a follow-up mOSdat PR that:
alt+wmenu-navigation fallback from all PR3325-class scenarios(currently present in
3325-master-toggle.yaml,3325-global-shortcut.yaml, and3325-cold-start.yaml).localizecalls for kebab + Settings item with deterministicxdotool search --classnameor PlaywrightgetByTestIdsteps.If ask C is accepted we will open a further PR that replaces the entire
automation/setup/inject_config.pylayer (I1, ~340 LOC) with a thin wrapper thatemits
--load-stateinstead of writingconfig.jsondirectly, removing themigrations.versiondetection complexity entirely.7. Contact
docs/IMPROVEMENTS.md— items I1–I15We are happy to assist with any of these PRs if the direction is approved.