* MM-25946 prompt sys admins if they are running server versions below 5.19 * Update alert message * Change alert buttons Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
parent
8af4ad793b
commit
07bc7a4c9f
7 changed files with 164 additions and 47 deletions
|
|
@ -95,8 +95,16 @@ const ViewTypes = keyMirror({
|
|||
LANDSCAPE: null,
|
||||
});
|
||||
|
||||
const RequiredServer = {
|
||||
FULL_VERSION: 5.19,
|
||||
MAJOR_VERSION: 5,
|
||||
MIN_VERSION: 19,
|
||||
PATCH_VERSION: 0,
|
||||
};
|
||||
|
||||
export default {
|
||||
...ViewTypes,
|
||||
RequiredServer,
|
||||
POST_VISIBILITY_CHUNK_SIZE: 15,
|
||||
FEATURE_TOGGLE_PREFIX: 'feature_enabled_',
|
||||
EMBED_PREVIEW: 'embed_preview',
|
||||
|
|
|
|||
|
|
@ -5,14 +5,16 @@ import React, {PureComponent} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {
|
||||
Alert,
|
||||
Keyboard,
|
||||
Linking,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
||||
|
||||
import {showModal, showModalOverCurrentContext} from '@actions/navigation';
|
||||
import LocalConfig from '@assets/config';
|
||||
import {NavigationTypes} from '@constants';
|
||||
import {NavigationTypes, ViewTypes} from '@constants';
|
||||
import EventEmitter from '@mm-redux/utils/event_emitter';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
|
@ -37,6 +39,7 @@ export default class ChannelBase extends PureComponent {
|
|||
currentChannelId: PropTypes.string,
|
||||
currentTeamId: PropTypes.string,
|
||||
disableTermsModal: PropTypes.bool,
|
||||
isSupportedServer: PropTypes.bool,
|
||||
teamName: PropTypes.string,
|
||||
theme: PropTypes.object.isRequired,
|
||||
showTermsOfService: PropTypes.bool,
|
||||
|
|
@ -67,31 +70,43 @@ export default class ChannelBase extends PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
actions,
|
||||
currentChannelId,
|
||||
currentTeamId,
|
||||
disableTermsModal,
|
||||
isSupportedServer,
|
||||
showTermsOfService,
|
||||
skipMetrics,
|
||||
} = this.props;
|
||||
EventEmitter.on(NavigationTypes.BLUR_POST_DRAFT, this.blurPostDraft);
|
||||
EventEmitter.on('leave_team', this.handleLeaveTeam);
|
||||
|
||||
if (this.props.currentTeamId) {
|
||||
this.loadChannels(this.props.currentTeamId);
|
||||
if (currentTeamId) {
|
||||
this.loadChannels(currentTeamId);
|
||||
} else {
|
||||
this.props.actions.selectDefaultTeam();
|
||||
actions.selectDefaultTeam();
|
||||
}
|
||||
|
||||
if (this.props.currentChannelId) {
|
||||
PushNotifications.clearChannelNotifications(this.props.currentChannelId);
|
||||
if (currentChannelId) {
|
||||
PushNotifications.clearChannelNotifications(currentChannelId);
|
||||
requestAnimationFrame(() => {
|
||||
this.props.actions.getChannelStats(this.props.currentChannelId);
|
||||
actions.getChannelStats(currentChannelId);
|
||||
});
|
||||
}
|
||||
|
||||
if (tracker.initialLoad && !this.props.skipMetrics) {
|
||||
this.props.actions.recordLoadTime('Start time', 'initialLoad');
|
||||
if (tracker.initialLoad && !skipMetrics) {
|
||||
actions.recordLoadTime('Start time', 'initialLoad');
|
||||
}
|
||||
|
||||
if (this.props.showTermsOfService && !this.props.disableTermsModal) {
|
||||
if (showTermsOfService && !disableTermsModal) {
|
||||
this.showTermsOfServiceModal();
|
||||
} else if (!isSupportedServer) {
|
||||
// Only display the Alert if the TOS does not need to show first
|
||||
this.showUnsupportedServer();
|
||||
}
|
||||
|
||||
if (!this.props.skipMetrics) {
|
||||
if (!skipMetrics) {
|
||||
telemetry.end(['start:channel_screen']);
|
||||
}
|
||||
}
|
||||
|
|
@ -140,31 +155,6 @@ export default class ChannelBase extends PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
showTermsOfServiceModal = async () => {
|
||||
const {intl} = this.context;
|
||||
const {theme} = this.props;
|
||||
const screen = 'TermsOfService';
|
||||
const title = intl.formatMessage({id: 'mobile.tos_link', defaultMessage: 'Terms of Service'});
|
||||
MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor).then((closeButton) => {
|
||||
const passProps = {closeButton};
|
||||
const options = {
|
||||
layout: {
|
||||
componentBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
topBar: {
|
||||
visible: true,
|
||||
height: null,
|
||||
title: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
text: title,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
showModalOverCurrentContext(screen, passProps, options);
|
||||
});
|
||||
};
|
||||
|
||||
goToChannelInfo = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const {theme} = this.props;
|
||||
|
|
@ -249,6 +239,62 @@ export default class ChannelBase extends PureComponent {
|
|||
return null;
|
||||
}
|
||||
|
||||
showTermsOfServiceModal = async () => {
|
||||
const {intl} = this.context;
|
||||
const {isSupportedServer, theme} = this.props;
|
||||
const screen = 'TermsOfService';
|
||||
const title = intl.formatMessage({id: 'mobile.tos_link', defaultMessage: 'Terms of Service'});
|
||||
MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor).then((closeButton) => {
|
||||
const passProps = {
|
||||
closeButton,
|
||||
isSupportedServer,
|
||||
showUnsupportedServer: this.showUnsupportedServer,
|
||||
};
|
||||
const options = {
|
||||
layout: {
|
||||
componentBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
topBar: {
|
||||
visible: true,
|
||||
height: null,
|
||||
title: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
text: title,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
showModalOverCurrentContext(screen, passProps, options);
|
||||
});
|
||||
};
|
||||
|
||||
showUnsupportedServer = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const title = formatMessage({id: 'mobile.server_upgrade.title', defaultMessage: 'Server upgrade required'});
|
||||
const message = formatMessage({
|
||||
id: 'mobile.server_upgrade.alert_description',
|
||||
defaultMessage: 'This server version is unsupported and users will be exposed to compatibility issues that cause crashes or severe bugs breaking core functionality of the app. Upgrading to server version {serverVersion} or later is required.',
|
||||
}, {serverVersion: ViewTypes.RequiredServer.FULL_VERSION});
|
||||
const cancel = {
|
||||
text: formatMessage({id: 'mobile.server_upgrade.dismiss', defaultMessage: 'Dismiss'}),
|
||||
style: 'default',
|
||||
};
|
||||
const learnMore = {
|
||||
text: formatMessage({id: 'mobile.server_upgrade.learn_more', defaultMessage: 'Learn More'}),
|
||||
style: 'cancel',
|
||||
onPress: () => {
|
||||
const url = 'https://mattermost.com/blog/support-for-esr-5-9-has-ended/';
|
||||
if (Linking.canOpenURL(url)) {
|
||||
Linking.openURL(url);
|
||||
}
|
||||
},
|
||||
};
|
||||
const buttons = [cancel, learnMore];
|
||||
const options = {cancelable: false};
|
||||
|
||||
Alert.alert(title, message, buttons, options);
|
||||
};
|
||||
|
||||
updateNativeScrollView = () => {
|
||||
if (this.keyboardTracker?.current) {
|
||||
this.keyboardTracker.current.resetScrollView(this.props.currentChannelId);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ describe('ChannelBase', () => {
|
|||
|
||||
const wrapper = shallow(
|
||||
<ChannelBase {...baseProps}/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
expect(mergeNavigationOptions.mock.calls).toEqual([]);
|
||||
|
|
|
|||
|
|
@ -7,20 +7,37 @@ import {connect} from 'react-redux';
|
|||
import {loadChannelsForTeam, selectInitialChannel} from '@actions/views/channel';
|
||||
import {recordLoadTime} from '@actions/views/root';
|
||||
import {selectDefaultTeam} from '@actions/views/select_team';
|
||||
import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels';
|
||||
import {getCurrentTeam} from '@mm-redux/selectors/entities/teams';
|
||||
import {getTheme} from '@mm-redux/selectors/entities/preferences';
|
||||
import {shouldShowTermsOfService} from '@mm-redux/selectors/entities/users';
|
||||
import {ViewTypes} from '@constants';
|
||||
import {getChannelStats} from '@mm-redux/actions/channels';
|
||||
import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels';
|
||||
import {getServerVersion} from '@mm-redux/selectors/entities/general';
|
||||
import {getTheme} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentTeam} from '@mm-redux/selectors/entities/teams';
|
||||
import {getCurrentUserId, getCurrentUserRoles, shouldShowTermsOfService} from '@mm-redux/selectors/entities/users';
|
||||
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
|
||||
import {isSystemAdmin as checkIsSystemAdmin} from '@mm-redux/utils/user_utils';
|
||||
|
||||
import Channel from './channel';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentTeam = getCurrentTeam(state);
|
||||
const roles = getCurrentUserId(state) ? getCurrentUserRoles(state) : '';
|
||||
const isSystemAdmin = checkIsSystemAdmin(roles);
|
||||
let isSupportedServer = true;
|
||||
|
||||
if (isSystemAdmin) {
|
||||
isSupportedServer = isMinimumServerVersion(
|
||||
getServerVersion(state),
|
||||
ViewTypes.RequiredServer.MAJOR_VERSION,
|
||||
ViewTypes.RequiredServer.MIN_VERSION,
|
||||
ViewTypes.RequiredServer.PATCH_VERSION,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
currentTeamId: currentTeam?.id,
|
||||
currentChannelId: getCurrentChannelId(state),
|
||||
isSupportedServer,
|
||||
teamName: currentTeam?.display_name,
|
||||
theme: getTheme(state),
|
||||
showTermsOfService: shouldShowTermsOfService(state),
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ export default class TermsOfService extends PureComponent {
|
|||
}).isRequired,
|
||||
componentId: PropTypes.string,
|
||||
closeButton: PropTypes.object,
|
||||
isSupportedServer: PropTypes.bool,
|
||||
showUnsupportedServer: PropTypes.func,
|
||||
siteName: PropTypes.string,
|
||||
theme: PropTypes.object,
|
||||
};
|
||||
|
|
@ -145,11 +147,18 @@ export default class TermsOfService extends PureComponent {
|
|||
};
|
||||
|
||||
handleAcceptTerms = () => {
|
||||
const onSuccess = () => {
|
||||
const {isSupportedServer, showUnsupportedServer} = this.props;
|
||||
dismissModal();
|
||||
|
||||
if (!isSupportedServer) {
|
||||
showUnsupportedServer();
|
||||
}
|
||||
};
|
||||
|
||||
this.registerUserAction(
|
||||
true,
|
||||
() => {
|
||||
dismissModal();
|
||||
},
|
||||
onSuccess,
|
||||
this.handleAcceptTerms,
|
||||
);
|
||||
};
|
||||
|
|
@ -189,7 +198,6 @@ export default class TermsOfService extends PureComponent {
|
|||
});
|
||||
|
||||
const {data} = await actions.updateMyTermsOfServiceStatus(this.state.termsId, accepted);
|
||||
|
||||
this.setState({
|
||||
loading: false,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {shallow} from 'enzyme';
|
|||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import * as NavigationActions from '@actions/navigation';
|
||||
import TestHelper from 'test/test_helper';
|
||||
|
||||
import TermsOfService from './terms_of_service.js';
|
||||
|
||||
|
|
@ -23,16 +24,18 @@ jest.mock('@utils/theme', () => {
|
|||
describe('TermsOfService', () => {
|
||||
const actions = {
|
||||
getTermsOfService: jest.fn(),
|
||||
updateMyTermsOfServiceStatus: jest.fn(),
|
||||
updateMyTermsOfServiceStatus: jest.fn().mockResolvedValue({data: true}),
|
||||
logout: jest.fn(),
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
actions,
|
||||
theme: Preferences.THEMES.default,
|
||||
closeButton: {},
|
||||
siteName: 'Mattermost',
|
||||
componentId: 'component-id',
|
||||
isSupportedServer: true,
|
||||
siteName: 'Mattermost',
|
||||
showUnsupportedServer: jest.fn(),
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
|
|
@ -130,4 +133,35 @@ describe('TermsOfService', () => {
|
|||
wrapper.instance().closeTermsAndLogout();
|
||||
expect(baseProps.actions.logout).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should NOT call showUnsupportedServer on acceptTerms if server is supported', async () => {
|
||||
const wrapper = shallow(
|
||||
<TermsOfService
|
||||
{...baseProps}
|
||||
/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
wrapper.setState({loading: false, termsId: 1, termsText: 'Terms Text'});
|
||||
wrapper.instance().handleAcceptTerms();
|
||||
TestHelper.wait(100).then(() => {
|
||||
expect(baseProps.showUnsupportedServer).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
test('should call showUnsupportedServer on acceptTerms if server not supported', async () => {
|
||||
const wrapper = shallow(
|
||||
<TermsOfService
|
||||
{...baseProps}
|
||||
isSupportedServer={false}
|
||||
/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
wrapper.setState({loading: false, termsId: 1, termsText: 'Terms Text'});
|
||||
wrapper.instance().handleAcceptTerms();
|
||||
TestHelper.wait(100).then(() => {
|
||||
expect(baseProps.showUnsupportedServer).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -453,8 +453,11 @@
|
|||
"mobile.server_link.unreachable_team.error": "This link belongs to a deleted team or to a team to which you do not have access.",
|
||||
"mobile.server_ssl.error.text": "The certificate from {host} is not trusted.\n\nPlease contact your System Administrator to resolve the certificate issues and allow connections to this server.",
|
||||
"mobile.server_ssl.error.title": "Untrusted Certificate",
|
||||
"mobile.server_upgrade.alert_description": "This server version is unsupported and users will be exposed to compatibility issues that cause crashes or severe bugs breaking core functionality of the app. Upgrading to server version {serverVersion} or later is required.",
|
||||
"mobile.server_upgrade.button": "OK",
|
||||
"mobile.server_upgrade.description": "\nA server upgrade is required to use the Mattermost app. Please ask your System Administrator for details.\n",
|
||||
"mobile.server_upgrade.dismiss": "Dismiss",
|
||||
"mobile.server_upgrade.learn_more": "Learn More",
|
||||
"mobile.server_upgrade.title": "Server upgrade required",
|
||||
"mobile.server_url.invalid_format": "URL must start with http:// or https://",
|
||||
"mobile.session_expired": "Session Expired: Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}}.",
|
||||
|
|
|
|||
Loading…
Reference in a new issue