[MM-55503] Update Calls Desktop API (#2937)
* Update Calls Desktop API * Update tests * Handle Calls links internally --------- Co-authored-by: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>
This commit is contained in:
parent
37829f11d2
commit
1613eb17bc
|
@ -38,30 +38,36 @@ export type DesktopAPI = {
|
|||
onBrowserHistoryPush: (listener: (pathName: string) => void) => () => void;
|
||||
sendBrowserHistoryPush: (path: string) => void;
|
||||
|
||||
// Calls widget
|
||||
openLinkFromCallsWidget: (url: string) => void;
|
||||
openScreenShareModal: () => void;
|
||||
onScreenShared: (listener: (sourceID: string, withAudio: boolean) => void) => () => void;
|
||||
callsWidgetConnected: (callID: string, sessionID: string) => void;
|
||||
onJoinCallRequest: (listener: (callID: string) => void) => () => void;
|
||||
resizeCallsWidget: (width: number, height: number) => void;
|
||||
focusPopout: () => void;
|
||||
leaveCall: () => void;
|
||||
sendCallsError: (err: string, callID?: string, errMsg?: string) => void;
|
||||
|
||||
// Calls plugin
|
||||
getDesktopSources: (opts: DesktopSourcesOptions) => Promise<DesktopCaptureSource[]>;
|
||||
onOpenScreenShareModal: (listener: () => void) => () => void;
|
||||
shareScreen: (sourceID: string, withAudi: boolean) => void;
|
||||
// Calls
|
||||
joinCall: (opts: {
|
||||
callID: string;
|
||||
title: string;
|
||||
rootID: string;
|
||||
channelURL: string;
|
||||
}) => Promise<{callID: string; sessionID: string}>;
|
||||
sendJoinCallRequest: (callId: string) => void;
|
||||
leaveCall: () => void;
|
||||
|
||||
callsWidgetConnected: (callID: string, sessionID: string) => void;
|
||||
resizeCallsWidget: (width: number, height: number) => void;
|
||||
|
||||
sendCallsError: (err: string, callID?: string, errMsg?: string) => void;
|
||||
onCallsError: (listener: (err: string, callID?: string, errMsg?: string) => void) => () => void;
|
||||
|
||||
getDesktopSources: (opts: DesktopSourcesOptions) => Promise<DesktopCaptureSource[]>;
|
||||
|
||||
openScreenShareModal: () => void;
|
||||
onOpenScreenShareModal: (listener: () => void) => () => void;
|
||||
|
||||
shareScreen: (sourceID: string, withAudio: boolean) => void;
|
||||
onScreenShared: (listener: (sourceID: string, withAudio: boolean) => void) => () => void;
|
||||
|
||||
sendJoinCallRequest: (callId: string) => void;
|
||||
onJoinCallRequest: (listener: (callID: string) => void) => () => void;
|
||||
|
||||
openLinkFromCalls: (url: string) => void;
|
||||
|
||||
focusPopout: () => void;
|
||||
|
||||
// Utility
|
||||
unregister: (channel: string) => void;
|
||||
}
|
||||
|
|
28
api-types/lib/index.d.ts
vendored
28
api-types/lib/index.d.ts
vendored
|
@ -1,3 +1,5 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
export declare type DesktopSourcesOptions = {
|
||||
types: Array<'screen' | 'window'>;
|
||||
thumbnailSize?: {
|
||||
|
@ -30,18 +32,6 @@ export declare type DesktopAPI = {
|
|||
onBrowserHistoryStatusUpdated: (listener: (canGoBack: boolean, canGoForward: boolean) => void) => () => void;
|
||||
onBrowserHistoryPush: (listener: (pathName: string) => void) => () => void;
|
||||
sendBrowserHistoryPush: (path: string) => void;
|
||||
openLinkFromCallsWidget: (url: string) => void;
|
||||
openScreenShareModal: () => void;
|
||||
onScreenShared: (listener: (sourceID: string, withAudio: boolean) => void) => () => void;
|
||||
callsWidgetConnected: (callID: string, sessionID: string) => void;
|
||||
onJoinCallRequest: (listener: (callID: string) => void) => () => void;
|
||||
resizeCallsWidget: (width: number, height: number) => void;
|
||||
focusPopout: () => void;
|
||||
leaveCall: () => void;
|
||||
sendCallsError: (err: string, callID?: string, errMsg?: string) => void;
|
||||
getDesktopSources: (opts: DesktopSourcesOptions) => Promise<DesktopCaptureSource[]>;
|
||||
onOpenScreenShareModal: (listener: () => void) => () => void;
|
||||
shareScreen: (sourceID: string, withAudi: boolean) => void;
|
||||
joinCall: (opts: {
|
||||
callID: string;
|
||||
title: string;
|
||||
|
@ -51,7 +41,19 @@ export declare type DesktopAPI = {
|
|||
callID: string;
|
||||
sessionID: string;
|
||||
}>;
|
||||
sendJoinCallRequest: (callId: string) => void;
|
||||
leaveCall: () => void;
|
||||
callsWidgetConnected: (callID: string, sessionID: string) => void;
|
||||
resizeCallsWidget: (width: number, height: number) => void;
|
||||
sendCallsError: (err: string, callID?: string, errMsg?: string) => void;
|
||||
onCallsError: (listener: (err: string, callID?: string, errMsg?: string) => void) => () => void;
|
||||
getDesktopSources: (opts: DesktopSourcesOptions) => Promise<DesktopCaptureSource[]>;
|
||||
openScreenShareModal: () => void;
|
||||
onOpenScreenShareModal: (listener: () => void) => () => void;
|
||||
shareScreen: (sourceID: string, withAudio: boolean) => void;
|
||||
onScreenShared: (listener: (sourceID: string, withAudio: boolean) => void) => () => void;
|
||||
sendJoinCallRequest: (callId: string) => void;
|
||||
onJoinCallRequest: (listener: (callID: string) => void) => () => void;
|
||||
openLinkFromCalls: (url: string) => void;
|
||||
focusPopout: () => void;
|
||||
unregister: (channel: string) => void;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
"use strict";
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
'use strict';
|
||||
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
Object.defineProperty(exports, '__esModule', {value: true});
|
||||
|
|
|
@ -81,25 +81,30 @@ const desktopAPI: DesktopAPI = {
|
|||
onBrowserHistoryPush: (listener) => createListener(BROWSER_HISTORY_PUSH, listener),
|
||||
sendBrowserHistoryPush: (path) => ipcRenderer.send(BROWSER_HISTORY_PUSH, path),
|
||||
|
||||
// Calls widget
|
||||
openLinkFromCallsWidget: (url) => ipcRenderer.send(CALLS_LINK_CLICK, url),
|
||||
openScreenShareModal: () => ipcRenderer.send(DESKTOP_SOURCES_MODAL_REQUEST),
|
||||
onScreenShared: (listener) => createListener(CALLS_WIDGET_SHARE_SCREEN, listener),
|
||||
callsWidgetConnected: (callID, sessionID) => ipcRenderer.send(CALLS_JOINED_CALL, callID, sessionID),
|
||||
onJoinCallRequest: (listener) => createListener(CALLS_JOIN_REQUEST, listener),
|
||||
resizeCallsWidget: (width, height) => ipcRenderer.send(CALLS_WIDGET_RESIZE, width, height),
|
||||
focusPopout: () => ipcRenderer.send(CALLS_POPOUT_FOCUS),
|
||||
leaveCall: () => ipcRenderer.send(CALLS_LEAVE_CALL),
|
||||
sendCallsError: (error) => ipcRenderer.send(CALLS_ERROR, error),
|
||||
|
||||
// Calls plugin
|
||||
getDesktopSources: (opts) => ipcRenderer.invoke(GET_DESKTOP_SOURCES, opts),
|
||||
onOpenScreenShareModal: (listener) => createListener(DESKTOP_SOURCES_MODAL_REQUEST, listener),
|
||||
shareScreen: (sourceID, withAudio) => ipcRenderer.send(CALLS_WIDGET_SHARE_SCREEN, sourceID, withAudio),
|
||||
// Calls
|
||||
joinCall: (opts) => ipcRenderer.invoke(CALLS_JOIN_CALL, opts),
|
||||
sendJoinCallRequest: (callId) => ipcRenderer.send(CALLS_JOIN_REQUEST, callId),
|
||||
leaveCall: () => ipcRenderer.send(CALLS_LEAVE_CALL),
|
||||
|
||||
callsWidgetConnected: (callID, sessionID) => ipcRenderer.send(CALLS_JOINED_CALL, callID, sessionID),
|
||||
resizeCallsWidget: (width, height) => ipcRenderer.send(CALLS_WIDGET_RESIZE, width, height),
|
||||
|
||||
sendCallsError: (err, callID, errMsg) => ipcRenderer.send(CALLS_ERROR, err, callID, errMsg),
|
||||
onCallsError: (listener) => createListener(CALLS_ERROR, listener),
|
||||
|
||||
getDesktopSources: (opts) => ipcRenderer.invoke(GET_DESKTOP_SOURCES, opts),
|
||||
openScreenShareModal: () => ipcRenderer.send(DESKTOP_SOURCES_MODAL_REQUEST),
|
||||
onOpenScreenShareModal: (listener) => createListener(DESKTOP_SOURCES_MODAL_REQUEST, listener),
|
||||
|
||||
shareScreen: (sourceID, withAudio) => ipcRenderer.send(CALLS_WIDGET_SHARE_SCREEN, sourceID, withAudio),
|
||||
onScreenShared: (listener) => createListener(CALLS_WIDGET_SHARE_SCREEN, listener),
|
||||
|
||||
sendJoinCallRequest: (callId) => ipcRenderer.send(CALLS_JOIN_REQUEST, callId),
|
||||
onJoinCallRequest: (listener) => createListener(CALLS_JOIN_REQUEST, listener),
|
||||
|
||||
openLinkFromCalls: (url) => ipcRenderer.send(CALLS_LINK_CLICK, url),
|
||||
|
||||
focusPopout: () => ipcRenderer.send(CALLS_POPOUT_FOCUS),
|
||||
|
||||
// Utility
|
||||
unregister: (channel) => ipcRenderer.removeAllListeners(channel),
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ import {BrowserWindow, desktopCapturer, systemPreferences, ipcMain} from 'electr
|
|||
|
||||
import ServerViewState from 'app/serverViewState';
|
||||
|
||||
import {CALLS_WIDGET_SHARE_SCREEN, UPDATE_SHORTCUT_MENU} from 'common/communication';
|
||||
import {CALLS_WIDGET_SHARE_SCREEN, BROWSER_HISTORY_PUSH, UPDATE_SHORTCUT_MENU} from 'common/communication';
|
||||
import {
|
||||
MINIMUM_CALLS_WIDGET_WIDTH,
|
||||
MINIMUM_CALLS_WIDGET_HEIGHT,
|
||||
|
@ -534,6 +534,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
|
||||
describe('handleGetDesktopSources', () => {
|
||||
const callsWidgetWindow = new CallsWidgetWindow();
|
||||
callsWidgetWindow.options = {callID: 'callID'};
|
||||
callsWidgetWindow.win = {
|
||||
webContents: {
|
||||
send: jest.fn(),
|
||||
|
@ -626,12 +627,8 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
it('should send error with no sources', async () => {
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([]);
|
||||
await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
|
@ -649,12 +646,8 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
|
||||
expect(systemPreferences.getMediaAccessStatus).toHaveBeenCalledWith('screen');
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledTimes(1);
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
@ -680,12 +673,8 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
expect(callsWidgetWindow.missingScreensharePermissions).toBe(true);
|
||||
expect(resetScreensharePermissionsMacOS).toHaveBeenCalledTimes(1);
|
||||
expect(openScreensharePermissionsSettingsMacOS).toHaveBeenCalledTimes(0);
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', {
|
||||
err: 'screen-permissions',
|
||||
});
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
|
||||
|
@ -799,6 +788,49 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('handleCallsLinkClick', () => {
|
||||
const view = {
|
||||
view: {
|
||||
server: {
|
||||
id: 'server-1',
|
||||
},
|
||||
},
|
||||
sendToRenderer: jest.fn(),
|
||||
};
|
||||
const callsWidgetWindow = new CallsWidgetWindow();
|
||||
callsWidgetWindow.mainView = view;
|
||||
callsWidgetWindow.win = {webContents: {id: 1}};
|
||||
|
||||
const focus = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
urlUtils.parseURL.mockImplementation((url) => {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
MainWindow.get.mockReturnValue({focus});
|
||||
ViewManager.getView.mockReturnValue(view);
|
||||
ViewManager.handleDeepLink = jest.fn();
|
||||
});
|
||||
|
||||
it('should switch server, focus and send history push event', () => {
|
||||
const url = '/team/channel';
|
||||
callsWidgetWindow.handleCallsLinkClick({sender: {id: 1}}, url);
|
||||
expect(ServerViewState.switchServer).toHaveBeenCalledWith('server-1');
|
||||
expect(focus).toHaveBeenCalled();
|
||||
expect(view.sendToRenderer).toBeCalledWith(BROWSER_HISTORY_PUSH, url);
|
||||
});
|
||||
|
||||
it('should call ViewManager.handleDeepLink for parseable urls', () => {
|
||||
const url = 'http://localhost:8065/team/channel';
|
||||
callsWidgetWindow.handleCallsLinkClick({sender: {id: 1}}, url);
|
||||
expect(ViewManager.handleDeepLink).toHaveBeenCalledWith(new URL(url));
|
||||
});
|
||||
});
|
||||
|
||||
describe('isOpen', () => {
|
||||
const callsWidgetWindow = new CallsWidgetWindow();
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ export class CallsWidgetWindow {
|
|||
// forwards to the main app
|
||||
ipcMain.on(DESKTOP_SOURCES_MODAL_REQUEST, this.forwardToMainApp(DESKTOP_SOURCES_MODAL_REQUEST));
|
||||
ipcMain.on(CALLS_ERROR, this.forwardToMainApp(CALLS_ERROR));
|
||||
ipcMain.on(CALLS_LINK_CLICK, this.forwardToMainApp(CALLS_LINK_CLICK));
|
||||
ipcMain.on(CALLS_LINK_CLICK, this.handleCallsLinkClick);
|
||||
ipcMain.on(CALLS_JOIN_REQUEST, this.forwardToMainApp(CALLS_JOIN_REQUEST));
|
||||
|
||||
// deprecated in favour of CALLS_LINK_CLICK
|
||||
|
@ -394,7 +394,7 @@ export class CallsWidgetWindow {
|
|||
}
|
||||
}
|
||||
|
||||
const screenPermissionsErrMsg = {err: 'screen-permissions'};
|
||||
const screenPermissionsErrArgs = ['screen-permissions', this.callID];
|
||||
|
||||
return desktopCapturer.getSources(opts).then((sources) => {
|
||||
let hasScreenPermissions = true;
|
||||
|
@ -409,8 +409,8 @@ export class CallsWidgetWindow {
|
|||
|
||||
if (!hasScreenPermissions || !sources.length) {
|
||||
log.info('missing screen permissions');
|
||||
view.sendToRenderer(CALLS_ERROR, screenPermissionsErrMsg);
|
||||
this.win?.webContents.send(CALLS_ERROR, screenPermissionsErrMsg);
|
||||
view.sendToRenderer(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
this.win?.webContents.send(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@ -426,8 +426,8 @@ export class CallsWidgetWindow {
|
|||
}).catch((err) => {
|
||||
log.error('desktopCapturer.getSources failed', err);
|
||||
|
||||
view.sendToRenderer(CALLS_ERROR, screenPermissionsErrMsg);
|
||||
this.win?.webContents.send(CALLS_ERROR, screenPermissionsErrMsg);
|
||||
view.sendToRenderer(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
this.win?.webContents.send(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
|
||||
return [];
|
||||
});
|
||||
|
@ -505,6 +505,31 @@ export class CallsWidgetWindow {
|
|||
};
|
||||
}
|
||||
|
||||
private handleCallsLinkClick = (event: IpcMainEvent, url: string) => {
|
||||
log.debug('handleCallsLinkClick', url);
|
||||
|
||||
if (!this.isCallsWidget(event.sender.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.serverID) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedURL = parseURL(url);
|
||||
if (parsedURL) {
|
||||
ViewManager.handleDeepLink(parsedURL);
|
||||
return;
|
||||
}
|
||||
|
||||
// If parsing above fails it means it's a relative path (e.g.
|
||||
// pointing to a channel).
|
||||
|
||||
ServerViewState.switchServer(this.serverID);
|
||||
MainWindow.get()?.focus();
|
||||
this.mainView?.sendToRenderer(BROWSER_HISTORY_PUSH, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
|
|
|
@ -20,5 +20,6 @@ export interface ExternalAPI {
|
|||
createListener(event: 'calls-widget-share-screen', listener: (sourceID: string, withAudio: boolean) => void): () => void;
|
||||
createListener(event: 'calls-join-request', listener: (callID: string) => void): () => void;
|
||||
createListener(event: 'calls-error', listener: (err: string, callID?: string, errMsg?: string) => void): () => void;
|
||||
createListener(event: 'calls-link-click', listener: (url: string) => void): () => void;
|
||||
createListener(event: 'desktop-sources-modal-request', listener: () => void): () => void;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue