MM-42623 - Calls: remove Feature Flag (#6091)
* removed CallsMobile feature flag; added server version check * added on-demand check and Alert for Calls enabled * merge with master * fix deps, typo, test snapshots
This commit is contained in:
parent
87f891a457
commit
734675978d
25 changed files with 219 additions and 211 deletions
|
|
@ -12,7 +12,7 @@ import {getThreads} from '@mm-redux/actions/threads';
|
|||
import {getProfilesByIds, getStatusesByIds} from '@mm-redux/actions/users';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import {getCurrentChannelId, getCurrentChannelStats} from '@mm-redux/selectors/entities/channels';
|
||||
import {getConfig, getFeatureFlagValue} from '@mm-redux/selectors/entities/general';
|
||||
import {getConfig} from '@mm-redux/selectors/entities/general';
|
||||
import {getPostIdsInChannel} from '@mm-redux/selectors/entities/posts';
|
||||
import {isCollapsedThreadsEnabled} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
|
||||
|
|
@ -38,6 +38,7 @@ import {
|
|||
handleCallScreenOn,
|
||||
handleCallScreenOff, handleCallUserRaiseHand, handleCallUserUnraiseHand,
|
||||
} from '@mmproducts/calls/store/actions/websockets';
|
||||
import {isSupportedServer} from '@mmproducts/calls/store/selectors/calls';
|
||||
import {appsConfiguredAsEnabled} from '@utils/apps';
|
||||
import {getChannelSinceValue} from '@utils/channels';
|
||||
import {semverFromServerVersion} from '@utils/general';
|
||||
|
|
@ -152,6 +153,7 @@ export function doReconnect(now: number) {
|
|||
const currentChannelId = getCurrentChannelId(state);
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const users = getUsers(state);
|
||||
const isSupportedServerCalls = isSupportedServer(state);
|
||||
const {lastDisconnectAt} = state.websocket;
|
||||
const actions: GenericAction[] = [];
|
||||
|
||||
|
|
@ -168,7 +170,7 @@ export function doReconnect(now: number) {
|
|||
const {data: me}: any = await dispatch(loadMe(null, null, true));
|
||||
|
||||
if (!me.error) {
|
||||
if (getFeatureFlagValue(getState(), 'CallsMobile') === 'true') {
|
||||
if (isSupportedServerCalls) {
|
||||
dispatch(loadCalls());
|
||||
}
|
||||
|
||||
|
|
@ -448,40 +450,37 @@ function handleEvent(msg: WebSocketMessage) {
|
|||
return dispatch(handleSidebarCategoryDeleted(msg));
|
||||
case WebsocketEvents.SIDEBAR_CATEGORY_ORDER_UPDATED:
|
||||
return dispatch(handleSidebarCategoryOrderUpdated(msg));
|
||||
}
|
||||
|
||||
if (getFeatureFlagValue(getState(), 'CallsMobile') === 'true') {
|
||||
switch (msg.event) {
|
||||
case WebsocketEvents.CALLS_CHANNEL_ENABLED:
|
||||
return dispatch(handleCallChannelEnabled(msg));
|
||||
case WebsocketEvents.CALLS_CHANNEL_DISABLED:
|
||||
return dispatch(handleCallChannelDisabled(msg));
|
||||
case WebsocketEvents.CALLS_USER_CONNECTED:
|
||||
handleCallUserConnected(dispatch, getState, msg);
|
||||
break;
|
||||
case WebsocketEvents.CALLS_USER_DISCONNECTED:
|
||||
return dispatch(handleCallUserDisconnected(msg));
|
||||
case WebsocketEvents.CALLS_USER_MUTED:
|
||||
return dispatch(handleCallUserMuted(msg));
|
||||
case WebsocketEvents.CALLS_USER_UNMUTED:
|
||||
return dispatch(handleCallUserUnmuted(msg));
|
||||
case WebsocketEvents.CALLS_USER_VOICE_ON:
|
||||
handleCallUserVoiceOn(msg);
|
||||
break;
|
||||
case WebsocketEvents.CALLS_USER_VOICE_OFF:
|
||||
handleCallUserVoiceOff(msg);
|
||||
break;
|
||||
case WebsocketEvents.CALLS_CALL_START:
|
||||
return dispatch(handleCallStarted(msg));
|
||||
case WebsocketEvents.CALLS_SCREEN_ON:
|
||||
return dispatch(handleCallScreenOn(msg));
|
||||
case WebsocketEvents.CALLS_SCREEN_OFF:
|
||||
return dispatch(handleCallScreenOff(msg));
|
||||
case WebsocketEvents.CALLS_USER_RAISE_HAND:
|
||||
return dispatch(handleCallUserRaiseHand(msg));
|
||||
case WebsocketEvents.CALLS_USER_UNRAISE_HAND:
|
||||
return dispatch(handleCallUserUnraiseHand(msg));
|
||||
}
|
||||
// Calls ws events:
|
||||
case WebsocketEvents.CALLS_CHANNEL_ENABLED:
|
||||
return dispatch(handleCallChannelEnabled(msg));
|
||||
case WebsocketEvents.CALLS_CHANNEL_DISABLED:
|
||||
return dispatch(handleCallChannelDisabled(msg));
|
||||
case WebsocketEvents.CALLS_USER_CONNECTED:
|
||||
handleCallUserConnected(dispatch, getState, msg);
|
||||
break;
|
||||
case WebsocketEvents.CALLS_USER_DISCONNECTED:
|
||||
return dispatch(handleCallUserDisconnected(msg));
|
||||
case WebsocketEvents.CALLS_USER_MUTED:
|
||||
return dispatch(handleCallUserMuted(msg));
|
||||
case WebsocketEvents.CALLS_USER_UNMUTED:
|
||||
return dispatch(handleCallUserUnmuted(msg));
|
||||
case WebsocketEvents.CALLS_USER_VOICE_ON:
|
||||
handleCallUserVoiceOn(msg);
|
||||
break;
|
||||
case WebsocketEvents.CALLS_USER_VOICE_OFF:
|
||||
handleCallUserVoiceOff(msg);
|
||||
break;
|
||||
case WebsocketEvents.CALLS_CALL_START:
|
||||
return dispatch(handleCallStarted(msg));
|
||||
case WebsocketEvents.CALLS_SCREEN_ON:
|
||||
return dispatch(handleCallScreenOn(msg));
|
||||
case WebsocketEvents.CALLS_SCREEN_OFF:
|
||||
return dispatch(handleCallScreenOff(msg));
|
||||
case WebsocketEvents.CALLS_USER_RAISE_HAND:
|
||||
return dispatch(handleCallUserRaiseHand(msg));
|
||||
case WebsocketEvents.CALLS_USER_UNRAISE_HAND:
|
||||
return dispatch(handleCallUserUnraiseHand(msg));
|
||||
}
|
||||
|
||||
return {data: true};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {showPermalink} from '@actions/views/permalink';
|
|||
import {THREAD} from '@constants/screen';
|
||||
import {removePost} from '@mm-redux/actions/posts';
|
||||
import {getChannel} from '@mm-redux/selectors/entities/channels';
|
||||
import {getConfig, getFeatureFlagValue} from '@mm-redux/selectors/entities/general';
|
||||
import {getConfig} from '@mm-redux/selectors/entities/general';
|
||||
import {getPost, isRootPost} from '@mm-redux/selectors/entities/posts';
|
||||
import {getMyPreferences, getTeammateNameDisplaySetting, isCollapsedThreadsEnabled} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
|
||||
|
|
@ -49,7 +49,6 @@ function mapSateToProps(state: GlobalState, ownProps: OwnProps) {
|
|||
const teammateNameDisplay = getTeammateNameDisplaySetting(state);
|
||||
const enablePostUsernameOverride = config.EnablePostUsernameOverride === 'true';
|
||||
const isConsecutivePost = post && previousPost && !author?.is_bot && !isRootPost(state, post.id) && areConsecutivePosts(post, previousPost);
|
||||
const callsFeatureEnabled = getFeatureFlagValue(state, 'CallsMobile') === 'true';
|
||||
let isFirstReply = true;
|
||||
let isLastReply = true;
|
||||
let canDelete = false;
|
||||
|
|
@ -98,7 +97,6 @@ function mapSateToProps(state: GlobalState, ownProps: OwnProps) {
|
|||
teammateNameDisplay,
|
||||
thread,
|
||||
threadStarter: getUser(state, post.user_id),
|
||||
callsFeatureEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ type PostProps = {
|
|||
theme: Theme;
|
||||
thread: UserThread;
|
||||
threadStarter: UserProfile;
|
||||
callsFeatureEnabled: boolean;
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
|
|
@ -115,7 +114,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
const Post = ({
|
||||
canDelete, collapsedThreadsEnabled, enablePostUsernameOverride, highlight, highlightPinnedOrFlagged = true, intl, isConsecutivePost, isFirstReply, isFlagged, isLastReply,
|
||||
location, post, removePost, rootPostAuthor, shouldRenderReplyButton, skipFlaggedHeader, skipPinnedHeader, showAddReaction = true, showPermalink, style,
|
||||
teammateNameDisplay, testID, theme, thread, threadStarter, callsFeatureEnabled,
|
||||
teammateNameDisplay, testID, theme, thread, threadStarter,
|
||||
}: PostProps) => {
|
||||
const pressDetected = useRef(false);
|
||||
const styles = getStyleSheet(theme);
|
||||
|
|
@ -241,7 +240,7 @@ const Post = ({
|
|||
theme={theme}
|
||||
/>
|
||||
);
|
||||
} else if (post.type === 'custom_calls' && callsFeatureEnabled) {
|
||||
} else if (post.type === Posts.POST_TYPES.CUSTOM_CALLS) {
|
||||
body = (
|
||||
<CallMessage
|
||||
post={post}
|
||||
|
|
|
|||
|
|
@ -808,118 +808,7 @@ exports[`ChannelItem should match snapshot for no displayName 1`] = `null`;
|
|||
|
||||
exports[`ChannelItem should match snapshot for showUnreadForMsgs 1`] = `null`;
|
||||
|
||||
exports[`ChannelItem should match snapshot when there is a call and but calls are disabled 1`] = `
|
||||
<TouchableHighlight
|
||||
onPress={[Function]}
|
||||
underlayColor="rgba(40,66,123,0.5)"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flex": 1,
|
||||
"flexDirection": "row",
|
||||
"height": 44,
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flex": 1,
|
||||
"flexDirection": "row",
|
||||
"paddingLeft": 16,
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
hasDraft={false}
|
||||
isActive={false}
|
||||
isArchived={false}
|
||||
isInfo={false}
|
||||
isUnread={true}
|
||||
membersCount={1}
|
||||
size={24}
|
||||
statusStyle={
|
||||
Object {
|
||||
"backgroundColor": "#1e325c",
|
||||
"borderColor": "transparent",
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc1f",
|
||||
"buttonBg": "#1c58d9",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3f4350",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#d24b4e",
|
||||
"errorTextColor": "#d24b4e",
|
||||
"linkColor": "#386fe5",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionColor": "#1e325c",
|
||||
"mentionHighlightBg": "#ffd470",
|
||||
"mentionHighlightLink": "#1b1d22",
|
||||
"newMessageSeparator": "#cc8f00",
|
||||
"onlineIndicator": "#3db887",
|
||||
"sidebarBg": "#1e325c",
|
||||
"sidebarHeaderBg": "#192a4d",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarTeamBarBg": "#14213e",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#5d89ea",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#28427b",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Denim",
|
||||
}
|
||||
}
|
||||
type="O"
|
||||
/>
|
||||
<Text
|
||||
ellipsizeMode="tail"
|
||||
numberOfLines={1}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignSelf": "center",
|
||||
"color": "rgba(255,255,255,0.6)",
|
||||
"fontFamily": "Open Sans",
|
||||
"fontSize": 16,
|
||||
"lineHeight": 24,
|
||||
"marginLeft": 13,
|
||||
"maxWidth": "80%",
|
||||
"paddingRight": 10,
|
||||
},
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
"fontWeight": "500",
|
||||
"maxWidth": "70%",
|
||||
"opacity": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.display_name"
|
||||
>
|
||||
display_name
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
`;
|
||||
|
||||
exports[`ChannelItem should match snapshot when there is a call and calls are enabled 1`] = `
|
||||
exports[`ChannelItem should match snapshot when there is a call 1`] = `
|
||||
<TouchableHighlight
|
||||
onPress={[Function]}
|
||||
underlayColor="rgba(40,66,123,0.5)"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ export default class ChannelItem extends PureComponent {
|
|||
viewingGlobalThreads: PropTypes.bool,
|
||||
customStatusEnabled: PropTypes.bool.isRequired,
|
||||
channelHasCall: PropTypes.bool.isRequired,
|
||||
callsFeatureEnabled: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -217,7 +216,7 @@ export default class ChannelItem extends PureComponent {
|
|||
</Text>
|
||||
{customStatus}
|
||||
{badge}
|
||||
{this.props.callsFeatureEnabled && this.props.channelHasCall &&
|
||||
{this.props.channelHasCall &&
|
||||
<CompassIcon
|
||||
name='phone-in-talk'
|
||||
size={16}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ describe('ChannelItem', () => {
|
|||
isBot: false,
|
||||
customStatusEnabled: true,
|
||||
channelHasCall: false,
|
||||
callsFeatureEnabled: false,
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
|
|
@ -52,24 +51,9 @@ describe('ChannelItem', () => {
|
|||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot when there is a call and calls are enabled', () => {
|
||||
test('should match snapshot when there is a call', () => {
|
||||
const newProps = {
|
||||
...baseProps,
|
||||
callsFeatureEnabled: true,
|
||||
channelHasCall: true,
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelItem {...newProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot when there is a call and but calls are disabled', () => {
|
||||
const newProps = {
|
||||
...baseProps,
|
||||
callsFeatureEnabled: false,
|
||||
channelHasCall: true,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import {
|
|||
makeGetChannel,
|
||||
shouldHideDefaultChannel,
|
||||
} from '@mm-redux/selectors/entities/channels';
|
||||
import {getFeatureFlagValue} from '@mm-redux/selectors/entities/general';
|
||||
import {getTheme, getTeammateNameDisplaySetting, isCollapsedThreadsEnabled} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentUserId, getUser} from '@mm-redux/selectors/entities/users';
|
||||
import {getMsgCountInChannel, getUserIdFromChannelName, isChannelMuted} from '@mm-redux/utils/channel_utils';
|
||||
|
|
@ -75,7 +74,6 @@ function makeMapStateToProps() {
|
|||
if (member && member.notify_props) {
|
||||
showUnreadForMsgs = member.notify_props.mark_unread !== General.MENTION;
|
||||
}
|
||||
const callsFeatureEnabled = getFeatureFlagValue(state, 'CallsMobile') === 'true';
|
||||
|
||||
const viewingGlobalThreads = getViewingGlobalThreads(state);
|
||||
return {
|
||||
|
|
@ -97,7 +95,6 @@ function makeMapStateToProps() {
|
|||
viewingGlobalThreads,
|
||||
customStatusEnabled: isCustomStatusEnabled(state),
|
||||
channelHasCall,
|
||||
callsFeatureEnabled,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
11
app/constants/calls.ts
Normal file
11
app/constants/calls.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
const RequiredServer = {
|
||||
FULL_VERSION: '6.3.0',
|
||||
MAJOR_VERSION: 6,
|
||||
MIN_VERSION: 3,
|
||||
PATCH_VERSION: 0,
|
||||
};
|
||||
|
||||
export default {RequiredServer};
|
||||
|
|
@ -28,6 +28,7 @@ export const PostTypes = {
|
|||
COMBINED_USER_ACTIVITY: 'system_combined_user_activity',
|
||||
ME: 'me',
|
||||
ADD_BOT_TEAMS_CHANNELS: 'add_bot_teams_channels',
|
||||
CUSTOM_CALLS: 'custom_calls',
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,25 @@
|
|||
import type {ServerChannelState} from '@mmproducts/calls/store/types/calls';
|
||||
|
||||
export interface ClientCallsMix {
|
||||
getEnabled: () => Promise<Boolean>;
|
||||
getCalls: () => Promise<ServerChannelState[]>;
|
||||
enableChannelCalls: (channelId: string) => Promise<ServerChannelState>;
|
||||
disableChannelCalls: (channelId: string) => Promise<ServerChannelState>;
|
||||
}
|
||||
|
||||
const ClientCalls = (superclass: any) => class extends superclass {
|
||||
getEnabled = async () => {
|
||||
try {
|
||||
await this.doFetch(
|
||||
`${this.getCallsRoute()}/version`,
|
||||
{method: 'get'},
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
getCalls = async () => {
|
||||
return this.doFetch(
|
||||
`${this.getCallsRoute()}/channels`,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import React from 'react';
|
||||
import {Alert, TouchableOpacity} from 'react-native';
|
||||
|
||||
import {Posts} from '@mm-redux/constants';
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
import {shallowWithIntl} from '@test/intl-test-helper';
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ describe('CallMessage', () => {
|
|||
props: {
|
||||
start_at: 100,
|
||||
},
|
||||
type: 'custom_calls',
|
||||
type: Posts.POST_TYPES.CUSTOM_CALLS,
|
||||
},
|
||||
user: {
|
||||
id: 'user-1-id',
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import React, {useCallback} from 'react';
|
||||
|
||||
import {Theme} from '@mm-redux/types/theme';
|
||||
import {useTryCallsFunction} from '@mmproducts/calls/hooks';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
|
@ -19,7 +20,8 @@ type Props = {
|
|||
const EnableDisableCalls = (props: Props) => {
|
||||
const {testID, canEnableDisableCalls, theme, onPress, enabled} = props;
|
||||
|
||||
const handleEnableDisableCalls = useCallback(preventDoubleTap(onPress), [onPress]);
|
||||
const [tryOnPress, msgPostfix] = useTryCallsFunction(onPress);
|
||||
const handleEnableDisableCalls = useCallback(preventDoubleTap(tryOnPress), [tryOnPress]);
|
||||
|
||||
if (!canEnableDisableCalls) {
|
||||
return null;
|
||||
|
|
@ -31,7 +33,7 @@ const EnableDisableCalls = (props: Props) => {
|
|||
<ChannelInfoRow
|
||||
testID={testID}
|
||||
action={handleEnableDisableCalls}
|
||||
defaultMessage={enabled ? 'Disable Calls' : 'Enable Calls'}
|
||||
defaultMessage={(enabled ? 'Disable Calls' : 'Enable Calls') + msgPostfix}
|
||||
icon='phone-outline'
|
||||
theme={theme}
|
||||
rightArrow={false}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,27 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import nock from 'nock';
|
||||
import React from 'react';
|
||||
import {Alert, TouchableHighlight} from 'react-native';
|
||||
|
||||
import {Client4} from '@client/rest';
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import {shallowWithIntl} from '@test/intl-test-helper';
|
||||
import TestHelper from '@test/test_helper';
|
||||
|
||||
import StartCall from './start_call';
|
||||
|
||||
describe('StartCall', () => {
|
||||
beforeAll(async () => {
|
||||
await TestHelper.initBasic(Client4);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await TestHelper.tearDown();
|
||||
});
|
||||
|
||||
const baseProps = {
|
||||
actions: {
|
||||
joinCall: jest.fn(),
|
||||
|
|
@ -53,22 +64,70 @@ describe('StartCall', () => {
|
|||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
|
||||
test('should join on click', () => {
|
||||
test('should start on click when calls is enabled', async () => {
|
||||
nock(Client4.getCallsRoute()).
|
||||
get('/version').
|
||||
times(2).
|
||||
reply(200, {version: 1, build: 2});
|
||||
const joinCall = jest.fn();
|
||||
const props = {...baseProps, actions: {joinCall}};
|
||||
const wrapper = shallowWithIntl(<StartCall {...props}/>).dive();
|
||||
|
||||
wrapper.find(ChannelInfoRow).dive().find(TouchableHighlight).simulate('press');
|
||||
|
||||
// This is so that the awaited call within ClientCalls in products/calls/client/rest.ts has
|
||||
// a chance to be completed by nock:
|
||||
await Client4.doFetch(
|
||||
`${Client4.getUrl()}/plugins/com.mattermost.calls/version`,
|
||||
{method: 'get'},
|
||||
);
|
||||
|
||||
expect(Alert.alert).not.toHaveBeenCalled();
|
||||
expect(props.actions.joinCall).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should ask for confirmation on click', () => {
|
||||
test('should not start on click and should show alert when calls is not enabled', async () => {
|
||||
nock(Client4.getCallsRoute()).
|
||||
get('/version').
|
||||
times(2).
|
||||
reply(404);
|
||||
const joinCall = jest.fn();
|
||||
const props = {...baseProps, actions: {joinCall}};
|
||||
const wrapper = shallowWithIntl(<StartCall {...props}/>).dive();
|
||||
wrapper.find(ChannelInfoRow).dive().find(TouchableHighlight).simulate('press');
|
||||
|
||||
// This is so that the awaited call within ClientCalls in products/calls/client/rest.ts has
|
||||
// a chance to be completed by nock:
|
||||
try {
|
||||
await Client4.doFetch(
|
||||
`${Client4.getUrl()}/plugins/com.mattermost.calls/version`,
|
||||
{method: 'get'},
|
||||
);
|
||||
} catch (e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
expect(Alert.alert).toHaveBeenCalled();
|
||||
expect(props.actions.joinCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should ask for confirmation on click', async () => {
|
||||
nock(Client4.getCallsRoute()).
|
||||
get('/version').
|
||||
times(2).
|
||||
reply(200, {version: 1, build: 2});
|
||||
const joinCall = jest.fn();
|
||||
const props = {...baseProps, confirmToJoin: true, actions: {joinCall}};
|
||||
const wrapper = shallowWithIntl(<StartCall {...props}/>).dive();
|
||||
|
||||
wrapper.find(ChannelInfoRow).dive().find(TouchableHighlight).simulate('press');
|
||||
|
||||
// This is so that the awaited call within ClientCalls in products/calls/client/rest.ts has
|
||||
// a chance to be completed by nock:
|
||||
await Client4.doFetch(
|
||||
`${Client4.getUrl()}/plugins/com.mattermost.calls/version`,
|
||||
{method: 'get'},
|
||||
);
|
||||
|
||||
expect(Alert.alert).toHaveBeenCalled();
|
||||
expect(props.actions.joinCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {injectIntl, IntlShape} from 'react-intl';
|
|||
|
||||
import {Theme} from '@mm-redux/types/theme';
|
||||
import leaveAndJoinWithAlert from '@mmproducts/calls/components/leave_and_join_alert';
|
||||
import {useTryCallsFunction} from '@mmproducts/calls/hooks';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
|
@ -29,9 +30,11 @@ type Props = {
|
|||
const StartCall = (props: Props) => {
|
||||
const {testID, canStartCall, theme, actions, currentChannelId, callChannelName, currentChannelName, confirmToJoin, alreadyInTheCall, ongoingCall, intl} = props;
|
||||
|
||||
const handleStartCall = useCallback(preventDoubleTap(() => {
|
||||
const leaveAndJoin = useCallback(() => {
|
||||
leaveAndJoinWithAlert(intl, currentChannelId, callChannelName, currentChannelName, confirmToJoin, actions.joinCall);
|
||||
}), [actions.joinCall, currentChannelId]);
|
||||
}, [intl, currentChannelId, callChannelName, currentChannelName, confirmToJoin, actions.joinCall]);
|
||||
const [tryLeaveAndJoin, msgPostfix] = useTryCallsFunction(leaveAndJoin);
|
||||
const handleStartCall = useCallback(preventDoubleTap(tryLeaveAndJoin), [tryLeaveAndJoin]);
|
||||
|
||||
if (!canStartCall) {
|
||||
return null;
|
||||
|
|
@ -47,7 +50,7 @@ const StartCall = (props: Props) => {
|
|||
<ChannelInfoRow
|
||||
testID={testID}
|
||||
action={handleStartCall}
|
||||
defaultMessage={ongoingCall ? 'Join Ongoing Call' : 'Start Call'}
|
||||
defaultMessage={(ongoingCall ? 'Join Ongoing Call' : 'Start Call') + msgPostfix}
|
||||
icon='phone-in-talk'
|
||||
theme={theme}
|
||||
rightArrow={false}
|
||||
|
|
|
|||
35
app/products/calls/hooks.ts
Normal file
35
app/products/calls/hooks.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useState} from 'react';
|
||||
import {Alert} from 'react-native';
|
||||
|
||||
import {Client4} from '@client/rest';
|
||||
|
||||
// Check if calls is enabled. If it is, then run fn; if it isn't, show an alert and set
|
||||
// msgPostfix to ' (Not Available)'.
|
||||
export const useTryCallsFunction = (fn: (channelId: string) => void) => {
|
||||
const [msgPostfix, setMsgPostfix] = useState('');
|
||||
|
||||
const tryFn = async (channelId: string) => {
|
||||
if (await Client4.getEnabled()) {
|
||||
setMsgPostfix('');
|
||||
fn(channelId);
|
||||
return;
|
||||
}
|
||||
|
||||
Alert.alert(
|
||||
'Calls is not enabled',
|
||||
'Please contact your system administrator to enable the feature.',
|
||||
[
|
||||
{
|
||||
text: 'OK',
|
||||
style: 'cancel',
|
||||
},
|
||||
],
|
||||
);
|
||||
setMsgPostfix(' (Not Available)');
|
||||
};
|
||||
|
||||
return [tryFn, msgPostfix];
|
||||
};
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Client4} from '@client/rest';
|
||||
import Calls from '@constants/calls';
|
||||
import {getCurrentChannelId} from '@mm-redux/selectors/entities/common';
|
||||
import {getServerVersion} from '@mm-redux/selectors/entities/general';
|
||||
import {GlobalState} from '@mm-redux/types/store';
|
||||
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
|
||||
|
||||
export function getCalls(state: GlobalState) {
|
||||
return state.entities.calls.calls;
|
||||
|
|
@ -27,3 +31,17 @@ export function getScreenShareURL(state: GlobalState) {
|
|||
export function isSpeakerphoneOn(state: GlobalState) {
|
||||
return state.entities.calls.speakerphoneOn;
|
||||
}
|
||||
|
||||
export function isSupportedServer(state: GlobalState) {
|
||||
const serverVersion = Client4.getServerVersion() || getServerVersion(state);
|
||||
if (serverVersion) {
|
||||
return isMinimumServerVersion(
|
||||
serverVersion,
|
||||
Calls.RequiredServer.MAJOR_VERSION,
|
||||
Calls.RequiredServer.MIN_VERSION,
|
||||
Calls.RequiredServer.PATCH_VERSION,
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export default class ChannelAndroid extends ChannelBase {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {theme, viewingGlobalThreads, callsFeatureEnabled} = this.props;
|
||||
const {theme, viewingGlobalThreads, isSupportedServerCalls} = this.props;
|
||||
let component;
|
||||
|
||||
if (viewingGlobalThreads) {
|
||||
|
|
@ -106,7 +106,7 @@ export default class ChannelAndroid extends ChannelBase {
|
|||
{component}
|
||||
<NetworkIndicator/>
|
||||
<AnnouncementBanner/>
|
||||
{callsFeatureEnabled &&
|
||||
{isSupportedServerCalls &&
|
||||
<FloatingCallContainer>
|
||||
<JoinCall/>
|
||||
<CurrentCall/>
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export default class ChannelIOS extends ChannelBase {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {currentChannelId, theme, viewingGlobalThreads, callsFeatureEnabled} = this.props;
|
||||
const {currentChannelId, theme, viewingGlobalThreads, isSupportedServerCalls} = this.props;
|
||||
|
||||
let component;
|
||||
let renderDraftArea = false;
|
||||
|
|
@ -85,7 +85,7 @@ export default class ChannelIOS extends ChannelBase {
|
|||
<>
|
||||
<AnnouncementBanner/>
|
||||
<NetworkIndicator/>
|
||||
{callsFeatureEnabled &&
|
||||
{isSupportedServerCalls &&
|
||||
<FloatingCallContainer>
|
||||
<JoinCall/>
|
||||
<CurrentCall/>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export default class ChannelBase extends PureComponent {
|
|||
skipMetrics: PropTypes.bool,
|
||||
viewingGlobalThreads: PropTypes.bool,
|
||||
collapsedThreadsEnabled: PropTypes.bool.isRequired,
|
||||
callsFeatureEnabled: PropTypes.bool.isRequired,
|
||||
isSupportedServerCalls: PropTypes.bool.isRequired,
|
||||
selectedPost: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
channel_id: PropTypes.string.isRequired,
|
||||
|
|
@ -105,7 +105,7 @@ export default class ChannelBase extends PureComponent {
|
|||
unsupportedServer(isSystemAdmin, this.context.intl.formatMessage);
|
||||
}
|
||||
|
||||
if (this.props.callsFeatureEnabled) {
|
||||
if (this.props.isSupportedServerCalls) {
|
||||
this.props.actions.loadCalls();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ describe('ChannelBase', () => {
|
|||
componentId: channelBaseComponentId,
|
||||
theme: Preferences.THEMES.denim,
|
||||
collapsedThreadsEnabled: false,
|
||||
callsFeatureEnabled: false,
|
||||
isSupportedServerCalls: false,
|
||||
};
|
||||
const optionsForTheme = (theme) => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {Client4} from '@client/rest';
|
|||
import {ViewTypes} from '@constants';
|
||||
import {getChannelStats} from '@mm-redux/actions/channels';
|
||||
import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels';
|
||||
import {getServerVersion, getFeatureFlagValue} from '@mm-redux/selectors/entities/general';
|
||||
import {getServerVersion} from '@mm-redux/selectors/entities/general';
|
||||
import {getSelectedPost} from '@mm-redux/selectors/entities/posts';
|
||||
import {getTheme, isCollapsedThreadsEnabled} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentTeam} from '@mm-redux/selectors/entities/teams';
|
||||
|
|
@ -18,6 +18,7 @@ import {getCurrentUserId, getCurrentUserRoles, shouldShowTermsOfService} from '@
|
|||
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
|
||||
import {isSystemAdmin as checkIsSystemAdmin} from '@mm-redux/utils/user_utils';
|
||||
import {loadCalls} from '@mmproducts/calls/store/actions/calls';
|
||||
import {isSupportedServer as isSupportedServerForCalls} from '@mmproducts/calls/store/selectors/calls';
|
||||
import {getViewingGlobalThreads} from '@selectors/threads';
|
||||
|
||||
import Channel from './channel';
|
||||
|
|
@ -42,7 +43,7 @@ function mapStateToProps(state) {
|
|||
const currentTeamId = currentTeam?.delete_at === 0 ? currentTeam?.id : '';
|
||||
const currentChannelId = currentTeam?.delete_at === 0 ? getCurrentChannelId(state) : '';
|
||||
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(state);
|
||||
const callsFeatureEnabled = getFeatureFlagValue(state, 'CallsMobile') === 'true';
|
||||
const isSupportedServerCalls = isSupportedServerForCalls(state);
|
||||
|
||||
return {
|
||||
currentChannelId,
|
||||
|
|
@ -56,7 +57,7 @@ function mapStateToProps(state) {
|
|||
teamName: currentTeam?.display_name,
|
||||
theme: getTheme(state),
|
||||
viewingGlobalThreads: collapsedThreadsEnabled && getViewingGlobalThreads(state),
|
||||
callsFeatureEnabled,
|
||||
isSupportedServerCalls,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -614,7 +614,7 @@ exports[`channelInfo should match snapshot 1`] = `
|
|||
</RNCSafeAreaView>
|
||||
`;
|
||||
|
||||
exports[`channelInfo should match snapshot on calls features enabled and calls disabled for channel 1`] = `
|
||||
exports[`channelInfo should match snapshot on calls supported and calls disabled for channel 1`] = `
|
||||
<RNCSafeAreaView
|
||||
edges={
|
||||
Array [
|
||||
|
|
@ -1301,7 +1301,7 @@ exports[`channelInfo should match snapshot on calls features enabled and calls d
|
|||
</RNCSafeAreaView>
|
||||
`;
|
||||
|
||||
exports[`channelInfo should match snapshot on calls features enabled and calls enabled for channel 1`] = `
|
||||
exports[`channelInfo should match snapshot on calls supported and calls enabled for channel 1`] = `
|
||||
<RNCSafeAreaView
|
||||
edges={
|
||||
Array [
|
||||
|
|
@ -1988,7 +1988,7 @@ exports[`channelInfo should match snapshot on calls features enabled and calls e
|
|||
</RNCSafeAreaView>
|
||||
`;
|
||||
|
||||
exports[`channelInfo should match snapshot on calls features enabled, user is not admin and calls disabled for channel 1`] = `
|
||||
exports[`channelInfo should match snapshot on calls supported, user is not admin and calls disabled for channel 1`] = `
|
||||
<RNCSafeAreaView
|
||||
edges={
|
||||
Array [
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export default class ChannelInfo extends PureComponent {
|
|||
isCustomStatusExpirySupported: PropTypes.bool.isRequired,
|
||||
isCallsEnabled: PropTypes.bool.isRequired,
|
||||
isChannelAdmin: PropTypes.bool.isRequired,
|
||||
callsFeatureEnabled: PropTypes.bool.isRequired,
|
||||
isSupportedServerCalls: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -117,7 +117,7 @@ export default class ChannelInfo extends PureComponent {
|
|||
};
|
||||
|
||||
actionsRows = (channelIsArchived) => {
|
||||
const {currentChannel, currentUserId, isDirectMessage, isGroupMessage, theme, isCallsEnabled, callsFeatureEnabled, isChannelAdmin} = this.props;
|
||||
const {currentChannel, currentUserId, isDirectMessage, isGroupMessage, theme, isCallsEnabled, isSupportedServerCalls, isChannelAdmin} = this.props;
|
||||
|
||||
if (channelIsArchived) {
|
||||
return (
|
||||
|
|
@ -178,7 +178,7 @@ export default class ChannelInfo extends PureComponent {
|
|||
testID='channel_info.edit_channel.action'
|
||||
theme={theme}
|
||||
/>
|
||||
{callsFeatureEnabled &&
|
||||
{isSupportedServerCalls &&
|
||||
<>
|
||||
<StartCall
|
||||
testID='channel_info.start_call.action'
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ describe('channelInfo', () => {
|
|||
disableChannelCalls: jest.fn(),
|
||||
},
|
||||
isCallsEnabled: false,
|
||||
callsFeatureEnabled: false,
|
||||
isSupportedServerCalls: false,
|
||||
isChannelAdmin: false,
|
||||
};
|
||||
|
||||
|
|
@ -76,8 +76,8 @@ describe('channelInfo', () => {
|
|||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot on calls features enabled, user is not admin and calls disabled for channel', async () => {
|
||||
const props = {...baseProps, isCallsEnabled: false, callsFeatureEnabled: true, isChannelAdmin: false};
|
||||
test('should match snapshot on calls supported, user is not admin and calls disabled for channel', async () => {
|
||||
const props = {...baseProps, isCallsEnabled: false, isSupportedServerCalls: true, isChannelAdmin: false};
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...props}
|
||||
|
|
@ -87,8 +87,8 @@ describe('channelInfo', () => {
|
|||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot on calls features enabled and calls disabled for channel', async () => {
|
||||
const props = {...baseProps, isCallsEnabled: false, callsFeatureEnabled: true, isChannelAdmin: true};
|
||||
test('should match snapshot on calls supported and calls disabled for channel', async () => {
|
||||
const props = {...baseProps, isCallsEnabled: false, isSupportedServerCalls: true, isChannelAdmin: true};
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...props}
|
||||
|
|
@ -98,8 +98,8 @@ describe('channelInfo', () => {
|
|||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot on calls features enabled and calls enabled for channel', async () => {
|
||||
const props = {...baseProps, isCallsEnabled: true, callsFeatureEnabled: true, isChannelAdmin: true};
|
||||
test('should match snapshot on calls supported and calls enabled for channel', async () => {
|
||||
const props = {...baseProps, isCallsEnabled: true, isSupportedServerCalls: true, isChannelAdmin: true};
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,12 @@ import {getChannelStats} from '@mm-redux/actions/channels';
|
|||
import {getCustomEmojisInText} from '@mm-redux/actions/emojis';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import {getCurrentChannel, getCurrentChannelStats} from '@mm-redux/selectors/entities/channels';
|
||||
import {getFeatureFlagValue} from '@mm-redux/selectors/entities/general';
|
||||
import {getTeammateNameDisplaySetting, getTheme} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentUserRoles, getCurrentUserId, getUser} from '@mm-redux/selectors/entities/users';
|
||||
import {getUserIdFromChannelName} from '@mm-redux/utils/channel_utils';
|
||||
import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin, displayUsername} from '@mm-redux/utils/user_utils';
|
||||
import {joinCall, enableChannelCalls, disableChannelCalls} from '@mmproducts/calls/store/actions/calls';
|
||||
import {isCallsEnabled} from '@mmproducts/calls/store/selectors/calls';
|
||||
import {isCallsEnabled, isSupportedServer} from '@mmproducts/calls/store/selectors/calls';
|
||||
import {makeGetCustomStatus, isCustomStatusEnabled, isCustomStatusExpired, isCustomStatusExpirySupported} from '@selectors/custom_status';
|
||||
import {isGuest} from '@utils/users';
|
||||
|
||||
|
|
@ -61,7 +60,7 @@ function makeMapStateToProps() {
|
|||
currentChannelMemberCount = currentChannel.display_name.split(',').length;
|
||||
}
|
||||
|
||||
const callsFeatureEnabled = getFeatureFlagValue(state, 'CallsMobile') === 'true';
|
||||
const isSupportedServerCalls = isSupportedServer(state);
|
||||
|
||||
return {
|
||||
currentChannel,
|
||||
|
|
@ -79,7 +78,7 @@ function makeMapStateToProps() {
|
|||
isCustomStatusExpired: customStatusExpired,
|
||||
isCustomStatusExpirySupported: customStatusExpirySupported,
|
||||
isCallsEnabled: isCallsEnabled(state),
|
||||
callsFeatureEnabled,
|
||||
isSupportedServerCalls,
|
||||
isChannelAdmin,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue