* add isCallsPluginEnabled; refactor Calls.PluginId
* revert Podfile.lock changes
(cherry picked from commit 912287fbe0)
Co-authored-by: Christopher Poile <cpoile@gmail.com>
This commit is contained in:
parent
b476fc00ff
commit
20d106b609
17 changed files with 131 additions and 28 deletions
|
|
@ -7,6 +7,7 @@
|
|||
import {RNFetchBlobFetchRepsonse} from 'rn-fetch-blob';
|
||||
import urlParse from 'url-parse';
|
||||
|
||||
import Calls from '@constants/calls';
|
||||
import {Options} from '@mm-redux/types/client4';
|
||||
|
||||
import * as ClientConstants from './constants';
|
||||
|
|
@ -286,12 +287,16 @@ export default class ClientBase {
|
|||
return `${this.getUserThreadsRoute(userId, teamId)}/${threadId}`;
|
||||
}
|
||||
|
||||
getPluginsRoute() {
|
||||
return `${this.getBaseRoute()}/plugins`;
|
||||
}
|
||||
|
||||
getAppsProxyRoute() {
|
||||
return `${this.url}/plugins/com.mattermost.apps`;
|
||||
}
|
||||
|
||||
getCallsRoute() {
|
||||
return `${this.url}/plugins/com.mattermost.calls`;
|
||||
return `${this.url}/plugins/${Calls.PluginId}`;
|
||||
}
|
||||
|
||||
// Client Helpers
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import ClientPlugins, {ClientPluginsMix} from '@client/rest/plugins';
|
||||
import ClientCalls, {ClientCallsMix} from '@mmproducts/calls/client/rest';
|
||||
import mix from '@utils/mix';
|
||||
|
||||
|
|
@ -36,7 +37,8 @@ interface Client extends ClientBase,
|
|||
ClientTeamsMix,
|
||||
ClientTosMix,
|
||||
ClientUsersMix,
|
||||
ClientCallsMix
|
||||
ClientCallsMix,
|
||||
ClientPluginsMix
|
||||
{}
|
||||
|
||||
class Client extends mix(ClientBase).with(
|
||||
|
|
@ -55,6 +57,7 @@ class Client extends mix(ClientBase).with(
|
|||
ClientTos,
|
||||
ClientUsers,
|
||||
ClientCalls,
|
||||
ClientPlugins,
|
||||
) {}
|
||||
|
||||
const Client4 = new Client();
|
||||
|
|
|
|||
19
app/client/rest/plugins.ts
Normal file
19
app/client/rest/plugins.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ClientPluginManifest} from '@mm-redux/types/plugins';
|
||||
|
||||
export interface ClientPluginsMix {
|
||||
getPluginsManifests: () => Promise<ClientPluginManifest[]>;
|
||||
}
|
||||
|
||||
const ClientPlugins = (superclass: any) => class extends superclass {
|
||||
getPluginsManifests = async () => {
|
||||
return this.doFetch(
|
||||
`${this.getPluginsRoute()}/webapp`,
|
||||
{method: 'get'},
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
export default ClientPlugins;
|
||||
|
|
@ -10,4 +10,6 @@ const RequiredServer = {
|
|||
PATCH_VERSION: 0,
|
||||
};
|
||||
|
||||
export default {RequiredServer, RefreshConfigMillis};
|
||||
const PluginId = 'com.mattermost.calls';
|
||||
|
||||
export default {RequiredServer, RefreshConfigMillis, PluginId};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Calls from '@constants/calls';
|
||||
|
||||
const WebsocketEvents = {
|
||||
POSTED: 'posted',
|
||||
POST_EDITED: 'post_edited',
|
||||
|
|
@ -53,18 +56,18 @@ const WebsocketEvents = {
|
|||
SIDEBAR_CATEGORY_UPDATED: 'sidebar_category_updated',
|
||||
SIDEBAR_CATEGORY_DELETED: 'sidebar_category_deleted',
|
||||
SIDEBAR_CATEGORY_ORDER_UPDATED: 'sidebar_category_order_updated',
|
||||
CALLS_CHANNEL_ENABLED: 'custom_com.mattermost.calls_channel_enable_voice',
|
||||
CALLS_CHANNEL_DISABLED: 'custom_com.mattermost.calls_channel_disable_voice',
|
||||
CALLS_USER_CONNECTED: 'custom_com.mattermost.calls_user_connected',
|
||||
CALLS_USER_DISCONNECTED: 'custom_com.mattermost.calls_user_disconnected',
|
||||
CALLS_USER_MUTED: 'custom_com.mattermost.calls_user_muted',
|
||||
CALLS_USER_UNMUTED: 'custom_com.mattermost.calls_user_unmuted',
|
||||
CALLS_USER_VOICE_ON: 'custom_com.mattermost.calls_user_voice_on',
|
||||
CALLS_USER_VOICE_OFF: 'custom_com.mattermost.calls_user_voice_off',
|
||||
CALLS_CALL_START: 'custom_com.mattermost.calls_call_start',
|
||||
CALLS_SCREEN_ON: 'custom_com.mattermost.calls_user_screen_on',
|
||||
CALLS_SCREEN_OFF: 'custom_com.mattermost.calls_user_screen_off',
|
||||
CALLS_USER_RAISE_HAND: 'custom_com.mattermost.calls_user_raise_hand',
|
||||
CALLS_USER_UNRAISE_HAND: 'custom_com.mattermost.calls_user_unraise_hand',
|
||||
CALLS_CHANNEL_ENABLED: `custom_${Calls.PluginId}_channel_enable_voice`,
|
||||
CALLS_CHANNEL_DISABLED: `custom_${Calls.PluginId}_channel_disable_voice`,
|
||||
CALLS_USER_CONNECTED: `custom_${Calls.PluginId}_user_connected`,
|
||||
CALLS_USER_DISCONNECTED: `custom_${Calls.PluginId}_user_disconnected`,
|
||||
CALLS_USER_MUTED: `custom_${Calls.PluginId}_user_muted`,
|
||||
CALLS_USER_UNMUTED: `custom_${Calls.PluginId}_user_unmuted`,
|
||||
CALLS_USER_VOICE_ON: `custom_${Calls.PluginId}_user_voice_on`,
|
||||
CALLS_USER_VOICE_OFF: `custom_${Calls.PluginId}_user_voice_off`,
|
||||
CALLS_CALL_START: `custom_${Calls.PluginId}_call_start`,
|
||||
CALLS_SCREEN_ON: `custom_${Calls.PluginId}_user_screen_on`,
|
||||
CALLS_SCREEN_OFF: `custom_${Calls.PluginId}_user_screen_off`,
|
||||
CALLS_USER_RAISE_HAND: `custom_${Calls.PluginId}_user_raise_hand`,
|
||||
CALLS_USER_UNRAISE_HAND: `custom_${Calls.PluginId}_user_unraise_hand`,
|
||||
};
|
||||
export default WebsocketEvents;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,12 @@ import {getCurrentChannel} from '@mm-redux/selectors/entities/channels';
|
|||
import {getCurrentUserRoles} from '@mm-redux/selectors/entities/users';
|
||||
import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin} from '@mm-redux/utils/user_utils';
|
||||
import {loadConfig} from '@mmproducts/calls/store/actions/calls';
|
||||
import {getConfig, isCallsExplicitlyDisabled, isCallsExplicitlyEnabled} from '@mmproducts/calls/store/selectors/calls';
|
||||
import {
|
||||
getConfig,
|
||||
isCallsExplicitlyDisabled,
|
||||
isCallsExplicitlyEnabled,
|
||||
isCallsPluginEnabled,
|
||||
} from '@mmproducts/calls/store/selectors/calls';
|
||||
|
||||
// Check if calls is enabled. If it is, then run fn; if it isn't, show an alert and set
|
||||
// msgPostfix to ' (Not Available)'.
|
||||
|
|
@ -45,12 +50,15 @@ export const useCallsChannelSettings = () => {
|
|||
const dispatch = useDispatch();
|
||||
const config = useSelector(getConfig);
|
||||
const currentChannel = useSelector(getCurrentChannel);
|
||||
const pluginEnabled = useSelector(isCallsPluginEnabled);
|
||||
const explicitlyDisabled = useSelector(isCallsExplicitlyDisabled);
|
||||
const explicitlyEnabled = useSelector(isCallsExplicitlyEnabled);
|
||||
const roles = useSelector(getCurrentUserRoles);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(loadConfig());
|
||||
if (pluginEnabled) {
|
||||
dispatch(loadConfig());
|
||||
}
|
||||
}, []);
|
||||
|
||||
const isDirectMessage = currentChannel.type === General.DM_CHANNEL;
|
||||
|
|
@ -58,9 +66,11 @@ export const useCallsChannelSettings = () => {
|
|||
const isAdmin = checkIsAdmin(roles);
|
||||
const isChannelAdmin = isAdmin || checkIsChannelAdmin(roles);
|
||||
|
||||
const enabled = (explicitlyEnabled || (!explicitlyDisabled && config.DefaultEnabled));
|
||||
const enabled = pluginEnabled && (explicitlyEnabled || (!explicitlyDisabled && config.DefaultEnabled));
|
||||
let canEnableDisable;
|
||||
if (config.AllowEnableCalls) {
|
||||
if (!pluginEnabled) {
|
||||
canEnableDisable = false;
|
||||
} else if (config.AllowEnableCalls) {
|
||||
canEnableDisable = isDirectMessage || isGroupMessage || isChannelAdmin;
|
||||
} else {
|
||||
canEnableDisable = isAdmin;
|
||||
|
|
|
|||
|
|
@ -24,4 +24,5 @@ export default keyMirror({
|
|||
SET_SCREENSHARE_URL: null,
|
||||
SET_SPEAKERPHONE: null,
|
||||
RECEIVED_CONFIG: null,
|
||||
RECEIVED_PLUGIN_ENABLED: null,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ jest.mock('@client/rest', () => ({
|
|||
DefaultEnabled: true,
|
||||
last_retrieved_at: 1234,
|
||||
})),
|
||||
getPluginsManifests: jest.fn(() => (
|
||||
[
|
||||
{id: 'playbooks'},
|
||||
{id: 'com.mattermost.calls'},
|
||||
]
|
||||
)),
|
||||
enableChannelCalls: jest.fn(() => null),
|
||||
disableChannelCalls: jest.fn(() => null),
|
||||
},
|
||||
|
|
@ -150,6 +156,7 @@ describe('Actions.Calls', () => {
|
|||
|
||||
it('batchLoadConfig', async () => {
|
||||
await store.dispatch(CallsActions.batchLoadCalls());
|
||||
expect(Client4.getPluginsManifests).toBeCalledWith();
|
||||
expect(Client4.getCallsConfig).toBeCalledWith();
|
||||
expect(Client4.getCalls).toBeCalledWith();
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,12 @@ export function loadCalls(): ActionFunc {
|
|||
|
||||
export function batchLoadCalls(forceConfig = false): ActionFunc {
|
||||
return async (dispatch: DispatchFunc) => {
|
||||
const res = await dispatch(checkIsCallsPluginEnabled());
|
||||
if (!res.data) {
|
||||
// Calls is not enabled.
|
||||
return {};
|
||||
}
|
||||
|
||||
const promises = [dispatch(loadConfig(forceConfig)), dispatch(loadCalls())];
|
||||
Promise.all(promises).then((actions: Array<Awaited<GenericAction>>) => {
|
||||
dispatch(batchActions(actions, 'BATCH_LOAD_CALLS'));
|
||||
|
|
@ -101,6 +107,24 @@ export function batchLoadCalls(forceConfig = false): ActionFunc {
|
|||
};
|
||||
}
|
||||
|
||||
export function checkIsCallsPluginEnabled(): ActionFunc {
|
||||
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
||||
let data;
|
||||
try {
|
||||
data = await Client4.getPluginsManifests();
|
||||
} catch (error) {
|
||||
forceLogoutIfNecessary(error, dispatch, getState);
|
||||
dispatch(logError(error));
|
||||
return {} as GenericAction;
|
||||
}
|
||||
|
||||
const enabled = data.findIndex((m) => m.id === Calls.PluginId) !== -1;
|
||||
dispatch({type: CallsTypes.RECEIVED_PLUGIN_ENABLED, data: enabled});
|
||||
|
||||
return {data: enabled};
|
||||
};
|
||||
}
|
||||
|
||||
export function enableChannelCalls(channelId: string): ActionFunc {
|
||||
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
||||
try {
|
||||
|
|
@ -135,6 +159,10 @@ export function disableChannelCalls(channelId: string): ActionFunc {
|
|||
|
||||
export function joinCall(channelId: string, intl: typeof intlShape): ActionFunc {
|
||||
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
||||
// Edge case: calls was disabled when app loaded, and then enabled, but app hasn't
|
||||
// reconnected its websocket since then (i.e., hasn't called batchLoadCalls yet)
|
||||
dispatch(checkIsCallsPluginEnabled());
|
||||
|
||||
const hasPermission = await hasMicrophonePermission(intl);
|
||||
if (!hasPermission) {
|
||||
return {error: 'no permissions to microphone, unable to start call'};
|
||||
|
|
|
|||
|
|
@ -216,6 +216,16 @@ function speakerphoneOn(state = false, action: GenericAction) {
|
|||
}
|
||||
}
|
||||
|
||||
function pluginEnabled(state = false, action: GenericAction) {
|
||||
switch (action.type) {
|
||||
case CallsTypes.RECEIVED_PLUGIN_ENABLED: {
|
||||
return action.data;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default combineReducers({
|
||||
calls,
|
||||
enabled,
|
||||
|
|
@ -223,4 +233,5 @@ export default combineReducers({
|
|||
screenShareURL,
|
||||
speakerphoneOn,
|
||||
config,
|
||||
pluginEnabled,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -61,3 +61,7 @@ export function isSupportedServer(state: GlobalState) {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isCallsPluginEnabled(state: GlobalState) {
|
||||
return state.entities.calls.pluginEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export type CallsState = {
|
|||
screenShareURL: string;
|
||||
speakerphoneOn: boolean;
|
||||
config: ServerConfig;
|
||||
pluginEnabled: boolean;
|
||||
}
|
||||
|
||||
export type Call = {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
// See LICENSE.txt for license information.
|
||||
import {EventEmitter} from 'events';
|
||||
|
||||
import Calls from '@constants/calls';
|
||||
import {encode} from '@msgpack/msgpack/dist';
|
||||
|
||||
export default class WebSocketClient extends EventEmitter {
|
||||
private ws: WebSocket | null;
|
||||
private seqNo = 0;
|
||||
private connID = '';
|
||||
private eventPrefix = 'custom_com.mattermost.calls';
|
||||
private eventPrefix = `custom_${Calls.PluginId}`;
|
||||
|
||||
constructor(connURL: string) {
|
||||
super();
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export default class ChannelAndroid extends ChannelBase {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {theme, viewingGlobalThreads, isSupportedServerCalls} = this.props;
|
||||
const {theme, viewingGlobalThreads, isCallsEnabled} = this.props;
|
||||
let component;
|
||||
|
||||
if (viewingGlobalThreads) {
|
||||
|
|
@ -106,11 +106,12 @@ export default class ChannelAndroid extends ChannelBase {
|
|||
{component}
|
||||
<NetworkIndicator/>
|
||||
<AnnouncementBanner/>
|
||||
{isSupportedServerCalls &&
|
||||
{isCallsEnabled &&
|
||||
<FloatingCallContainer>
|
||||
<JoinCall/>
|
||||
<CurrentCall/>
|
||||
</FloatingCallContainer>}
|
||||
</FloatingCallContainer>
|
||||
}
|
||||
</>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export default class ChannelIOS extends ChannelBase {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {currentChannelId, theme, viewingGlobalThreads, isSupportedServerCalls} = this.props;
|
||||
const {currentChannelId, theme, viewingGlobalThreads, isCallsEnabled} = this.props;
|
||||
|
||||
let component;
|
||||
let renderDraftArea = false;
|
||||
|
|
@ -85,11 +85,12 @@ export default class ChannelIOS extends ChannelBase {
|
|||
<>
|
||||
<AnnouncementBanner/>
|
||||
<NetworkIndicator/>
|
||||
{isSupportedServerCalls &&
|
||||
{isCallsEnabled &&
|
||||
<FloatingCallContainer>
|
||||
<JoinCall/>
|
||||
<CurrentCall/>
|
||||
</FloatingCallContainer>}
|
||||
</FloatingCallContainer>
|
||||
}
|
||||
</>
|
||||
);
|
||||
const header = (
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ export default class ChannelBase extends PureComponent {
|
|||
viewingGlobalThreads: PropTypes.bool,
|
||||
collapsedThreadsEnabled: PropTypes.bool.isRequired,
|
||||
isSupportedServerCalls: PropTypes.bool.isRequired,
|
||||
isCallsEnabled: PropTypes.bool.isRequired,
|
||||
selectedPost: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
channel_id: PropTypes.string.isRequired,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ import {getCurrentUserId, getCurrentUserRoles, shouldShowTermsOfService} from '@
|
|||
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
|
||||
import {isSystemAdmin as checkIsSystemAdmin} from '@mm-redux/utils/user_utils';
|
||||
import {batchLoadCalls} from '@mmproducts/calls/store/actions/calls';
|
||||
import {isSupportedServer as isSupportedServerForCalls} from '@mmproducts/calls/store/selectors/calls';
|
||||
import {
|
||||
isCallsPluginEnabled,
|
||||
isSupportedServer as isSupportedServerForCalls,
|
||||
} from '@mmproducts/calls/store/selectors/calls';
|
||||
import {getViewingGlobalThreads} from '@selectors/threads';
|
||||
|
||||
import Channel from './channel';
|
||||
|
|
@ -44,6 +47,7 @@ function mapStateToProps(state) {
|
|||
const currentChannelId = currentTeam?.delete_at === 0 ? getCurrentChannelId(state) : '';
|
||||
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(state);
|
||||
const isSupportedServerCalls = isSupportedServerForCalls(state);
|
||||
const isCallsEnabled = isCallsPluginEnabled(state);
|
||||
|
||||
return {
|
||||
currentChannelId,
|
||||
|
|
@ -58,6 +62,7 @@ function mapStateToProps(state) {
|
|||
theme: getTheme(state),
|
||||
viewingGlobalThreads: collapsedThreadsEnabled && getViewingGlobalThreads(state),
|
||||
isSupportedServerCalls,
|
||||
isCallsEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue