[MM-63838] Fix potential TypeError when Calls is disabled (#30867)
* Fix potential TypeError when Calls is disabled * Use createSelector
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
bc561620cb
Коммит
d69925a415
@@ -1,7 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {isUserInCall} from './index';
|
||||
import {screen, render} from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import {Provider} from 'react-redux';
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
import {TestHelper} from '../../../utils/test_helper';
|
||||
|
||||
import CallButton, {isUserInCall} from './index';
|
||||
|
||||
describe('isUserInCall', () => {
|
||||
test('missing state', () => {
|
||||
@@ -51,3 +58,385 @@ describe('isUserInCall', () => {
|
||||
} as any, 'userA', 'channelID')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CallButton', () => {
|
||||
const mockStore = configureStore();
|
||||
const userId = 'user1';
|
||||
const currentUserId = 'current_user';
|
||||
const dmChannelId = 'dm_channel_id';
|
||||
const baseProps = {
|
||||
userId,
|
||||
currentUserId,
|
||||
fullname: 'Test User',
|
||||
username: 'testuser',
|
||||
};
|
||||
const PluginComponent = () => {
|
||||
return <button>{'Start Call'}</button>;
|
||||
};
|
||||
|
||||
test('should not render when calls are disabled', () => {
|
||||
const store = mockStore({
|
||||
'plugins-com.mattermost.calls': {
|
||||
enabled: false,
|
||||
},
|
||||
entities: {
|
||||
channels: {
|
||||
channels: {
|
||||
currentChannelId: dmChannelId,
|
||||
channels: {
|
||||
current_channel_id: TestHelper.getChannelMock({
|
||||
id: dmChannelId,
|
||||
name: `${currentUserId}__${userId}`,
|
||||
display_name: `${currentUserId}__${userId}`,
|
||||
delete_at: 0,
|
||||
type: 'D',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
users: {
|
||||
profiles: {
|
||||
[currentUserId]: TestHelper.getUserMock({
|
||||
id: currentUserId,
|
||||
roles: 'system_user',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
plugins: {
|
||||
'com.mattermost.calls': {
|
||||
id: 'com.mattermost.calls',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<CallButton {...baseProps}/>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
expect(screen.queryByTestId('startCallButton')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should render for admin even in test mode', () => {
|
||||
const store = mockStore({
|
||||
'plugins-com.mattermost.calls': {
|
||||
enabled: true,
|
||||
config: {
|
||||
DefaultEnabled: false,
|
||||
},
|
||||
},
|
||||
entities: {
|
||||
channels: {
|
||||
currentChannelId: dmChannelId,
|
||||
channels: {
|
||||
current_channel_id: TestHelper.getChannelMock({
|
||||
id: dmChannelId,
|
||||
name: `${currentUserId}__${userId}`,
|
||||
display_name: `${currentUserId}__${userId}`,
|
||||
delete_at: 0,
|
||||
type: 'D',
|
||||
}),
|
||||
},
|
||||
myMembers: {
|
||||
[dmChannelId]: TestHelper.getChannelMembershipMock({channel_id: dmChannelId}),
|
||||
},
|
||||
},
|
||||
users: {
|
||||
currentUserId,
|
||||
profiles: {
|
||||
[currentUserId]: TestHelper.getUserMock({
|
||||
id: currentUserId,
|
||||
roles: 'system_admin',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
plugins: {
|
||||
'com.mattermost.calls': {
|
||||
id: 'com.mattermost.calls',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
CallButton: [{
|
||||
id: 'CallButton',
|
||||
plugin_id: 'com.mattermost.calls',
|
||||
button: PluginComponent,
|
||||
}],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
rhs: {
|
||||
isSidebarOpen: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<CallButton {...baseProps}/>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('Start Call')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should render when calls are enabled and not in test mode', () => {
|
||||
const store = mockStore({
|
||||
'plugins-com.mattermost.calls': {
|
||||
enabled: true,
|
||||
config: {
|
||||
DefaultEnabled: true,
|
||||
},
|
||||
channels: {},
|
||||
sessions: {},
|
||||
},
|
||||
entities: {
|
||||
channels: {
|
||||
currentChannelId: dmChannelId,
|
||||
channels: {
|
||||
current_channel_id: TestHelper.getChannelMock({
|
||||
id: dmChannelId,
|
||||
name: `${currentUserId}__${userId}`,
|
||||
display_name: `${currentUserId}__${userId}`,
|
||||
delete_at: 0,
|
||||
type: 'D',
|
||||
}),
|
||||
},
|
||||
myMembers: {
|
||||
[dmChannelId]: TestHelper.getChannelMembershipMock({channel_id: dmChannelId}),
|
||||
},
|
||||
},
|
||||
users: {
|
||||
currentUserId,
|
||||
profiles: {
|
||||
[currentUserId]: TestHelper.getUserMock({
|
||||
id: currentUserId,
|
||||
roles: 'system_admin',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
plugins: {
|
||||
'com.mattermost.calls': {
|
||||
id: 'com.mattermost.calls',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
CallButton: [{
|
||||
id: 'CallButton',
|
||||
plugin_id: 'com.mattermost.calls',
|
||||
button: PluginComponent,
|
||||
}],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
rhs: {
|
||||
isSidebarOpen: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<CallButton {...baseProps}/>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('Start Call')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should render when channel is explicitly enabled regardless of test mode', () => {
|
||||
const store = mockStore({
|
||||
'plugins-com.mattermost.calls': {
|
||||
enabled: true,
|
||||
config: {
|
||||
DefaultEnabled: false,
|
||||
},
|
||||
channels: {
|
||||
[dmChannelId]: {enabled: true},
|
||||
},
|
||||
sessions: {},
|
||||
},
|
||||
entities: {
|
||||
channels: {
|
||||
currentChannelId: dmChannelId,
|
||||
channels: {
|
||||
current_channel_id: TestHelper.getChannelMock({
|
||||
id: dmChannelId,
|
||||
name: `${currentUserId}__${userId}`,
|
||||
display_name: `${currentUserId}__${userId}`,
|
||||
delete_at: 0,
|
||||
type: 'D',
|
||||
}),
|
||||
},
|
||||
myMembers: {
|
||||
[dmChannelId]: TestHelper.getChannelMembershipMock({channel_id: dmChannelId}),
|
||||
},
|
||||
},
|
||||
users: {
|
||||
currentUserId,
|
||||
profiles: {
|
||||
[currentUserId]: TestHelper.getUserMock({
|
||||
id: currentUserId,
|
||||
roles: 'system_admin',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
plugins: {
|
||||
'com.mattermost.calls': {
|
||||
id: 'com.mattermost.calls',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
CallButton: [{
|
||||
id: 'CallButton',
|
||||
plugin_id: 'com.mattermost.calls',
|
||||
button: PluginComponent,
|
||||
}],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
rhs: {
|
||||
isSidebarOpen: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<CallButton {...baseProps}/>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('Start Call')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should not render when channel is explicitly disabled', () => {
|
||||
const store = mockStore({
|
||||
'plugins-com.mattermost.calls': {
|
||||
enabled: true,
|
||||
config: {
|
||||
DefaultEnabled: true,
|
||||
},
|
||||
channels: {
|
||||
[dmChannelId]: {enabled: false},
|
||||
},
|
||||
sessions: {},
|
||||
},
|
||||
entities: {
|
||||
channels: {
|
||||
currentChannelId: dmChannelId,
|
||||
channels: {
|
||||
current_channel_id: TestHelper.getChannelMock({
|
||||
id: dmChannelId,
|
||||
name: `${currentUserId}__${userId}`,
|
||||
display_name: `${currentUserId}__${userId}`,
|
||||
delete_at: 0,
|
||||
type: 'D',
|
||||
}),
|
||||
},
|
||||
myMembers: {
|
||||
[dmChannelId]: TestHelper.getChannelMembershipMock({channel_id: dmChannelId}),
|
||||
},
|
||||
},
|
||||
users: {
|
||||
profiles: {
|
||||
[currentUserId]: TestHelper.getUserMock({
|
||||
id: currentUserId,
|
||||
roles: 'system_admin',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
plugins: {
|
||||
'com.mattermost.calls': {
|
||||
id: 'com.mattermost.calls',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<CallButton {...baseProps}/>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
expect(screen.queryByLabelText('Start Call')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should disable button when there is an ongoing call', () => {
|
||||
const store = mockStore({
|
||||
'plugins-com.mattermost.calls': {
|
||||
enabled: true,
|
||||
config: {
|
||||
DefaultEnabled: true,
|
||||
},
|
||||
sessions: {
|
||||
[dmChannelId]: {
|
||||
session1: {
|
||||
user_id: currentUserId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
entities: {
|
||||
channels: {
|
||||
currentChannelId: dmChannelId,
|
||||
channels: {
|
||||
current_channel_id: TestHelper.getChannelMock({
|
||||
id: dmChannelId,
|
||||
name: `${currentUserId}__${userId}`,
|
||||
display_name: `${currentUserId}__${userId}`,
|
||||
delete_at: 0,
|
||||
type: 'D',
|
||||
}),
|
||||
},
|
||||
myMembers: {
|
||||
[dmChannelId]: TestHelper.getChannelMembershipMock({channel_id: dmChannelId}),
|
||||
},
|
||||
},
|
||||
users: {
|
||||
profiles: {
|
||||
[currentUserId]: TestHelper.getUserMock({
|
||||
id: currentUserId,
|
||||
roles: 'system_admin',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
plugins: {
|
||||
'com.mattermost.calls': {
|
||||
id: 'com.mattermost.calls',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<CallButton {...baseProps}/>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const button = screen.getByLabelText('Call with Test User is ongoing');
|
||||
expect(button).toBeInTheDocument();
|
||||
expect(button).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,12 +5,18 @@ import semver from 'semver';
|
||||
|
||||
import type {CallsConfig, UserSessionState} from '@mattermost/calls-common/lib/types';
|
||||
|
||||
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
||||
|
||||
import {suitePluginIds} from 'utils/constants';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
const CALLS_PLUGIN = `plugins-${suitePluginIds.calls}`;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const pluginState = (state: GlobalState) => state[CALLS_PLUGIN];
|
||||
|
||||
export function isCallsEnabled(state: GlobalState, minVersion = '0.4.2') {
|
||||
return Boolean(state.plugins.plugins[suitePluginIds.calls] &&
|
||||
semver.gte(String(semver.clean(state.plugins.plugins[suitePluginIds.calls].version || '0.0.0')), minVersion));
|
||||
@@ -18,32 +24,33 @@ export function isCallsEnabled(state: GlobalState, minVersion = '0.4.2') {
|
||||
|
||||
// isCallsRingingEnabledOnServer is the flag for the ringing/notification feature in calls
|
||||
export function isCallsRingingEnabledOnServer(state: GlobalState) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return Boolean(state[CALLS_PLUGIN]?.callsConfig?.EnableRinging);
|
||||
return Boolean(pluginState(state)?.callsConfig?.EnableRinging);
|
||||
}
|
||||
|
||||
export function getSessionsInCalls(state: GlobalState): Record<string, Record<string, UserSessionState>> {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return state[CALLS_PLUGIN]?.sessions || {};
|
||||
}
|
||||
export const getSessionsInCalls = createSelector(
|
||||
'getSessionsInCalls',
|
||||
pluginState,
|
||||
(state): Record<string, Record<string, UserSessionState>> => {
|
||||
return state?.sessions || {};
|
||||
},
|
||||
);
|
||||
|
||||
export function getCallsConfig(state: GlobalState): CallsConfig {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return state[CALLS_PLUGIN]?.callsConfig;
|
||||
}
|
||||
export const getCallsConfig = createSelector(
|
||||
'getCallsConfig',
|
||||
pluginState,
|
||||
(state): CallsConfig => {
|
||||
return state?.callsConfig || {};
|
||||
},
|
||||
);
|
||||
|
||||
export function getCallsChannelState(state: GlobalState, channelId: string): {enabled?: boolean} {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (!state[CALLS_PLUGIN] || !state[CALLS_PLUGIN].channels) {
|
||||
const callsState = pluginState(state);
|
||||
|
||||
if (!callsState || !callsState.channels || !callsState.channels[channelId]) {
|
||||
return {};
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return state[CALLS_PLUGIN].channels[channelId] || {};
|
||||
|
||||
return callsState.channels[channelId];
|
||||
}
|
||||
|
||||
export function callsChannelExplicitlyEnabled(state: GlobalState, channelId: string) {
|
||||
|
||||
Ссылка в новой задаче
Block a user