Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions apps/meteor/client/views/room/body/MediaCallRoom.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { isDirectMessageRoom } from '@rocket.chat/core-typings';
import type { PeerInfo } from '@rocket.chat/ui-voip';
import {
MediaCallRoomActivity,
usePeekMediaSessionState,
usePeekMediaSessionPeerInfo,
usePeekMediaSessionFeatures,
} from '@rocket.chat/ui-voip';
import { MediaCallRoomActivity, usePeekMediaSessionState, usePeekMediaSessionPeerInfo } from '@rocket.chat/ui-voip';
import type { ReactNode } from 'react';
import { memo } from 'react';

Expand All @@ -33,15 +28,8 @@ export type MediaCallRoomProps = {
const MediaCallRoom = ({ children }: MediaCallRoomProps) => {
const state = usePeekMediaSessionState();
const peerInfo = usePeekMediaSessionPeerInfo();
const features = usePeekMediaSessionFeatures();
const room = useRoom();

const screenShareEnabled = features.includes('screen-share');

if (!screenShareEnabled) {
return children;
}

if (state !== 'ongoing' || !isMediaCallRoom(room, peerInfo)) {
return children;
}
Expand Down
1 change: 0 additions & 1 deletion apps/meteor/ee/server/settings/voip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export function addSettings(): Promise<void> {
type: 'boolean',
public: true,
invalidValue: false,
alert: 'VoIP_TeamCollab_Screen_Sharing_Enabled_Alert',
i18nDescription: 'VoIP_TeamCollab_Screen_Sharing_Enabled_Description',
});

Expand Down
8 changes: 6 additions & 2 deletions apps/meteor/tests/e2e/page-objects/fragments/voice-calls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export class Widget {

private readonly transferModal: TransferModal;

constructor(page: Page) {
constructor(private readonly page: Page) {
this.transferModal = new TransferModal(page, page.getByRole('dialog', { name: 'Transfer call' }));
this.root = page.getByRole('dialog', { name: 'Voice call', exact: false });
this.callControls = new VoiceCallControls(this.root.getByRole('group'));
Expand Down Expand Up @@ -140,7 +140,11 @@ export class Widget {
return timerToSeconds(text);
}

async initiateCall(): Promise<void> {
async initiateCall(username?: string): Promise<void> {
if (username) {
await this.root.getByRole('textbox', { name: 'Enter username or number' }).fill(username);
await this.page.getByRole('listbox').getByRole('option', { name: username }).click();
Comment thread
gabriellsh marked this conversation as resolved.
}
await this.callControls.call.click();
await expect(this.callControls.cancel).toBeVisible();
}
Expand Down
40 changes: 14 additions & 26 deletions apps/meteor/tests/e2e/voice-calls-ee.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,10 @@ test.describe('Internal Voice Calls - Enterprise Edition', () => {
test('should initiate voice call from direct message', async () => {
const [user1, user2] = sessions;

await test.step('should open direct message with user2', async () => {
await user1.poHomeChannel.navbar.openChat('user2');
await expect(user1.poHomeChannel.composer.inputMessage).toBeVisible();
});

await test.step('initiate a voice call from room toolbar', async () => {
await user1.poHomeChannel.content.btnVoiceCall.click();
await test.step('establish call connection', async () => {
await user1.poHomeChannel.navbar.btnNewVoiceCall.click();
Comment thread
gabriellsh marked this conversation as resolved.
await expect(user1.poHomeChannel.voiceCalls.widget.content).toBeVisible();
await user1.poHomeChannel.voiceCalls.widget.initiateCall();
await user1.poHomeChannel.voiceCalls.widget.initiateCall(Users.user2.data.username);
});

await test.step('user2 accepts the call', async () => {
Expand All @@ -59,37 +54,34 @@ test.describe('Internal Voice Calls - Enterprise Edition', () => {
test('should handle call controls during active call', async () => {
const [user1, user2] = sessions;
await test.step('establish call connection', async () => {
await user1.poHomeChannel.navbar.openChat('user2');
await expect(user1.poHomeChannel.composer.inputMessage).toBeVisible();
await user1.poHomeChannel.content.btnVoiceCall.click();
await user1.poHomeChannel.voiceCalls.widget.initiateCall();
await user1.poHomeChannel.navbar.btnNewVoiceCall.click();
await user1.poHomeChannel.voiceCalls.widget.initiateCall(Users.user2.data.username);
await user2.poHomeChannel.voiceCalls.widget.acceptCall();
});

await test.step('should mute/unmute microphone from user1', async () => {
// User1 mutes microphone
await user1.poHomeChannel.voiceCalls.widget.muteSelf();

// User1 unmutes microphone
await user1.poHomeChannel.voiceCalls.widget.unmuteSelf();
});

await test.step('should put call on hold from user1', async () => {
// User1 puts call on hold
await user1.poHomeChannel.voiceCalls.widget.holdSelf();

// User1 resumes call
await user1.poHomeChannel.voiceCalls.widget.resumeSelf();
});

await test.step('should access dialpad during call', async () => {
// User1 opens dial pad
await user1.poHomeChannel.voiceCalls.widget.openDialpad();

// User1 closes dial pad
await user1.poHomeChannel.voiceCalls.widget.closeDialpad();
});

await test.step('should not display screen share button', async () => {
await expect(user1.poHomeChannel.voiceCalls.widget.controls.shareScreen).not.toBeVisible();
await expect(user2.poHomeChannel.voiceCalls.widget.controls.shareScreen).not.toBeVisible();
});

await test.step('should end the call from user1', async () => {
await user1.poHomeChannel.voiceCalls.widget.endCall();
await expect(user2.poHomeChannel.voiceCalls.widget.content).not.toBeVisible();
Expand All @@ -106,10 +98,8 @@ test.describe('Internal Voice Calls - Enterprise Edition', () => {
const user3 = { page: user3Context.page, poHomeChannel: new HomeChannel(user3Context.page) };

await test.step('establish call between user1 and user2', async () => {
await user1.poHomeChannel.navbar.openChat('user2');
await expect(user1.poHomeChannel.composer.inputMessage).toBeVisible();
await user1.poHomeChannel.content.btnVoiceCall.click();
await user1.poHomeChannel.voiceCalls.widget.initiateCall();
await user1.poHomeChannel.navbar.btnNewVoiceCall.click();
await user1.poHomeChannel.voiceCalls.widget.initiateCall(Users.user2.data.username);
await user2.poHomeChannel.voiceCalls.widget.acceptCall();
});

Expand Down Expand Up @@ -139,10 +129,8 @@ test.describe('Internal Voice Calls - Enterprise Edition', () => {
const [user1, user2] = sessions;

await test.step('user1 initiates call to user2', async () => {
await user1.poHomeChannel.navbar.openChat('user2');
await expect(user1.poHomeChannel.composer.inputMessage).toBeVisible();
await user1.poHomeChannel.content.btnVoiceCall.click();
await user1.poHomeChannel.voiceCalls.widget.initiateCall();
await user1.poHomeChannel.navbar.btnNewVoiceCall.click();
await user1.poHomeChannel.voiceCalls.widget.initiateCall(Users.user2.data.username);
});

await test.step('user2 declines the call', async () => {
Expand Down
2 changes: 0 additions & 2 deletions packages/i18n/src/locales/de.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,6 @@
"Call_ended_bold": "*Sprachanruf beendet*",
"Call_not_answered_bold": "*Sprachanruf nicht angenommen*",
"Call_failed_bold": "*Sprachanruf fehlgeschlagen*",
"Call_feature_unsupported": "Die Gegenseite unterst眉tzt dies nicht",
"Call_transferred_bold": "*Sprachanruf weitergeleitet*",
"Call_history": "Anrufverlauf",
"Call_history_provides_a_record_of_when_calls_took_place_and_who_joined": "In der Anrufliste wird festgehalten, wann Anrufe get盲tigt wurden und wer daran teilgenommen hat.",
Expand Down Expand Up @@ -5930,7 +5929,6 @@
"VoIP_TeamCollab_Mobile_Ringing_Enabled_Description": "Erm枚glicht Benutzern, Anrufe in der mobilen App zu t盲tigen und zu empfangen.",
"VoIP_TeamCollab_Screen_Sharing_Enabled": "Bildschirmfreigabe",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Description": "Erm枚glicht Benutzern, ihren Bildschirm w盲hrend Sprachanrufen freizugeben.",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Alert": "Die Bildschirmfreigabe befindet sich derzeit in der Beta-Phase.",
"VoIP_TeamCollab_Internal_SIP_Beta_Alert": "Das Weiterleiten interner Anrufe 眉ber SIP befindet sich in der Beta-Phase und wird nicht f眉r den Produktiveinsatz empfohlen.",
"VoIP_TeamCollab_Drachtio_Host": "Drachtio-Host",
"VoIP_TeamCollab_Drachtio_Port": "Drachtio-Port",
Expand Down
2 changes: 0 additions & 2 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,6 @@
"Call_ended_bold": "*Voice call ended*",
"Call_not_answered_bold": "*Voice call not answered*",
"Call_failed_bold": "*Voice call failed*",
"Call_feature_unsupported": "Other party doesn't support this",
"Call_transferred_bold": "*Voice call transferred*",
"Call_history": "Call history",
"Call_history_provides_a_record_of_when_calls_took_place_and_who_joined": "Call history provides a record of when calls took place and who joined.",
Expand Down Expand Up @@ -6060,7 +6059,6 @@
"VoIP_TeamCollab_Mobile_Ringing_Enabled_Description": "Allow users to make and receive calls on the mobile app.",
"VoIP_TeamCollab_Screen_Sharing_Enabled": "Screen sharing",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Description": "Allow users to share their screen during voice calls.",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Alert": "Screen sharing is currently in beta.",
"VoIP_TeamCollab_Internal_SIP_Beta_Alert": "Routing of internal calls through SIP is in beta and is not recommended for production use.",
"VoIP_TeamCollab_Drachtio_Host": "Drachtio Host",
"VoIP_TeamCollab_Drachtio_Port": "Drachtio Port",
Expand Down
2 changes: 0 additions & 2 deletions packages/i18n/src/locales/pt-BR.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,6 @@
"Call_ended_bold": "*Chamada de voz encerrada*",
"Call_not_answered_bold": "*Chamada de voz n茫o atendida*",
"Call_failed_bold": "*Falha na chamada de voz*",
"Call_feature_unsupported": "A outra parte n茫o suporta isso",
"Call_transferred_bold": "*Chamada de voz transferida*",
"Call_history": "Hist贸rico de chamadas",
"Call_history_provides_a_record_of_when_calls_took_place_and_who_joined": "O hist贸rico de chamadas fornece um registro de quando as chamadas foram realizadas e quem participou.",
Expand Down Expand Up @@ -5875,7 +5874,6 @@
"VoIP_TeamCollab_Mobile_Ringing_Enabled_Description": "Permitir que os usu谩rios fa莽am e recebam chamadas no aplicativo m贸vel.",
"VoIP_TeamCollab_Screen_Sharing_Enabled": "Compartilhamento de tela",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Description": "Permitir que os usu谩rios compartilhem a tela durante as chamadas de voz.",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Alert": "O compartilhamento de tela est谩 atualmente na vers茫o beta.",
"VoIP_TeamCollab_Internal_SIP_Beta_Alert": "O roteamento de chamadas internas por SIP est谩 em fase beta e n茫o 茅 recomendado para uso em produ莽茫o.",
"VoIP_TeamCollab_Drachtio_Host": "Host do Drachtio",
"VoIP_TeamCollab_Drachtio_Port": "Porta do Drachtio",
Expand Down
2 changes: 0 additions & 2 deletions packages/i18n/src/locales/sv.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,6 @@
"Call_ended_bold": "*R枚stsamtal avslutad*",
"Call_not_answered_bold": "*R枚stsamtal besvarades inte*",
"Call_failed_bold": "*R枚stsamtal misslyckades*",
"Call_feature_unsupported": "Andra parten st枚der inte detta",
"Call_transferred_bold": "*R枚stsamtal 枚verf枚rdes*",
"Call_history": "Samtalhistorik",
"Call_history_provides_a_record_of_when_calls_took_place_and_who_joined": "I samtalshistoriken samlas information om n盲r samtal 盲gt rum och vilka som deltog.",
Expand Down Expand Up @@ -5858,7 +5857,6 @@
"VoIP_TeamCollab_Mobile_Ringing_Enabled_Description": "Till氓t anv盲ndare att g枚ra och ta emot samtal i mobilappen.",
"VoIP_TeamCollab_Screen_Sharing_Enabled": "Sk盲rmdelning",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Description": "Till氓t anv盲ndare att dela sin sk盲rm under r枚stsamtal.",
"VoIP_TeamCollab_Screen_Sharing_Enabled_Alert": "Sk盲rmdelning 盲r f枚r n盲rvarande i beta.",
"VoIP_TeamCollab_Internal_SIP_Beta_Alert": "Routning av interna samtal genom SIP 盲r i beta och rekommenderas inte f枚r produktionsanv盲ndning.",
"VoIP_TeamCollab_Drachtio_Host": "Drachtio Host",
"VoIP_TeamCollab_Drachtio_Port": "Drachtio Port",
Expand Down
6 changes: 5 additions & 1 deletion packages/ui-voip/src/providers/MockedMediaCallProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { UserStatus } from '@rocket.chat/core-typings';
import type { CallFeature } from '@rocket.chat/media-signaling';
import { callFeatureList } from '@rocket.chat/media-signaling';
import type { ReactNode } from 'react';
import { useState } from 'react';

Expand All @@ -18,6 +20,7 @@ export type MockedMediaCallProviderProps = {
held?: boolean;
onClickDirectMessage?: () => void;
instanceProps?: Partial<MockedInstanceProviderProps>;
supportedFeatures?: readonly CallFeature[];
};

const MockedMediaCallProvider = ({
Expand All @@ -31,6 +34,7 @@ const MockedMediaCallProvider = ({
muted = false,
held = false,
instanceProps,
supportedFeatures = callFeatureList,
}: MockedMediaCallProviderProps) => {
const [peerInfo, setPeerInfo] = useState<PeerInfo | undefined>({
displayName: 'John Doe',
Expand Down Expand Up @@ -122,7 +126,7 @@ const MockedMediaCallProvider = ({
remoteMuted,
remoteHeld,
callId: undefined,
supportedFeatures: ['audio', 'screen-share', 'transfer', 'hold'],
supportedFeatures,
} as SessionState;

const contextValue = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const MediaCallRoomSection = ({ showChat, onToggleChat, user, containerHeight }:

const isPopout = currentViews.has('popout');

const { muted, held, peerInfo, connectionState, startedAt } = sessionState;
const { muted, held, peerInfo, connectionState, startedAt, supportedFeatures } = sessionState;

const shouldWrapCards = useShouldWrapCards(showChat, containerHeight);

Expand All @@ -69,6 +69,10 @@ const MediaCallRoomSection = ({ showChat, onToggleChat, user, containerHeight }:

useRegisterView('room');

const screenShareAvailable = supportedFeatures.includes('screen-share');
const holdAvailable = supportedFeatures.includes('hold');
const transferAvailable = supportedFeatures.includes('transfer');

if (!peerInfo || 'number' in peerInfo) {
return null;
}
Expand Down Expand Up @@ -108,21 +112,27 @@ const MediaCallRoomSection = ({ showChat, onToggleChat, user, containerHeight }:
}
>
<ToggleButton label={t('Mute')} icons={['mic', 'mic-off']} titles={[t('Mute'), t('Unmute')]} pressed={muted} onToggle={onMute} />
<ToggleButton
label={t('Hold')}
icons={['pause-shape-unfilled', 'pause-shape-unfilled']}
titles={[t('Hold'), t('Resume')]}
pressed={held}
onToggle={onHold}
/>
<ToggleButton
label={t('Share_screen')}
icons={['desktop-arrow-up', 'desktop-cross']}
titles={[t('Share_screen'), t('Stop_sharing_screen')]}
pressed={localScreen?.active ?? false}
onToggle={onToggleScreenSharing}
/>
<ActionButton disabled={connecting || reconnecting} label={t('Forward')} icon='arrow-forward' onClick={onForward} />
{holdAvailable && (
<ToggleButton
label={t('Hold')}
icons={['pause-shape-unfilled', 'pause-shape-unfilled']}
titles={[t('Hold'), t('Resume')]}
pressed={held}
onToggle={onHold}
/>
)}
{screenShareAvailable && (
<ToggleButton
label={t('Share_screen')}
icons={['desktop-arrow-up', 'desktop-cross']}
titles={[t('Share_screen'), t('Stop_sharing_screen')]}
pressed={localScreen?.active ?? false}
onToggle={onToggleScreenSharing}
/>
)}
{transferAvailable && (
<ActionButton disabled={connecting || reconnecting} label={t('Forward')} icon='arrow-forward' onClick={onForward} />
)}
<ActionButton label={t('Voice_call__user__hangup', { user: peerInfo.displayName })} icon='phone-off' danger onClick={onEndCall} />
</ActionStrip>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,17 @@ export const OngoingCallConnecting: Story = {
connectionState: 'CONNECTING',
},
};

export const OngoingCallDisabledAllFeatures: Story = {
args: {
state: 'ongoing',
supportedFeatures: [],
},
};

export const OngoingCallDisabledAllButScreenshare: Story = {
args: {
state: 'ongoing',
supportedFeatures: ['screen-share'],
},
};
34 changes: 16 additions & 18 deletions packages/ui-voip/src/views/MediaCallWidget/OngoingCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ const OngoingCall = () => {
const connecting = connectionState === 'CONNECTING';
const reconnecting = connectionState === 'RECONNECTING';

const transferDisabled = !supportedFeatures.includes('transfer');
const holdDisabled = !supportedFeatures.includes('hold');
const holdAvailable = supportedFeatures.includes('hold');
const transferAvailable = supportedFeatures.includes('transfer');

// TODO: Figure out how to ensure this always exist before rendering the component
if (!peerInfo) {
Expand Down Expand Up @@ -72,7 +72,7 @@ const OngoingCall = () => {
<Divider width='100%' />
</Box>
) : null}
<ButtonGroup large>
<ButtonGroup large align='center'>
<ActionButton
disabled={connecting || reconnecting}
icon='dialpad'
Expand All @@ -81,21 +81,19 @@ const OngoingCall = () => {
onClick={() => setOpen((open) => !open)}
/>
<ToggleButton label={t('Mute')} icons={['mic', 'mic-off']} titles={[t('Mute'), t('Unmute')]} pressed={muted} onToggle={onMute} />
<ToggleButton
label={t('Hold')}
icons={['pause-shape-unfilled', 'pause-shape-unfilled']}
titles={[holdDisabled ? t('Call_feature_unsupported') : t('Hold'), t('Resume')]}
pressed={held}
onToggle={onHold}
disabled={connecting || reconnecting || holdDisabled}
/>
<ActionButton
disabled={connecting || reconnecting || transferDisabled}
label={t('Forward')}
icon='arrow-forward'
title={transferDisabled ? t('Call_feature_unsupported') : t('Forward')}
onClick={onForward}
/>
{holdAvailable && (
<ToggleButton
label={t('Hold')}
icons={['pause-shape-unfilled', 'pause-shape-unfilled']}
titles={[t('Hold'), t('Resume')]}
pressed={held}
onToggle={onHold}
disabled={connecting || reconnecting}
/>
)}
{transferAvailable && (
<ActionButton disabled={connecting || reconnecting} label={t('Forward')} icon='arrow-forward' onClick={onForward} />
)}
<ActionButton
label={t('Voice_call__user__hangup', { user: 'userId' in peerInfo ? peerInfo.displayName : peerInfo.number })}
icon='phone-off'
Expand Down
Loading
Loading