feat(ui-voip): pre-fill media-call widget from desktop telephony deeplink#40751
feat(ui-voip): pre-fill media-call widget from desktop telephony deeplink#40751jeanfbrito wants to merge 4 commits into
Conversation
…link
Consume `window.RocketChatDesktop.onTelephonyCallRequested` (forwarded
`tel:`/`callto:` deeplinks and global-shortcut numbers from the Desktop
app) and pre-populate the media-call dial-pad with the number. The user
still starts the call.
- useDesktopTelephonyListener: routes by widget state — closed opens the
widget pre-filled, new sets the number, an in-progress call is ignored.
- usePeerAutocomplete: reflect an externally-selected `{ number }` peer in
the visible input (value is derived from userId only, so the field would
otherwise stay empty). Fires on peerInfo identity change, preserving
manual typing.
- desktop-api: declare optional `onTelephonyCallRequested` on
IRocketChatDesktop. Implemented in Rocket.Chat.Electron#3325.
Cold-start replay (app closed when the deeplink fires) is handled on the
Desktop side: the contract is replay-last-pending on subscribe.
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
🦋 Changeset detectedLatest commit: 4667ffa The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
WalkthroughAdds a desktop API callback and changes to media/voip hooks/providers so desktop telephony requests spawn or prefill a media-call PeerInfo; autocomplete syncs external numbers into the filter and media session teardown preserves user-driven "new" state. ChangesDesktop Telephony Call Request Integration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eea5bfd81a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/ui-voip/src/context/usePeerAutocomplete.ts (1)
42-45: 💤 Low valueConsider removing the inline comment.
Per coding guidelines, code comments should be avoided in TypeScript implementation. The effect's behavior can be understood from the conditional and effect dependencies.
🤖 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 `@packages/ui-voip/src/context/usePeerAutocomplete.ts` around lines 42 - 45, Remove the inline explanatory comment inside usePeerAutocomplete that describes the effect behavior (the block referencing peerInfo, value and number)—leave the effect and its conditionals intact (the logic that mirrors an externally-selected phone number into the input when peerInfo identity changes) but delete the comment text so only the implementation (including references to peerInfo, value and number) remains.packages/ui-voip/src/providers/useDesktopTelephonyListener.ts (1)
11-23: 💤 Low valueConsider removing the documentation comment.
Per coding guidelines, code comments should be avoided in TypeScript implementation. The hook's behavior can be documented externally or inferred from the type signature and implementation.
🤖 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 `@packages/ui-voip/src/providers/useDesktopTelephonyListener.ts` around lines 11 - 23, Remove the large documentation block comment above the useDesktopTelephonyListener hook; delete the multi-line JSDoc-style comment that describes deeplink/global-shortcut handling and routing behavior so the TypeScript implementation contains no large explanatory comments, leaving only the hook export (useDesktopTelephonyListener) and related runtime code (including references to window.RocketChatDesktop.onTelephonyCallRequested) intact; if any short clarification is still required for maintainers keep it as a one-line comment next to the hook definition rather than the current multi-line doc block.
🤖 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.
Nitpick comments:
In `@packages/ui-voip/src/context/usePeerAutocomplete.ts`:
- Around line 42-45: Remove the inline explanatory comment inside
usePeerAutocomplete that describes the effect behavior (the block referencing
peerInfo, value and number)—leave the effect and its conditionals intact (the
logic that mirrors an externally-selected phone number into the input when
peerInfo identity changes) but delete the comment text so only the
implementation (including references to peerInfo, value and number) remains.
In `@packages/ui-voip/src/providers/useDesktopTelephonyListener.ts`:
- Around line 11-23: Remove the large documentation block comment above the
useDesktopTelephonyListener hook; delete the multi-line JSDoc-style comment that
describes deeplink/global-shortcut handling and routing behavior so the
TypeScript implementation contains no large explanatory comments, leaving only
the hook export (useDesktopTelephonyListener) and related runtime code
(including references to window.RocketChatDesktop.onTelephonyCallRequested)
intact; if any short clarification is still required for maintainers keep it as
a one-line comment next to the hook definition rather than the current
multi-line doc block.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 022fec20-56e0-4386-b159-c3051581c5d5
📒 Files selected for processing (7)
.changeset/telephony-call-requested-desktop-api.mdpackages/desktop-api/src/index.tspackages/ui-voip/src/context/usePeerAutocomplete.spec.tsxpackages/ui-voip/src/context/usePeerAutocomplete.tspackages/ui-voip/src/providers/MediaCallViewProvider.tsxpackages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsxpackages/ui-voip/src/providers/useDesktopTelephonyListener.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). (5)
- GitHub Check: 📦 Build Packages
- GitHub Check: cubic · AI code reviewer
- GitHub Check: CodeQL-Build
- GitHub Check: Hacktron Security Check
- GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
packages/ui-voip/src/context/usePeerAutocomplete.spec.tsxpackages/ui-voip/src/context/usePeerAutocomplete.tspackages/ui-voip/src/providers/MediaCallViewProvider.tsxpackages/desktop-api/src/index.tspackages/ui-voip/src/providers/useDesktopTelephonyListener.tspackages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsx
🧠 Learnings (8)
📚 Learning: 2026-03-16T21:50:37.589Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39676
File: .changeset/migrate-users-register-openapi.md:3-3
Timestamp: 2026-03-16T21:50:37.589Z
Learning: For changes related to OpenAPI migrations in Rocket.Chat/OpenAPI, when removing endpoint types and validators from rocket.chat/rest-typings (e.g., UserRegisterParamsPOST, /v1/users.register) document this as a minor changeset (not breaking) per RocketChat/Rocket.Chat-Open-API#150 Rule 7. Note that the endpoint type is re-exposed via a module augmentation .d.ts in the consuming package (e.g., packages/web-ui-registration/src/users-register.d.ts). In reviews, ensure the changeset clearly states: this is a non-breaking change, the major version should not be bumped, and the changeset reflects a minor version bump. Do not treat this as a breaking change during OpenAPI migrations.
Applied to files:
.changeset/telephony-call-requested-desktop-api.md
📚 Learning: 2026-02-26T19:22:29.385Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.tsx:40-40
Timestamp: 2026-02-26T19:22:29.385Z
Learning: For TSX files in the UI VOIP package, ensure that when a media session state is 'unavailable', the voiceCall action is excluded from the actions object passed to CallHistoryActions so it does not render in the menu. This filtering should occur upstream (before getItems is called) to avoid tooltips or UI hints for unavailable actions. If there are multiple actions with availability states, implement a centralized helper to filter actions based on session state.
Applied to files:
packages/ui-voip/src/context/usePeerAutocomplete.spec.tsxpackages/ui-voip/src/providers/MediaCallViewProvider.tsxpackages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsx
📚 Learning: 2026-05-05T12:34:29.042Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 40331
File: packages/ui-voip/src/views/MediaCallWidget/OngoingCallWithScreen.tsx:69-69
Timestamp: 2026-05-05T12:34:29.042Z
Learning: In Rocket.Chat’s `packages/ui-voip` UI (e.g., media/call widgets), voice/media calls are only supported in Direct Message (DM) rooms. Rocket.Chat models a DM as a “room” with exactly two participants, so handlers like `onClickDirectMessage` are the correct destination—even when the UI text/element says “Open in room” (e.g., on the shared screen card/`StreamCard`). During review, don’t flag a “DM vs room” mismatch for these cases; they intentionally map to the same destination.
Applied to files:
packages/ui-voip/src/context/usePeerAutocomplete.spec.tsxpackages/ui-voip/src/providers/MediaCallViewProvider.tsxpackages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsx
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.
Applied to files:
packages/ui-voip/src/context/usePeerAutocomplete.spec.tsxpackages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsx
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.
Applied to files:
packages/ui-voip/src/context/usePeerAutocomplete.spec.tsxpackages/ui-voip/src/providers/MediaCallViewProvider.tsxpackages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsx
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.
Applied to files:
packages/ui-voip/src/context/usePeerAutocomplete.spec.tsxpackages/ui-voip/src/context/usePeerAutocomplete.tspackages/ui-voip/src/providers/MediaCallViewProvider.tsxpackages/desktop-api/src/index.tspackages/ui-voip/src/providers/useDesktopTelephonyListener.tspackages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsx
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
packages/ui-voip/src/context/usePeerAutocomplete.tspackages/desktop-api/src/index.tspackages/ui-voip/src/providers/useDesktopTelephonyListener.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
packages/ui-voip/src/context/usePeerAutocomplete.tspackages/desktop-api/src/index.tspackages/ui-voip/src/providers/useDesktopTelephonyListener.ts
🔇 Additional comments (7)
.changeset/telephony-call-requested-desktop-api.md (1)
1-6: LGTM!packages/desktop-api/src/index.ts (1)
66-66: LGTM!packages/ui-voip/src/providers/useDesktopTelephonyListener.ts (1)
24-49: LGTM!packages/ui-voip/src/providers/useDesktopTelephonyListener.spec.tsx (1)
1-107: LGTM!packages/ui-voip/src/context/usePeerAutocomplete.spec.tsx (1)
142-200: LGTM!packages/ui-voip/src/providers/MediaCallViewProvider.tsx (1)
16-16: LGTM!Also applies to: 47-48
packages/ui-voip/src/context/usePeerAutocomplete.ts (1)
46-50: ⚡ Quick winUpdate
filterwhenpeerInfoswitches away from{ number }
usePeerAutocompletesetsfilteronly whenpeerInfohasnumberand leavesfilterunchanged whenpeerInfobecomes{ userId }orundefined(lines 46-50), which can leave a stale phone-number term drivingpeerAutocomplete(debouncedFilter).usePeerAutocomplete.spec.tsxcoversnumber→numberupdates and “preserve manual typing while peerInfo is unchanged”, but there’s no test fornumber→userId/undefined, so the intended UX here isn’t locked in.Proposed fix (if you want the dropdown/search term cleared when not syncing a number)
useEffect(() => { if (peerInfo && 'number' in peerInfo) { setFilter(peerInfo.number); + } else { + setFilter(''); } }, [peerInfo]);
There was a problem hiding this comment.
1 issue found across 7 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #40751 +/- ##
===========================================
+ Coverage 69.76% 69.79% +0.03%
===========================================
Files 3327 3328 +1
Lines 123134 123175 +41
Branches 21963 21953 -10
===========================================
+ Hits 85902 85970 +68
+ Misses 33873 33845 -28
- Partials 3359 3360 +1
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
|
@coderabbitai Keeping the explanatory comments in |
When a number peer is pre-filled (e.g. from a desktop telephony deeplink), editing the dial-pad input only changed local filter state, leaving sessionState.peerInfo.number stale. onCall then dialed the original number instead of the one shown. Sync the selected peer on onChangeFilter/onKeypadPress for number-dial peers so the call dials what the user sees.
|
Tip For best results, initiate chat on the files or code changes.
✏️ Learnings added
|
On cold start the dial pad opened pre-filled then immediately closed, and the delivered number could be dropped. Two causes: the freshly-initialized media-call instance emits a no-active-call state right after init, which reset the widget from 'new' back to 'closed'; and the deeplink number is delivered consume-once, before the dial pad can act. - useDesktopTelephonyListener: register the handler once at mount and store the delivered number, applying it via a separate effect when the widget is idle. Delivery is consume-once, so registration must not be gated on subsystem readiness — only acting on the number is. - useMediaSession: a no-active-call instance emit no longer tears down an idle 'new' compose widget (e.g. a deeplink-prefilled dial pad); only real call teardown resets it.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4667ffa5be
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Clearing the dial-pad input re-selects a number peer with an empty number (the input and selected peer are mirrored on purpose). Guard onCall so an empty or whitespace-only number no longer requests media or attempts a SIP call — it is a no-op, consistent with the existing empty-peer case.
Proposed changes
Consumer side of the Desktop telephony deeplink feature. The Rocket.Chat Desktop app forwards
tel:/callto:deeplinks and global-shortcut phone numbers to the workspace viawindow.RocketChatDesktop.onTelephonyCallRequested. This PR consumes that signal and pre-populates the media-call dial-pad with the number — the user still presses Call.What's included
useDesktopTelephonyListener— subscribes toonTelephonyCallRequestedand routes by widget state:closed→ open the widget pre-filled with the numbernew→ widget already open/idle → set the numberusePeerAutocomplete— reflect an externally-selected{ number }peer in the visible input. The input value was derived fromuserIdonly, so a number set programmatically left the field empty. The new sync fires onpeerInfoidentity change, so manual typing is preserved.@rocket.chat/desktop-api— declare optionalonTelephonyCallRequestedonIRocketChatDesktop(payload{ phoneNumber, rawUri }). Implemented in Rocket.Chat.Electron#3325.Cold-start
When the Desktop app is closed at deeplink time, the event fires before the workspace mounts the listener. Buffering + replay-last-pending on subscribe is handled on the Desktop side; this consumer registers once on mount and handles the event whenever it arrives.
How to test
tel:/callto:deeplink or the global shortcut.Further comments
@rocket.chat/ui-voipis a private package → no changeset;@rocket.chat/desktop-apiis published → changeset included (minor).packages/ui-voip(co-located with the media-call provider) rather thanapps/meteor/client, and routes by widget state (toggleWidget/selectPeer) instead oftoggleWidgetonly.Summary by CodeRabbit
New Features
Behavior Changes
Tests