summaryrefslogtreecommitdiffstats
path: root/webapp/components/user_settings
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/components/user_settings')
-rw-r--r--webapp/components/user_settings/custom_theme_chooser.jsx476
-rw-r--r--webapp/components/user_settings/desktop_notification_settings.jsx464
-rw-r--r--webapp/components/user_settings/email_notification_setting.jsx262
-rw-r--r--webapp/components/user_settings/import_theme_modal.jsx218
-rw-r--r--webapp/components/user_settings/manage_languages.jsx135
-rw-r--r--webapp/components/user_settings/premade_theme_chooser.jsx72
-rw-r--r--webapp/components/user_settings/user_settings.jsx124
-rw-r--r--webapp/components/user_settings/user_settings_advanced.jsx587
-rw-r--r--webapp/components/user_settings/user_settings_display.jsx673
-rw-r--r--webapp/components/user_settings/user_settings_general/index.js24
-rw-r--r--webapp/components/user_settings/user_settings_general/user_settings_general.jsx1245
-rw-r--r--webapp/components/user_settings/user_settings_modal.jsx309
-rw-r--r--webapp/components/user_settings/user_settings_notifications.jsx911
-rw-r--r--webapp/components/user_settings/user_settings_security/index.js34
-rw-r--r--webapp/components/user_settings/user_settings_security/user_settings_security.jsx1469
-rw-r--r--webapp/components/user_settings/user_settings_theme.jsx362
16 files changed, 0 insertions, 7365 deletions
diff --git a/webapp/components/user_settings/custom_theme_chooser.jsx b/webapp/components/user_settings/custom_theme_chooser.jsx
deleted file mode 100644
index 82bf99a0a..000000000
--- a/webapp/components/user_settings/custom_theme_chooser.jsx
+++ /dev/null
@@ -1,476 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import 'bootstrap-colorpicker';
-import $ from 'jquery';
-import PropTypes from 'prop-types';
-import React from 'react';
-import {Popover, OverlayTrigger} from 'react-bootstrap';
-import {defineMessages, FormattedMessage, intlShape, injectIntl} from 'react-intl';
-
-import Constants from 'utils/constants.jsx';
-import * as UserAgent from 'utils/user_agent.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-const messages = defineMessages({
- sidebarBg: {
- id: 'user.settings.custom_theme.sidebarBg',
- defaultMessage: 'Sidebar BG'
- },
- sidebarText: {
- id: 'user.settings.custom_theme.sidebarText',
- defaultMessage: 'Sidebar Text'
- },
- sidebarHeaderBg: {
- id: 'user.settings.custom_theme.sidebarHeaderBg',
- defaultMessage: 'Sidebar Header BG'
- },
- sidebarHeaderTextColor: {
- id: 'user.settings.custom_theme.sidebarHeaderTextColor',
- defaultMessage: 'Sidebar Header Text'
- },
- sidebarUnreadText: {
- id: 'user.settings.custom_theme.sidebarUnreadText',
- defaultMessage: 'Sidebar Unread Text'
- },
- sidebarTextHoverBg: {
- id: 'user.settings.custom_theme.sidebarTextHoverBg',
- defaultMessage: 'Sidebar Text Hover BG'
- },
- sidebarTextActiveBorder: {
- id: 'user.settings.custom_theme.sidebarTextActiveBorder',
- defaultMessage: 'Sidebar Text Active Border'
- },
- sidebarTextActiveColor: {
- id: 'user.settings.custom_theme.sidebarTextActiveColor',
- defaultMessage: 'Sidebar Text Active Color'
- },
- onlineIndicator: {
- id: 'user.settings.custom_theme.onlineIndicator',
- defaultMessage: 'Online Indicator'
- },
- awayIndicator: {
- id: 'user.settings.custom_theme.awayIndicator',
- defaultMessage: 'Away Indicator'
- },
- mentionBj: {
- id: 'user.settings.custom_theme.mentionBj',
- defaultMessage: 'Mention Jewel BG'
- },
- mentionColor: {
- id: 'user.settings.custom_theme.mentionColor',
- defaultMessage: 'Mention Jewel Text'
- },
- centerChannelBg: {
- id: 'user.settings.custom_theme.centerChannelBg',
- defaultMessage: 'Center Channel BG'
- },
- centerChannelColor: {
- id: 'user.settings.custom_theme.centerChannelColor',
- defaultMessage: 'Center Channel Text'
- },
- newMessageSeparator: {
- id: 'user.settings.custom_theme.newMessageSeparator',
- defaultMessage: 'New Message Separator'
- },
- linkColor: {
- id: 'user.settings.custom_theme.linkColor',
- defaultMessage: 'Link Color'
- },
- buttonBg: {
- id: 'user.settings.custom_theme.buttonBg',
- defaultMessage: 'Button BG'
- },
- buttonColor: {
- id: 'user.settings.custom_theme.buttonColor',
- defaultMessage: 'Button Text'
- },
- errorTextColor: {
- id: 'user.settings.custom_theme.errorTextColor',
- defaultMessage: 'Error Text Color'
- },
- mentionHighlightBg: {
- id: 'user.settings.custom_theme.mentionHighlightBg',
- defaultMessage: 'Mention Highlight BG'
- },
- mentionHighlightLink: {
- id: 'user.settings.custom_theme.mentionHighlightLink',
- defaultMessage: 'Mention Highlight Link'
- },
- codeTheme: {
- id: 'user.settings.custom_theme.codeTheme',
- defaultMessage: 'Code Theme'
- }
-});
-
-const HEX_CODE_LENGTH = 7;
-
-class CustomThemeChooser extends React.Component {
- constructor(props) {
- super(props);
- this.selectTheme = this.selectTheme.bind(this);
-
- const copyTheme = Object.assign({}, this.props.theme);
- delete copyTheme.type;
- delete copyTheme.image;
-
- this.state = {
- copyTheme: JSON.stringify(copyTheme)
- };
- }
-
- componentDidMount() {
- $('.color-picker').colorpicker({
- format: 'hex'
- });
- $('.color-picker').on('changeColor', this.onPickerChange);
- $('.group--code').on('change', this.onCodeThemeChange);
- document.addEventListener('click', this.closeColorpicker);
- }
-
- componentWillUnmount() {
- $('.color-picker').off('changeColor', this.onPickerChange);
- $('.group--code').off('change', this.onCodeThemeChange);
- document.removeEventListener('click', this.closeColorpicker);
- }
-
- componentDidUpdate() {
- const theme = this.props.theme;
- Constants.THEME_ELEMENTS.forEach((element) => {
- if (theme.hasOwnProperty(element.id) && element.id !== 'codeTheme') {
- $('#' + element.id).data('colorpicker').color.setColor(theme[element.id]);
- $('#' + element.id).colorpicker('update');
- }
- });
- }
-
- closeColorpicker(e) {
- if (!$(e.target).closest('.color-picker').length && Utils.isMobile()) {
- $('.color-picker').colorpicker('hide');
- }
- }
-
- onPickerChange = (e) => {
- const inputBox = e.target.childNodes[0];
- if (document.activeElement === inputBox && inputBox.value.length !== HEX_CODE_LENGTH) {
- return;
- }
-
- const theme = this.props.theme;
- if (theme[e.target.id] !== e.color.toHex()) {
- theme[e.target.id] = e.color.toHex();
- theme.type = 'custom';
- this.props.updateTheme(theme);
- }
- }
-
- pasteBoxChange = (e) => {
- let text = '';
-
- if (window.clipboardData && window.clipboardData.getData) { // IE
- text = window.clipboardData.getData('Text');
- } else {
- text = e.clipboardData.getData('Text');//e.clipboardData.getData('text/plain');
- }
-
- if (text.length === 0) {
- return;
- }
-
- let theme;
- try {
- theme = JSON.parse(text);
- } catch (err) {
- return;
- }
-
- this.setState({
- copyTheme: JSON.stringify(theme)
- });
-
- theme.type = 'custom';
- this.props.updateTheme(theme);
- }
-
- onChangeHandle = (e) => {
- e.stopPropagation();
- }
-
- selectTheme() {
- const textarea = this.refs.textarea;
- textarea.focus();
- textarea.setSelectionRange(0, this.state.copyTheme.length);
- }
-
- toggleSidebarStyles = (e) => {
- e.preventDefault();
-
- $(this.refs.sidebarStylesHeader).toggleClass('open');
- this.toggleSection(this.refs.sidebarStyles);
- }
-
- toggleCenterChannelStyles = (e) => {
- e.preventDefault();
-
- $(this.refs.centerChannelStylesHeader).toggleClass('open');
- this.toggleSection(this.refs.centerChannelStyles);
- }
-
- toggleLinkAndButtonStyles = (e) => {
- e.preventDefault();
-
- $(this.refs.linkAndButtonStylesHeader).toggleClass('open');
- this.toggleSection(this.refs.linkAndButtonStyles);
- }
-
- toggleSection(node) {
- if (UserAgent.isIos()) {
- // iOS doesn't support jQuery animations
- $(node).toggleClass('open');
- } else {
- $(node).slideToggle();
- }
- }
-
- onCodeThemeChange = (e) => {
- const theme = this.props.theme;
- theme.codeTheme = e.target.value;
- this.props.updateTheme(theme);
- }
-
- render() {
- const {formatMessage} = this.props.intl;
- const theme = this.props.theme;
-
- const sidebarElements = [];
- const centerChannelElements = [];
- const linkAndButtonElements = [];
- Constants.THEME_ELEMENTS.forEach((element, index) => {
- if (element.id === 'codeTheme') {
- const codeThemeOptions = [];
- let codeThemeURL = '';
-
- element.themes.forEach((codeTheme, codeThemeIndex) => {
- if (codeTheme.id === theme[element.id]) {
- codeThemeURL = codeTheme.iconURL;
- }
- codeThemeOptions.push(
- <option
- key={'code-theme-key' + codeThemeIndex}
- value={codeTheme.id}
- >
- {codeTheme.uiName}
- </option>
- );
- });
-
- var popoverContent = (
- <Popover
- bsStyle='info'
- id='code-popover'
- className='code-popover'
- >
- <img
- width='200'
- src={codeThemeURL}
- />
- </Popover>
- );
-
- centerChannelElements.push(
- <div
- className='col-sm-6 form-group'
- key={'custom-theme-key' + index}
- >
- <label className='custom-label'>{formatMessage(messages[element.id])}</label>
- <div
- className='input-group theme-group group--code dropdown'
- id={element.id}
- >
- <select
- className='form-control'
- type='text'
- defaultValue={theme[element.id]}
- >
- {codeThemeOptions}
- </select>
- <OverlayTrigger
- trigger={['hover', 'focus']}
- placement='top'
- overlay={popoverContent}
- ref='headerOverlay'
- >
- <span className='input-group-addon'>
- <img
- src={codeThemeURL}
- />
- </span>
- </OverlayTrigger>
- </div>
- </div>
- );
- } else if (element.group === 'centerChannelElements') {
- centerChannelElements.push(
- <div
- className='col-sm-6 form-group element'
- key={'custom-theme-key' + index}
- >
- <label className='custom-label'>{formatMessage(messages[element.id])}</label>
- <div
- className='input-group color-picker'
- id={element.id}
- >
- <input
- className='form-control'
- type='text'
- defaultValue={theme[element.id]}
- />
- <span className='input-group-addon'><i/></span>
- </div>
- </div>
- );
- } else if (element.group === 'sidebarElements') {
- sidebarElements.push(
- <div
- className='col-sm-6 form-group element'
- key={'custom-theme-key' + index}
- >
- <label className='custom-label'>{formatMessage(messages[element.id])}</label>
- <div
- className='input-group color-picker'
- id={element.id}
- >
- <input
- className='form-control'
- type='text'
- defaultValue={theme[element.id]}
- />
- <span className='input-group-addon'><i/></span>
- </div>
- </div>
- );
- } else {
- linkAndButtonElements.push(
- <div
- className='col-sm-6 form-group element'
- key={'custom-theme-key' + index}
- >
- <label className='custom-label'>{formatMessage(messages[element.id])}</label>
- <div
- className='input-group color-picker'
- id={element.id}
- >
- <input
- className='form-control'
- type='text'
- defaultValue={theme[element.id]}
- />
- <span className='input-group-addon'><i/></span>
- </div>
- </div>
- );
- }
- });
-
- const pasteBox = (
- <div className='col-sm-12'>
- <label className='custom-label'>
- <FormattedMessage
- id='user.settings.custom_theme.copyPaste'
- defaultMessage='Copy and paste to share theme colors:'
- />
- </label>
- <textarea
- ref='textarea'
- className='form-control'
- value={this.state.copyTheme}
- onPaste={this.pasteBoxChange}
- onChange={this.onChangeHandle}
- onClick={this.selectTheme}
- />
- </div>
- );
-
- return (
- <div className='appearance-section padding-top'>
- <div className='theme-elements row'>
- <div
- ref='sidebarStylesHeader'
- className='theme-elements__header'
- onClick={this.toggleSidebarStyles}
- >
- <FormattedMessage
- id='user.settings.custom_theme.sidebarTitle'
- defaultMessage='Sidebar Styles'
- />
- <div className='header__icon'>
- <i className='fa fa-plus'/>
- <i className='fa fa-minus'/>
- </div>
- </div>
- <div
- ref='sidebarStyles'
- className='theme-elements__body'
- >
- {sidebarElements}
- </div>
- </div>
- <div className='theme-elements row'>
- <div
- ref='centerChannelStylesHeader'
- className='theme-elements__header'
- onClick={this.toggleCenterChannelStyles}
- >
- <FormattedMessage
- id='user.settings.custom_theme.centerChannelTitle'
- defaultMessage='Center Channel Styles'
- />
- <div className='header__icon'>
- <i className='fa fa-plus'/>
- <i className='fa fa-minus'/>
- </div>
- </div>
- <div
- ref='centerChannelStyles'
- className='theme-elements__body'
- >
- {centerChannelElements}
- </div>
- </div>
- <div className='theme-elements row form-group'>
- <div
- ref='linkAndButtonStylesHeader'
- className='theme-elements__header'
- onClick={this.toggleLinkAndButtonStyles}
- >
- <FormattedMessage
- id='user.settings.custom_theme.linkButtonTitle'
- defaultMessage='Link and Button Styles'
- />
- <div className='header__icon'>
- <i className='fa fa-plus'/>
- <i className='fa fa-minus'/>
- </div>
- </div>
- <div
- ref='linkAndButtonStyles'
- className='theme-elements__body'
- >
- {linkAndButtonElements}
- </div>
- </div>
- <div className='row'>
- {pasteBox}
- </div>
- </div>
- );
- }
-}
-
-CustomThemeChooser.propTypes = {
- intl: intlShape.isRequired,
- theme: PropTypes.object.isRequired,
- updateTheme: PropTypes.func.isRequired
-};
-
-export default injectIntl(CustomThemeChooser);
diff --git a/webapp/components/user_settings/desktop_notification_settings.jsx b/webapp/components/user_settings/desktop_notification_settings.jsx
deleted file mode 100644
index abdbff512..000000000
--- a/webapp/components/user_settings/desktop_notification_settings.jsx
+++ /dev/null
@@ -1,464 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import SettingItemMin from 'components/setting_item_min.jsx';
-import SettingItemMax from 'components/setting_item_max.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-export default class DesktopNotificationSettings extends React.Component {
- constructor(props) {
- super(props);
-
- this.buildMaximizedSetting = this.buildMaximizedSetting.bind(this);
- this.buildMinimizedSetting = this.buildMinimizedSetting.bind(this);
-
- this.state = {};
- }
-
- buildMaximizedSetting() {
- const inputs = [];
- let extraInfo = null;
-
- const activityRadio = [false, false, false];
- if (this.props.activity === 'mention') {
- activityRadio[1] = true;
- } else if (this.props.activity === 'none') {
- activityRadio[2] = true;
- } else {
- activityRadio[0] = true;
- }
-
- let soundSection;
- let durationSection;
- if (this.props.activity !== 'none') {
- const soundRadio = [false, false];
- if (this.props.sound === 'false') {
- soundRadio[1] = true;
- } else {
- soundRadio[0] = true;
- }
-
- if (Utils.hasSoundOptions()) {
- soundSection = (
- <div>
- <hr/>
- <label>
- <FormattedMessage
- id='user.settings.notifications.desktop.sound'
- defaultMessage='Notification sound'
- />
- </label>
- <br/>
- <div className='radio'>
- <label>
- <input
- id='soundOn'
- type='radio'
- name='notificationSounds'
- checked={soundRadio[0]}
- onChange={() => this.props.setParentState('desktopSound', 'true')}
- />
- <FormattedMessage
- id='user.settings.notifications.on'
- defaultMessage='On'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='soundOff'
- type='radio'
- name='notificationSounds'
- checked={soundRadio[1]}
- onChange={() => this.props.setParentState('desktopSound', 'false')}
- />
- <FormattedMessage
- id='user.settings.notifications.off'
- defaultMessage='Off'
- />
- </label>
- <br/>
- </div>
- <br/>
- <span>
- <FormattedMessage
- id='user.settings.notifications.sounds_info'
- defaultMessage='Notification sounds are available on IE11, Safari, Chrome and Mattermost Desktop Apps.'
- />
- </span>
- </div>
- );
- } else {
- soundSection = (
- <div>
- <hr/>
- <label>
- <FormattedMessage
- id='user.settings.notifications.desktop.sound'
- defaultMessage='Notification sound'
- />
- </label>
- <br/>
- <FormattedMessage
- id='user.settings.notifications.soundConfig'
- defaultMessage='Please configure notification sounds in your browser settings'
- />
- </div>
- );
- }
-
- const durationRadio = [false, false, false, false];
- if (this.props.duration === '3') {
- durationRadio[0] = true;
- } else if (this.props.duration === '10') {
- durationRadio[2] = true;
- } else if (this.props.duration === '0') {
- durationRadio[3] = true;
- } else {
- durationRadio[1] = true;
- }
-
- durationSection = (
- <div>
- <hr/>
- <label>
- <FormattedMessage
- id='user.settings.notifications.desktop.duration'
- defaultMessage='Notification duration'
- />
- </label>
- <br/>
- <div className='radio'>
- <label>
- <input
- id='soundDuration3'
- type='radio'
- name='desktopDuration'
- checked={durationRadio[0]}
- onChange={() => this.props.setParentState('desktopDuration', '3')}
- />
- <FormattedMessage
- id='user.settings.notifications.desktop.seconds'
- defaultMessage='{seconds} seconds'
- values={{
- seconds: '3'
- }}
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='soundDuration5'
- type='radio'
- name='desktopDuration'
- checked={durationRadio[1]}
- onChange={() => this.props.setParentState('desktopDuration', '5')}
- />
- <FormattedMessage
- id='user.settings.notifications.desktop.seconds'
- defaultMessage='{seconds} seconds'
- values={{
- seconds: '5'
- }}
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='soundDuration10'
- type='radio'
- name='desktopDuration'
- checked={durationRadio[2]}
- onChange={() => this.props.setParentState('desktopDuration', '10')}
- />
- <FormattedMessage
- id='user.settings.notifications.desktop.seconds'
- defaultMessage='{seconds} seconds'
- values={{
- seconds: '10'
- }}
- />
- </label>
- </div>
- <div className='radio'>
- <label>
- <input
- id='soundDurationUnlimited'
- type='radio'
- name='desktopDuration'
- checked={durationRadio[3]}
- onChange={() => this.props.setParentState('desktopDuration', '0')}
- />
- <FormattedMessage
- id='user.settings.notifications.desktop.unlimited'
- defaultMessage='Unlimited'
- />
- </label>
- </div>
- </div>
- );
-
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.notifications.desktop.durationInfo'
- defaultMessage='Sets how long desktop notifications will remain on screen when using Firefox or Chrome. Desktop notifications in Edge and Safari can only stay on screen for a maximum of 5 seconds.'
- />
- </span>
- );
- }
-
- inputs.push(
- <div key='userNotificationLevelOption'>
- <label>
- <FormattedMessage
- id='user.settings.notifications.desktop'
- defaultMessage='Send desktop notifications'
- />
- </label>
- <br/>
- <div className='radio'>
- <label>
- <input
- id='desktopNotificationAllActivity'
- type='radio'
- name='desktopNotificationLevel'
- checked={activityRadio[0]}
- onChange={() => this.props.setParentState('desktopActivity', 'all')}
- />
- <FormattedMessage
- id='user.settings.notifications.allActivity'
- defaultMessage='For all activity'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='desktopNotificationMentions'
- type='radio'
- name='desktopNotificationLevel'
- checked={activityRadio[1]}
- onChange={() => this.props.setParentState('desktopActivity', 'mention')}
- />
- <FormattedMessage
- id='user.settings.notifications.onlyMentions'
- defaultMessage='Only for mentions and direct messages'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='desktopNotificationNever'
- type='radio'
- name='desktopNotificationLevel'
- checked={activityRadio[2]}
- onChange={() => this.props.setParentState('desktopActivity', 'none')}
- />
- <FormattedMessage
- id='user.settings.notifications.never'
- defaultMessage='Never'
- />
- </label>
- </div>
- <br/>
- <span>
- <FormattedMessage
- id='user.settings.notifications.info'
- defaultMessage='Desktop notifications are available on Edge, Firefox, Safari, Chrome and Mattermost Desktop Apps.'
- />
- </span>
- {soundSection}
- {durationSection}
- </div>
- );
-
- return (
- <SettingItemMax
- title={Utils.localizeMessage('user.settings.notifications.desktop.title', 'Desktop notifications')}
- extraInfo={extraInfo}
- inputs={inputs}
- submit={this.props.submit}
- server_error={this.props.error}
- updateSection={this.props.cancel}
- />
- );
- }
-
- buildMinimizedSetting() {
- let describe = '';
- if (this.props.activity === 'mention') {
- if (Utils.hasSoundOptions() && this.props.sound !== 'false') {
- if (this.props.duration === '0') { //eslint-disable-line no-lonely-if
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.mentionsSoundForever'
- defaultMessage='For mentions and direct messages, with sound, shown indefinitely'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.mentionsSoundTimed'
- defaultMessage='For mentions and direct messages, with sound, shown for {seconds} seconds'
- values={{
- seconds: this.props.duration
- }}
- />
- );
- }
- } else if (Utils.hasSoundOptions() && this.props.sound === 'false') {
- if (this.props.duration === '0') {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.mentionsNoSoundForever'
- defaultMessage='For mentions and direct messages, without sound, shown indefinitely'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.mentionsNoSoundTimed'
- defaultMessage='For mentions and direct messages, without sound, shown for {seconds} seconds'
- values={{
- seconds: this.props.duration
- }}
- />
- );
- }
- } else {
- if (this.props.duration === '0') { //eslint-disable-line no-lonely-if
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.mentionsSoundHiddenForever'
- defaultMessage='For mentions and direct messages, shown indefinitely'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.mentionsSoundHiddenTimed'
- defaultMessage='For mentions and direct messages, shown for {seconds} seconds'
- values={{
- seconds: this.props.duration
- }}
- />
- );
- }
- }
- } else if (this.props.activity === 'none') {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.off'
- defaultMessage='Off'
- />
- );
- } else {
- if (Utils.hasSoundOptions() && this.props.sound !== 'false') { //eslint-disable-line no-lonely-if
- if (this.props.duration === '0') { //eslint-disable-line no-lonely-if
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.allSoundForever'
- defaultMessage='For all activity, with sound, shown indefinitely'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.allSoundTimed'
- defaultMessage='For all activity, with sound, shown for {seconds} seconds'
- values={{
- seconds: this.props.duration
- }}
- />
- );
- }
- } else if (Utils.hasSoundOptions() && this.props.sound === 'false') {
- if (this.props.duration === '0') {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.allNoSoundForever'
- defaultMessage='For all activity, without sound, shown indefinitely'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.allNoSoundTimed'
- defaultMessage='For all activity, without sound, shown for {seconds} seconds'
- values={{
- seconds: this.props.duration
- }}
- />
- );
- }
- } else {
- if (this.props.duration === '0') { //eslint-disable-line no-lonely-if
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.allSoundHiddenForever'
- defaultMessage='For all activity, shown indefinitely'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.desktop.allSoundHiddenTimed'
- defaultMessage='For all activity, shown for {seconds} seconds'
- values={{
- seconds: this.props.duration
- }}
- />
- );
- }
- }
- }
-
- const handleUpdateDesktopSection = function updateDesktopSection() {
- this.props.updateSection('desktop');
- }.bind(this);
-
- return (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.notifications.desktop.title', 'Desktop notifications')}
- describe={describe}
- updateSection={handleUpdateDesktopSection}
- />
- );
- }
-
- render() {
- if (this.props.active) {
- return this.buildMaximizedSetting();
- }
-
- return this.buildMinimizedSetting();
- }
-}
-
-DesktopNotificationSettings.propTypes = {
- activity: PropTypes.string.isRequired,
- sound: PropTypes.string.isRequired,
- duration: PropTypes.string.isRequired,
- updateSection: PropTypes.func,
- setParentState: PropTypes.func,
- submit: PropTypes.func,
- cancel: PropTypes.func,
- error: PropTypes.string,
- active: PropTypes.bool
-};
diff --git a/webapp/components/user_settings/email_notification_setting.jsx b/webapp/components/user_settings/email_notification_setting.jsx
deleted file mode 100644
index bfba794ca..000000000
--- a/webapp/components/user_settings/email_notification_setting.jsx
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import {savePreference} from 'actions/user_actions.jsx';
-import {localizeMessage} from 'utils/utils.jsx';
-
-import {FormattedMessage} from 'react-intl';
-import SettingItemMin from 'components/setting_item_min.jsx';
-import SettingItemMax from 'components/setting_item_max.jsx';
-
-import {Preferences} from 'utils/constants.jsx';
-
-export default class EmailNotificationSetting extends React.Component {
- static propTypes = {
- activeSection: PropTypes.string.isRequired,
- updateSection: PropTypes.func.isRequired,
- enableEmail: PropTypes.bool.isRequired,
- emailInterval: PropTypes.number.isRequired,
- onSubmit: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired,
- serverError: PropTypes.string
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- enableEmail: props.enableEmail,
- emailInterval: props.emailInterval
- };
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.enableEmail !== this.props.enableEmail || nextProps.emailInterval !== this.props.emailInterval) {
- this.setState({
- enableEmail: nextProps.enableEmail,
- emailInterval: nextProps.emailInterval
- });
- }
- }
-
- handleChange = (enableEmail, emailInterval) => {
- this.setState({
- enableEmail,
- emailInterval
- });
- }
-
- handleSubmit = () => {
- // until the rest of the notification settings are moved to preferences, we have to do this separately
- savePreference(Preferences.CATEGORY_NOTIFICATIONS, Preferences.EMAIL_INTERVAL, this.state.emailInterval.toString());
-
- const {enableEmail} = this.state;
- this.props.onSubmit({enableEmail});
- }
-
- handleExpand = () => {
- this.props.updateSection('email');
- }
-
- handleCancel = (e) => {
- this.setState({
- enableEmail: this.props.enableEmail,
- emailInterval: this.props.emailInterval
- });
- this.props.onCancel(e);
- }
-
- render() {
- if (global.window.mm_config.SendEmailNotifications !== 'true' && this.props.activeSection === 'email') {
- const inputs = [];
-
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='padding-top'
- >
- <FormattedMessage
- id='user.settings.notifications.email.disabled_long'
- defaultMessage='Email notifications have been disabled by your System Administrator.'
- />
- </div>
- );
-
- return (
- <SettingItemMax
- title={localizeMessage('user.settings.notifications.emailNotifications', 'Email notifications')}
- inputs={inputs}
- server_error={this.state.serverError}
- updateSection={this.handleCancel}
- />
- );
- }
-
- if (this.props.activeSection !== 'email') {
- let description;
-
- if (global.window.mm_config.SendEmailNotifications !== 'true') {
- description = (
- <FormattedMessage
- id='user.settings.notifications.email.disabled'
- defaultMessage='Disabled by System Administrator'
- />
- );
- } else if (this.props.enableEmail) {
- switch (this.state.emailInterval) {
- case Preferences.INTERVAL_IMMEDIATE:
- description = (
- <FormattedMessage
- id='user.settings.notifications.email.immediately'
- defaultMessage='Immediately'
- />
- );
- break;
- case Preferences.INTERVAL_HOUR:
- description = (
- <FormattedMessage
- id='user.settings.notifications.email.everyHour'
- defaultMessage='Every hour'
- />
- );
- break;
- default:
- description = (
- <FormattedMessage
- id='user.settings.notifications.email.everyXMinutes'
- defaultMessage='Every {count, plural, one {minute} other {{count, number} minutes}}'
- values={{count: this.state.emailInterval / 60}}
- />
- );
- }
- } else {
- description = (
- <FormattedMessage
- id='user.settings.notifications.email.never'
- defaultMessage='Never'
- />
- );
- }
-
- return (
- <SettingItemMin
- title={localizeMessage('user.settings.notifications.emailNotifications', 'Email notifications')}
- describe={description}
- updateSection={this.handleExpand}
- />
- );
- }
-
- let batchingOptions = null;
- let batchingInfo = null;
- if (global.window.mm_config.EnableEmailBatching === 'true') {
- batchingOptions = (
- <div>
- <div className='radio'>
- <label>
- <input
- id='emailNotificationMinutes'
- type='radio'
- name='emailNotifications'
- checked={this.state.emailInterval === Preferences.INTERVAL_FIFTEEN_MINUTES}
- onChange={() => this.handleChange('true', Preferences.INTERVAL_FIFTEEN_MINUTES)}
- />
- <FormattedMessage
- id='user.settings.notifications.email.everyXMinutes'
- defaultMessage='Every {count} minutes'
- values={{count: Preferences.INTERVAL_FIFTEEN_MINUTES / 60}}
- />
- </label>
- </div>
- <div className='radio'>
- <label>
- <input
- id='emailNotificationHour'
- type='radio'
- name='emailNotifications'
- checked={this.state.emailInterval === Preferences.INTERVAL_HOUR}
- onChange={() => this.handleChange('true', Preferences.INTERVAL_HOUR)}
- />
- <FormattedMessage
- id='user.settings.notifications.email.everyHour'
- defaultMessage='Every hour'
- />
- </label>
- </div>
- </div>
- );
-
- batchingInfo = (
- <FormattedMessage
- id='user.settings.notifications.emailBatchingInfo'
- defaultMessage='Notifications received over the time period selected are combined and sent in a single email.'
- />
- );
- }
-
- return (
- <SettingItemMax
- title={localizeMessage('user.settings.notifications.emailNotifications', 'Email notifications')}
- inputs={[
- <div key='userNotificationEmailOptions'>
- <label>
- <FormattedMessage
- id='user.settings.notifications.email.send'
- defaultMessage='Send email notifications'
- />
- </label>
- <div className='radio'>
- <label>
- <input
- id='emailNotificationImmediately'
- type='radio'
- name='emailNotifications'
- checked={this.state.emailInterval === Preferences.INTERVAL_IMMEDIATE}
- onChange={() => this.handleChange('true', Preferences.INTERVAL_IMMEDIATE)}
- />
- <FormattedMessage
- id='user.settings.notifications.email.immediately'
- defaultMessage='Immediately'
- />
- </label>
- </div>
- {batchingOptions}
- <div className='radio'>
- <label>
- <input
- id='emailNotificationNever'
- type='radio'
- name='emailNotifications'
- checked={this.state.emailInterval === Preferences.INTERVAL_NEVER}
- onChange={() => this.handleChange('false', Preferences.INTERVAL_NEVER)}
- />
- <FormattedMessage
- id='user.settings.notifications.email.never'
- defaultMessage='Never'
- />
- </label>
- </div>
- <br/>
- <div>
- <FormattedMessage
- id='user.settings.notifications.emailInfo'
- defaultMessage='Email notifications are sent for mentions and direct messages when you are offline or away from {siteName} for more than 5 minutes.'
- values={{
- siteName: global.window.mm_config.SiteName
- }}
- />
- {' '}
- {batchingInfo}
- </div>
- </div>
- ]}
- submit={this.handleSubmit}
- server_error={this.props.serverError}
- updateSection={this.handleCancel}
- />
- );
- }
-}
diff --git a/webapp/components/user_settings/import_theme_modal.jsx b/webapp/components/user_settings/import_theme_modal.jsx
deleted file mode 100644
index d732daa52..000000000
--- a/webapp/components/user_settings/import_theme_modal.jsx
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ModalStore from 'stores/modal_store.jsx';
-import {Modal} from 'react-bootstrap';
-
-import Constants from 'utils/constants.jsx';
-
-import {FormattedMessage} from 'react-intl';
-
-const ActionTypes = Constants.ActionTypes;
-
-import React from 'react';
-
-export default class ImportThemeModal extends React.Component {
- constructor(props) {
- super(props);
-
- this.updateShow = this.updateShow.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- this.handleChange = this.handleChange.bind(this);
-
- this.state = {
- value: '',
- inputError: '',
- show: false,
- callback: null
- };
- }
-
- componentDidMount() {
- ModalStore.addModalListener(ActionTypes.TOGGLE_IMPORT_THEME_MODAL, this.updateShow);
- }
-
- componentWillUnmount() {
- ModalStore.removeModalListener(ActionTypes.TOGGLE_IMPORT_THEME_MODAL, this.updateShow);
- }
-
- updateShow(show, args) {
- this.setState({
- show,
- callback: args.callback
- });
- }
-
- handleSubmit(e) {
- e.preventDefault();
-
- const text = this.state.value;
-
- if (!this.isInputValid(text)) {
- this.setState({
- inputError: (
- <FormattedMessage
- id='user.settings.import_theme.submitError'
- defaultMessage='Invalid format, please try copying and pasting in again.'
- />
- )
- });
- return;
- }
-
- const colors = text.split(',');
- const theme = {type: 'custom'};
-
- theme.sidebarBg = colors[0];
- theme.sidebarText = colors[5];
- theme.sidebarUnreadText = colors[5];
- theme.sidebarTextHoverBg = colors[4];
- theme.sidebarTextActiveBorder = colors[2];
- theme.sidebarTextActiveColor = colors[3];
- theme.sidebarHeaderBg = colors[1];
- theme.sidebarHeaderTextColor = colors[5];
- theme.onlineIndicator = colors[6];
- theme.awayIndicator = '#E0B333';
- theme.mentionBj = colors[7];
- theme.mentionColor = '#ffffff';
- theme.centerChannelBg = '#ffffff';
- theme.centerChannelColor = '#333333';
- theme.newMessageSeparator = '#F80';
- theme.linkColor = '#2389d7';
- theme.buttonBg = '#26a970';
- theme.buttonColor = '#ffffff';
- theme.mentionHighlightBg = '#fff2bb';
- theme.mentionHighlightLink = '#2f81b7';
- theme.codeTheme = 'github';
-
- this.state.callback(theme);
- this.setState({
- show: false,
- callback: null
- });
- }
-
- isInputValid(text) {
- if (text.length === 0) {
- return false;
- }
-
- if (text.indexOf(' ') !== -1) {
- return false;
- }
-
- if (text.length > 0 && text.indexOf(',') === -1) {
- return false;
- }
-
- if (text.length > 0) {
- const colors = text.split(',');
-
- if (colors.length !== 8) {
- return false;
- }
-
- for (let i = 0; i < colors.length; i++) {
- if (colors[i].length !== 7 && colors[i].length !== 4) {
- return false;
- }
-
- if (colors[i].charAt(0) !== '#') {
- return false;
- }
- }
- }
-
- return true;
- }
-
- handleChange(e) {
- const value = e.target.value;
- this.setState({value});
-
- if (this.isInputValid(value)) {
- this.setState({inputError: null});
- } else {
- this.setState({
- inputError: (
- <FormattedMessage
- id='user.settings.import_theme.submitError'
- defaultMessage='Invalid format, please try copying and pasting in again.'
- />
- )
- });
- }
- }
-
- render() {
- return (
- <span>
- <Modal
- show={this.state.show}
- onHide={() => this.setState({show: false})}
- >
- <Modal.Header closeButton={true}>
- <Modal.Title>
- <FormattedMessage
- id='user.settings.import_theme.importHeader'
- defaultMessage='Import Slack Theme'
- />
- </Modal.Title>
- </Modal.Header>
- <form
- role='form'
- className='form-horizontal'
- >
- <Modal.Body>
- <p>
- <FormattedMessage
- id='user.settings.import_theme.importBody'
- defaultMessage='To import a theme, go to a Slack team and look for "Preferences -> Sidebar Theme". Open the custom theme option, copy the theme color values and paste them here:'
- />
- </p>
- <div className='form-group less'>
- <div className='col-sm-12'>
- <input
- id='themeVector'
- type='text'
- className='form-control'
- value={this.state.value}
- onChange={this.handleChange}
- />
- <div className='input__help'>
- {this.state.inputError}
- </div>
- </div>
- </div>
- </Modal.Body>
- <Modal.Footer>
- <button
- id='cancelButton'
- type='button'
- className='btn btn-default'
- onClick={() => this.setState({show: false})}
- >
- <FormattedMessage
- id='user.settings.import_theme.cancel'
- defaultMessage='Cancel'
- />
- </button>
- <button
- id='submitButton'
- onClick={this.handleSubmit}
- type='submit'
- className='btn btn-primary'
- tabIndex='3'
- >
- <FormattedMessage
- id='user.settings.import_theme.submit'
- defaultMessage='Submit'
- />
- </button>
- </Modal.Footer>
- </form>
- </Modal>
- </span>
- );
- }
-}
diff --git a/webapp/components/user_settings/manage_languages.jsx b/webapp/components/user_settings/manage_languages.jsx
deleted file mode 100644
index f83733c12..000000000
--- a/webapp/components/user_settings/manage_languages.jsx
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import SettingItemMax from '../setting_item_max.jsx';
-
-import * as I18n from 'i18n/i18n.jsx';
-import * as GlobalActions from 'actions/global_actions.jsx';
-import Constants from 'utils/constants.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import {updateUser} from 'actions/user_actions.jsx';
-import PropTypes from 'prop-types';
-import React from 'react';
-
-export default class ManageLanguage extends React.Component {
- constructor(props) {
- super(props);
-
- this.setLanguage = this.setLanguage.bind(this);
- this.changeLanguage = this.changeLanguage.bind(this);
- this.submitUser = this.submitUser.bind(this);
- this.state = {
- locale: props.locale
- };
- }
-
- setLanguage(e) {
- this.setState({locale: e.target.value});
- }
- changeLanguage(e) {
- e.preventDefault();
-
- this.submitUser({
- ...this.props.user,
- locale: this.state.locale
- });
- }
- submitUser(user) {
- updateUser(user, Constants.UserUpdateEvents.LANGUAGE,
- () => {
- GlobalActions.newLocalizationSelected(user.locale);
- },
- (err) => {
- let serverError;
- if (err.message) {
- serverError = err.message;
- } else {
- serverError = err;
- }
- this.setState({serverError});
- }
- );
- }
- render() {
- let serverError;
- if (this.state.serverError) {
- serverError = <label className='has-error'>{this.state.serverError}</label>;
- }
-
- const options = [];
- const locales = I18n.getLanguages();
-
- const languages = Object.keys(locales).map((l) => {
- return {
- value: locales[l].value,
- name: locales[l].name,
- order: locales[l].order
- };
- }).
- sort((a, b) => a.order - b.order);
-
- languages.forEach((lang) => {
- options.push(
- <option
- key={lang.value}
- value={lang.value}
- >
- {lang.name}
- </option>
- );
- });
-
- const input = (
- <div key='changeLanguage'>
- <br/>
- <label className='control-label'>
- <FormattedMessage
- id='user.settings.languages.change'
- defaultMessage='Change interface language'
- />
- </label>
- <div className='padding-top'>
- <select
- id='displayLanguage'
- ref='language'
- className='form-control'
- value={this.state.locale}
- onChange={this.setLanguage}
- >
- {options}
- </select>
- {serverError}
- </div>
- <div>
- <br/>
- <FormattedHTMLMessage
- id='user.settings.languages.promote'
- defaultMessage='Select which language Mattermost displays in the user interface.<br /><br />Would like to help with translations? Join the <a href="http://translate.mattermost.com/" target="_blank">Mattermost Translation Server</a> to contribute.'
- />
- </div>
- </div>
- );
-
- return (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.display.language'
- defaultMessage='Language'
- />
- }
- width='medium'
- submit={this.changeLanguage}
- inputs={[input]}
- updateSection={this.props.updateSection}
- />
- );
- }
-}
-
-ManageLanguage.propTypes = {
- user: PropTypes.object.isRequired,
- locale: PropTypes.string.isRequired,
- updateSection: PropTypes.func.isRequired
-};
diff --git a/webapp/components/user_settings/premade_theme_chooser.jsx b/webapp/components/user_settings/premade_theme_chooser.jsx
deleted file mode 100644
index 1bb2c6be9..000000000
--- a/webapp/components/user_settings/premade_theme_chooser.jsx
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-export default class PremadeThemeChooser extends React.Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
- render() {
- const theme = this.props.theme;
-
- const premadeThemes = [];
- const allowedThemes = global.mm_config.AllowedThemes ? global.mm_config.AllowedThemes.split(',') : [];
- const hasAllowedThemes = allowedThemes.length > 1 || (allowedThemes[0] && allowedThemes[0].trim().length > 0);
-
- for (const k in Constants.THEMES) {
- if (Constants.THEMES.hasOwnProperty(k)) {
- if (hasAllowedThemes && allowedThemes.indexOf(k) < 0) {
- continue;
- }
-
- const premadeTheme = $.extend(true, {}, Constants.THEMES[k]);
-
- let activeClass = '';
- if (premadeTheme.type === theme.type) {
- activeClass = 'active';
- }
-
- premadeThemes.push(
- <div
- className='col-xs-6 col-sm-3 premade-themes'
- key={'premade-theme-key' + k}
- >
- <div
- className={activeClass}
- onClick={() => this.props.updateTheme(premadeTheme)}
- >
- <label>
- <img
- className='img-responsive'
- src={premadeTheme.image}
- />
- <div className='theme-label'>{Utils.toTitleCase(premadeTheme.type)}</div>
- </label>
- </div>
- </div>
- );
- }
- }
-
- return (
- <div className='row appearance-section'>
- <div className='clearfix'>
- {premadeThemes}
- </div>
- </div>
- );
- }
-}
-
-PremadeThemeChooser.propTypes = {
- theme: PropTypes.object.isRequired,
- updateTheme: PropTypes.func.isRequired
-};
diff --git a/webapp/components/user_settings/user_settings.jsx b/webapp/components/user_settings/user_settings.jsx
deleted file mode 100644
index 4ad4153ce..000000000
--- a/webapp/components/user_settings/user_settings.jsx
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import UserStore from 'stores/user_store.jsx';
-import * as utils from 'utils/utils.jsx';
-import NotificationsTab from './user_settings_notifications.jsx';
-import SecurityTab from './user_settings_security';
-import GeneralTab from './user_settings_general';
-import DisplayTab from './user_settings_display.jsx';
-import AdvancedTab from './user_settings_advanced.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-export default class UserSettings extends React.Component {
- constructor(props) {
- super(props);
-
- this.onListenerChange = this.onListenerChange.bind(this);
-
- this.state = {user: UserStore.getCurrentUser()};
- }
-
- componentDidMount() {
- UserStore.addChangeListener(this.onListenerChange);
- }
-
- componentWillUnmount() {
- UserStore.removeChangeListener(this.onListenerChange);
- }
-
- onListenerChange() {
- var user = UserStore.getCurrentUser();
- if (!utils.areObjectsEqual(this.state.user, user)) {
- this.setState({user});
- }
- }
-
- render() {
- if (this.props.activeTab === 'general') {
- return (
- <div>
- <GeneralTab
- user={this.state.user}
- activeSection={this.props.activeSection}
- updateSection={this.props.updateSection}
- updateTab={this.props.updateTab}
- closeModal={this.props.closeModal}
- collapseModal={this.props.collapseModal}
- />
- </div>
- );
- } else if (this.props.activeTab === 'security') {
- return (
- <div>
- <SecurityTab
- user={this.state.user}
- activeSection={this.props.activeSection}
- updateSection={this.props.updateSection}
- updateTab={this.props.updateTab}
- closeModal={this.props.closeModal}
- collapseModal={this.props.collapseModal}
- setEnforceFocus={this.props.setEnforceFocus}
- />
- </div>
- );
- } else if (this.props.activeTab === 'notifications') {
- return (
- <div>
- <NotificationsTab
- user={this.state.user}
- activeSection={this.props.activeSection}
- updateSection={this.props.updateSection}
- updateTab={this.props.updateTab}
- closeModal={this.props.closeModal}
- collapseModal={this.props.collapseModal}
- />
- </div>
- );
- } else if (this.props.activeTab === 'display') {
- return (
- <div>
- <DisplayTab
- user={this.state.user}
- activeSection={this.props.activeSection}
- updateSection={this.props.updateSection}
- updateTab={this.props.updateTab}
- closeModal={this.props.closeModal}
- collapseModal={this.props.collapseModal}
- setEnforceFocus={this.props.setEnforceFocus}
- setRequireConfirm={this.props.setRequireConfirm}
- />
- </div>
- );
- } else if (this.props.activeTab === 'advanced') {
- return (
- <div>
- <AdvancedTab
- user={this.state.user}
- activeSection={this.props.activeSection}
- updateSection={this.props.updateSection}
- updateTab={this.props.updateTab}
- closeModal={this.props.closeModal}
- collapseModal={this.props.collapseModal}
- />
- </div>
- );
- }
-
- return <div/>;
- }
-}
-
-UserSettings.propTypes = {
- activeTab: PropTypes.string,
- activeSection: PropTypes.string,
- updateSection: PropTypes.func,
- updateTab: PropTypes.func,
- closeModal: PropTypes.func.isRequired,
- collapseModal: PropTypes.func.isRequired,
- setEnforceFocus: PropTypes.func.isRequired,
- setRequireConfirm: PropTypes.func.isRequired
-};
diff --git a/webapp/components/user_settings/user_settings_advanced.jsx b/webapp/components/user_settings/user_settings_advanced.jsx
deleted file mode 100644
index 0565310d5..000000000
--- a/webapp/components/user_settings/user_settings_advanced.jsx
+++ /dev/null
@@ -1,587 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import SettingItemMin from '../setting_item_min.jsx';
-import SettingItemMax from '../setting_item_max.jsx';
-
-import PreferenceStore from 'stores/preference_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-
-import Constants from 'utils/constants.jsx';
-const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
-import * as Utils from 'utils/utils.jsx';
-
-import {savePreferences} from 'actions/user_actions.jsx';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage} from 'react-intl';
-
-export default class AdvancedSettingsDisplay extends React.Component {
- constructor(props) {
- super(props);
-
- this.getStateFromStores = this.getStateFromStores.bind(this);
- this.updateSection = this.updateSection.bind(this);
- this.updateSetting = this.updateSetting.bind(this);
- this.toggleFeature = this.toggleFeature.bind(this);
- this.saveEnabledFeatures = this.saveEnabledFeatures.bind(this);
-
- this.renderFormattingSection = this.renderFormattingSection.bind(this);
- this.renderJoinLeaveSection = this.renderJoinLeaveSection.bind(this);
-
- this.state = this.getStateFromStores();
- }
-
- getStateFromStores() {
- let preReleaseFeaturesKeys = Object.keys(PreReleaseFeatures);
- const advancedSettings = PreferenceStore.getCategory(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS);
- const settings = {
- send_on_ctrl_enter: PreferenceStore.get(
- Constants.Preferences.CATEGORY_ADVANCED_SETTINGS,
- 'send_on_ctrl_enter',
- 'false'
- ),
- formatting: PreferenceStore.get(
- Constants.Preferences.CATEGORY_ADVANCED_SETTINGS,
- 'formatting',
- 'true'
- ),
- join_leave: PreferenceStore.get(
- Constants.Preferences.CATEGORY_ADVANCED_SETTINGS,
- 'join_leave',
- 'true'
- )
- };
-
- const webrtcEnabled = global.mm_config.EnableWebrtc === 'true';
- const linkPreviewsEnabled = global.mm_config.EnableLinkPreviews === 'true';
-
- if (!webrtcEnabled) {
- preReleaseFeaturesKeys = preReleaseFeaturesKeys.filter((f) => f !== 'WEBRTC_PREVIEW');
- }
-
- if (!linkPreviewsEnabled) {
- preReleaseFeaturesKeys = preReleaseFeaturesKeys.filter((f) => f !== 'EMBED_PREVIEW');
- }
-
- let enabledFeatures = 0;
- for (const [name, value] of advancedSettings) {
- for (const key of preReleaseFeaturesKeys) {
- const feature = PreReleaseFeatures[key];
-
- if (name === Constants.FeatureTogglePrefix + feature.label) {
- settings[name] = value;
-
- if (value === 'true') {
- enabledFeatures += 1;
- }
- }
- }
- }
-
- return {preReleaseFeatures: PreReleaseFeatures,
- settings,
- preReleaseFeaturesKeys,
- enabledFeatures
- };
- }
-
- updateSetting(setting, value) {
- const settings = this.state.settings;
- settings[setting] = value;
- this.setState(settings);
- }
-
- toggleFeature(feature, checked) {
- const settings = this.state.settings;
- settings[Constants.FeatureTogglePrefix + feature] = String(checked);
-
- let enabledFeatures = 0;
- Object.keys(this.state.settings).forEach((setting) => {
- if (setting.lastIndexOf(Constants.FeatureTogglePrefix) === 0 && this.state.settings[setting] === 'true') {
- enabledFeatures++;
- }
- });
-
- this.setState({settings, enabledFeatures});
- }
-
- saveEnabledFeatures() {
- const features = [];
- Object.keys(this.state.settings).forEach((setting) => {
- if (setting.lastIndexOf(Constants.FeatureTogglePrefix) === 0) {
- features.push(setting);
- }
- });
-
- this.handleSubmit(features);
- }
-
- handleSubmit(settings) {
- const preferences = [];
- const userId = UserStore.getCurrentId();
-
- // this should be refactored so we can actually be certain about what type everything is
- (Array.isArray(settings) ? settings : [settings]).forEach((setting) => {
- preferences.push({
- user_id: userId,
- category: Constants.Preferences.CATEGORY_ADVANCED_SETTINGS,
- name: setting,
- value: this.state.settings[setting]
- });
- });
-
- savePreferences(
- preferences,
- () => {
- this.updateSection('');
- }
- );
- }
-
- updateSection(section) {
- if ($('.section-max').length) {
- $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
- }
- if (!section) {
- this.setState(this.getStateFromStores());
- }
- this.props.updateSection(section);
- }
-
- renderOnOffLabel(enabled) {
- if (enabled === 'false') {
- return (
- <FormattedMessage
- id='user.settings.advance.off'
- defaultMessage='Off'
- />
- );
- }
-
- return (
- <FormattedMessage
- id='user.settings.advance.on'
- defaultMessage='On'
- />
- );
- }
-
- renderFormattingSection() {
- if (this.props.activeSection === 'formatting') {
- return (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.advance.formattingTitle'
- defaultMessage='Enable Post Formatting'
- />
- }
- inputs={[
- <div key='formattingSetting'>
- <div className='radio'>
- <label>
- <input
- id='postFormattingOn'
- type='radio'
- name='formatting'
- checked={this.state.settings.formatting !== 'false'}
- onChange={this.updateSetting.bind(this, 'formatting', 'true')}
- />
- <FormattedMessage
- id='user.settings.advance.on'
- defaultMessage='On'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='postFormattingOff'
- type='radio'
- name='formatting'
- checked={this.state.settings.formatting === 'false'}
- onChange={this.updateSetting.bind(this, 'formatting', 'false')}
- />
- <FormattedMessage
- id='user.settings.advance.off'
- defaultMessage='Off'
- />
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='user.settings.advance.formattingDesc'
- defaultMessage='If enabled, posts will be formatted to create links, show emoji, style the text, and add line breaks. By default, this setting is enabled. Changing this setting requires the page to be refreshed.'
- />
- </div>
- </div>
- ]}
- submit={() => this.handleSubmit('formatting')}
- server_error={this.state.serverError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- }
-
- return (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.advance.formattingTitle'
- defaultMessage='Enable Post Formatting'
- />
- }
- describe={this.renderOnOffLabel(this.state.settings.formatting)}
- updateSection={() => this.props.updateSection('formatting')}
- />
- );
- }
-
- renderJoinLeaveSection() {
- if (window.mm_config.BuildEnterpriseReady === 'true' && window.mm_license && window.mm_license.IsLicensed === 'true') {
- if (this.props.activeSection === 'join_leave') {
- return (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.advance.joinLeaveTitle'
- defaultMessage='Enable Join/Leave Messages'
- />
- }
- inputs={[
- <div key='joinLeaveSetting'>
- <div className='radio'>
- <label>
- <input
- id='joinLeaveOn'
- type='radio'
- name='join_leave'
- checked={this.state.settings.join_leave !== 'false'}
- onChange={this.updateSetting.bind(this, 'join_leave', 'true')}
- />
- <FormattedMessage
- id='user.settings.advance.on'
- defaultMessage='On'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='joinLeaveOff'
- type='radio'
- name='join_leave'
- checked={this.state.settings.join_leave === 'false'}
- onChange={this.updateSetting.bind(this, 'join_leave', 'false')}
- />
- <FormattedMessage
- id='user.settings.advance.off'
- defaultMessage='Off'
- />
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='user.settings.advance.joinLeaveDesc'
- defaultMessage='When "On", System Messages saying a user has joined or left a channel will be visible. When "Off", the System Messages about joining or leaving a channel will be hidden. A message will still show up when you are added to a channel, so you can receive a notification.'
- />
- </div>
- </div>
- ]}
- submit={() => this.handleSubmit('join_leave')}
- server_error={this.state.serverError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- }
-
- return (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.advance.joinLeaveTitle'
- defaultMessage='Enable Join/Leave Messages'
- />
- }
- describe={this.renderOnOffLabel(this.state.settings.join_leave)}
- updateSection={() => this.props.updateSection('join_leave')}
- />
- );
- }
-
- return null;
- }
-
- renderFeatureLabel(feature) {
- switch (feature) {
- case 'MARKDOWN_PREVIEW':
- return (
- <FormattedMessage
- id='user.settings.advance.markdown_preview'
- defaultMessage='Show markdown preview option in message input box'
- />
- );
- case 'EMBED_PREVIEW':
- return (
- <FormattedMessage
- id='user.settings.advance.embed_preview'
- defaultMessage='For the first web link in a message, display a preview of website content below the message, if available'
- />
- );
- case 'WEBRTC_PREVIEW':
- return (
- <FormattedMessage
- id='user.settings.advance.webrtc_preview'
- defaultMessage='Enable the ability to make and receive one-on-one WebRTC calls'
- />
- );
- default:
- return null;
- }
- }
-
- render() {
- const serverError = this.state.serverError || null;
- let ctrlSendSection;
-
- if (this.props.activeSection === 'advancedCtrlSend') {
- const ctrlSendActive = [
- this.state.settings.send_on_ctrl_enter === 'true',
- this.state.settings.send_on_ctrl_enter === 'false'
- ];
-
- const inputs = [
- <div key='ctrlSendSetting'>
- <div className='radio'>
- <label>
- <input
- id='ctrlSendOn'
- type='radio'
- name='sendOnCtrlEnter'
- checked={ctrlSendActive[0]}
- onChange={this.updateSetting.bind(this, 'send_on_ctrl_enter', 'true')}
- />
- <FormattedMessage
- id='user.settings.advance.on'
- defaultMessage='On'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='ctrlSendOff'
- type='radio'
- name='sendOnCtrlEnter'
- checked={ctrlSendActive[1]}
- onChange={this.updateSetting.bind(this, 'send_on_ctrl_enter', 'false')}
- />
- <FormattedMessage
- id='user.settings.advance.off'
- defaultMessage='Off'
- />
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='user.settings.advance.sendDesc'
- defaultMessage='If enabled ENTER inserts a new line and CTRL+ENTER submits the message.'
- />
- </div>
- </div>
- ];
- ctrlSendSection = (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.advance.sendTitle'
- defaultMessage='Send messages on CTRL+ENTER'
- />
- }
- inputs={inputs}
- submit={() => this.handleSubmit('send_on_ctrl_enter')}
- server_error={serverError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- } else {
- ctrlSendSection = (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.advance.sendTitle'
- defaultMessage='Send messages on CTRL+ENTER'
- />
- }
- describe={this.renderOnOffLabel(this.state.settings.send_on_ctrl_enter)}
- updateSection={() => this.props.updateSection('advancedCtrlSend')}
- />
- );
- }
-
- const formattingSection = this.renderFormattingSection();
- let formattingSectionDivider = null;
- if (formattingSection) {
- formattingSectionDivider = <div className='divider-light'/>;
- }
-
- const displayJoinLeaveSection = this.renderJoinLeaveSection();
- let displayJoinLeaveSectionDivider = null;
- if (displayJoinLeaveSection) {
- displayJoinLeaveSectionDivider = <div className='divider-light'/>;
- }
-
- let previewFeaturesSection;
- let previewFeaturesSectionDivider;
- if (this.state.preReleaseFeaturesKeys.length > 0) {
- previewFeaturesSectionDivider = (
- <div className='divider-light'/>
- );
-
- if (this.props.activeSection === 'advancedPreviewFeatures') {
- const inputs = [];
-
- this.state.preReleaseFeaturesKeys.forEach((key) => {
- const feature = this.state.preReleaseFeatures[key];
- inputs.push(
- <div key={'advancedPreviewFeatures_' + feature.label}>
- <div className='checkbox'>
- <label>
- <input
- id={'advancedPreviewFeatures' + feature.label}
- type='checkbox'
- checked={this.state.settings[Constants.FeatureTogglePrefix + feature.label] === 'true'}
- onChange={(e) => {
- this.toggleFeature(feature.label, e.target.checked);
- }}
- />
- {this.renderFeatureLabel(key)}
- </label>
- </div>
- </div>
- );
- });
-
- inputs.push(
- <div key='advancedPreviewFeatures_helptext'>
- <br/>
- <FormattedMessage
- id='user.settings.advance.preReleaseDesc'
- defaultMessage="Check any pre-released features you'd like to preview. You may also need to refresh the page before the setting will take effect."
- />
- </div>
- );
- previewFeaturesSection = (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.advance.preReleaseTitle'
- defaultMessage='Preview pre-release features'
- />
- }
- inputs={inputs}
- submit={this.saveEnabledFeatures}
- server_error={serverError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- } else {
- previewFeaturesSection = (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.advance.preReleaseTitle', 'Preview pre-release features')}
- describe={
- <FormattedMessage
- id='user.settings.advance.enabledFeatures'
- defaultMessage='{count, number} {count, plural, one {Feature} other {Features}} Enabled'
- values={{count: this.state.enabledFeatures}}
- />
- }
- updateSection={() => this.props.updateSection('advancedPreviewFeatures')}
- />
- );
- }
- }
-
- return (
- <div>
- <div className='modal-header'>
- <button
- id='closeButton'
- type='button'
- className='close'
- data-dismiss='modal'
- aria-label='Close'
- onClick={this.props.closeModal}
- >
- <span aria-hidden='true'>{'×'}</span>
- </button>
- <h4
- className='modal-title'
- ref='title'
- >
- <div className='modal-back'>
- <i
- className='fa fa-angle-left'
- onClick={this.props.collapseModal}
- />
- </div>
- <FormattedMessage
- id='user.settings.advance.title'
- defaultMessage='Advanced Settings'
- />
- </h4>
- </div>
- <div className='user-settings'>
- <h3 className='tab-header'>
- <FormattedMessage
- id='user.settings.advance.title'
- defaultMessage='Advanced Settings'
- />
- </h3>
- <div className='divider-dark first'/>
- {ctrlSendSection}
- {formattingSectionDivider}
- {formattingSection}
- {displayJoinLeaveSectionDivider}
- {displayJoinLeaveSection}
- {previewFeaturesSectionDivider}
- {previewFeaturesSection}
- <div className='divider-dark'/>
- </div>
- </div>
- );
- }
-}
-
-AdvancedSettingsDisplay.propTypes = {
- user: PropTypes.object,
- updateSection: PropTypes.func,
- updateTab: PropTypes.func,
- activeSection: PropTypes.string,
- closeModal: PropTypes.func.isRequired,
- collapseModal: PropTypes.func.isRequired
-};
diff --git a/webapp/components/user_settings/user_settings_display.jsx b/webapp/components/user_settings/user_settings_display.jsx
deleted file mode 100644
index f10b29900..000000000
--- a/webapp/components/user_settings/user_settings_display.jsx
+++ /dev/null
@@ -1,673 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import SettingItemMin from '../setting_item_min.jsx';
-import SettingItemMax from '../setting_item_max.jsx';
-import ManageLanguages from './manage_languages.jsx';
-import ThemeSetting from './user_settings_theme.jsx';
-
-import PreferenceStore from 'stores/preference_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-import * as Utils from 'utils/utils.jsx';
-import * as I18n from 'i18n/i18n.jsx';
-import {savePreferences} from 'actions/user_actions.jsx';
-
-import Constants from 'utils/constants.jsx';
-const Preferences = Constants.Preferences;
-
-import {FormattedMessage} from 'react-intl';
-
-function getDisplayStateFromStores() {
- return {
- militaryTime: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', 'false'),
- channelDisplayMode: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT),
- messageDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT),
- collapseDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSE_DISPLAY, Preferences.COLLAPSE_DISPLAY_DEFAULT)
- };
-}
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-export default class UserSettingsDisplay extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleSubmit = this.handleSubmit.bind(this);
- this.handleClockRadio = this.handleClockRadio.bind(this);
- this.updateSection = this.updateSection.bind(this);
- this.updateState = this.updateState.bind(this);
- this.createCollapseSection = this.createCollapseSection.bind(this);
-
- this.state = getDisplayStateFromStores();
- }
-
- handleSubmit() {
- const userId = UserStore.getCurrentId();
-
- const timePreference = {
- user_id: userId,
- category: Preferences.CATEGORY_DISPLAY_SETTINGS,
- name: 'use_military_time',
- value: this.state.militaryTime
- };
-
- const channelDisplayModePreference = {
- user_id: userId,
- category: Preferences.CATEGORY_DISPLAY_SETTINGS,
- name: Preferences.CHANNEL_DISPLAY_MODE,
- value: this.state.channelDisplayMode
- };
- const messageDisplayPreference = {
- user_id: userId,
- category: Preferences.CATEGORY_DISPLAY_SETTINGS,
- name: Preferences.MESSAGE_DISPLAY,
- value: this.state.messageDisplay
- };
- const collapseDisplayPreference = {
- user_id: userId,
- category: Preferences.CATEGORY_DISPLAY_SETTINGS,
- name: Preferences.COLLAPSE_DISPLAY,
- value: this.state.collapseDisplay
- };
-
- savePreferences([timePreference, channelDisplayModePreference, messageDisplayPreference, collapseDisplayPreference],
- () => {
- this.updateSection('');
- }
- );
- }
-
- handleClockRadio(militaryTime) {
- this.setState({militaryTime});
- }
-
- handleChannelDisplayModeRadio(channelDisplayMode) {
- this.setState({channelDisplayMode});
- }
-
- handlemessageDisplayRadio(messageDisplay) {
- this.setState({messageDisplay});
- }
-
- handleCollapseRadio(collapseDisplay) {
- this.setState({collapseDisplay});
- }
-
- updateSection(section) {
- if ($('.section-max').length) {
- $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
- }
- this.updateState();
- this.props.updateSection(section);
- }
-
- updateState() {
- const newState = getDisplayStateFromStores();
- if (!Utils.areObjectsEqual(newState, this.state)) {
- this.setState(newState);
- }
- }
-
- createCollapseSection() {
- if (this.props.activeSection === 'collapse') {
- const collapseFormat = [false, false];
- if (this.state.collapseDisplay === 'false') {
- collapseFormat[0] = true;
- } else {
- collapseFormat[1] = true;
- }
-
- const handleUpdateCollapseSection = (e) => {
- this.updateSection('');
- e.preventDefault();
- };
-
- const inputs = [
- <div key='userDisplayCollapseOptions'>
- <div className='radio'>
- <label>
- <input
- id='collapseFormat'
- type='radio'
- name='collapseFormat'
- checked={collapseFormat[0]}
- onChange={this.handleCollapseRadio.bind(this, 'false')}
- />
- <FormattedMessage
- id='user.settings.display.collapseOn'
- defaultMessage='On'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='collapseFormatOff'
- type='radio'
- name='collapseFormat'
- checked={collapseFormat[1]}
- onChange={this.handleCollapseRadio.bind(this, 'true')}
- />
- <FormattedMessage
- id='user.settings.display.collapseOff'
- defaultMessage='Off'
- />
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='user.settings.display.collapseDesc'
- defaultMessage='Set whether previews of image links show as expanded or collapsed by default. This setting can also be controlled using the slash commands /expand and /collapse.'
- />
- </div>
- </div>
- ];
-
- return (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.display.collapseDisplay'
- defaultMessage='Default appearance of image link previews'
- />
- }
- inputs={inputs}
- submit={this.handleSubmit}
- server_error={this.state.serverError}
- updateSection={handleUpdateCollapseSection}
- />
- );
- }
-
- let describe;
- if (this.state.collapseDisplay === 'false') {
- describe = (
- <FormattedMessage
- id='user.settings.display.collapseOn'
- defaultMessage='Expanded'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.display.collapseOff'
- defaultMessage='Collapsed'
- />
- );
- }
-
- const handleUpdateCollapseSection = () => {
- this.props.updateSection('collapse');
- };
-
- return (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.display.collapseDisplay'
- defaultMessage='Default appearance of image link previews'
- />
- }
- describe={describe}
- updateSection={handleUpdateCollapseSection}
- />
- );
- }
-
- render() {
- const serverError = this.state.serverError || null;
- let clockSection;
- let channelDisplayModeSection;
- let languagesSection;
- let messageDisplaySection;
-
- const collapseSection = this.createCollapseSection();
-
- if (this.props.activeSection === 'clock') {
- const clockFormat = [false, false];
- if (this.state.militaryTime === 'true') {
- clockFormat[1] = true;
- } else {
- clockFormat[0] = true;
- }
-
- const handleUpdateClockSection = (e) => {
- this.updateSection('');
- e.preventDefault();
- };
-
- const inputs = [
- <div key='userDisplayClockOptions'>
- <div className='radio'>
- <label>
- <input
- id='clockFormat12h'
- type='radio'
- name='clockFormat'
- checked={clockFormat[0]}
- onChange={this.handleClockRadio.bind(this, 'false')}
- />
- <FormattedMessage
- id='user.settings.display.normalClock'
- defaultMessage='12-hour clock (example: 4:00 PM)'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='clockFormat24h'
- type='radio'
- name='clockFormat'
- checked={clockFormat[1]}
- onChange={this.handleClockRadio.bind(this, 'true')}
- />
- <FormattedMessage
- id='user.settings.display.militaryClock'
- defaultMessage='24-hour clock (example: 16:00)'
- />
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='user.settings.display.preferTime'
- defaultMessage='Select how you prefer time displayed.'
- />
- </div>
- </div>
- ];
-
- clockSection = (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.display.clockDisplay'
- defaultMessage='Clock Display'
- />
- }
- inputs={inputs}
- submit={this.handleSubmit}
- server_error={serverError}
- updateSection={handleUpdateClockSection}
- />
- );
- } else {
- let describe;
- if (this.state.militaryTime === 'true') {
- describe = (
- <FormattedMessage
- id='user.settings.display.militaryClock'
- defaultMessage='24-hour clock (example: 16:00)'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.display.normalClock'
- defaultMessage='12-hour clock (example: 4:00 PM)'
- />
- );
- }
-
- const handleUpdateClockSection = () => {
- this.props.updateSection('clock');
- };
-
- clockSection = (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.display.clockDisplay'
- defaultMessage='Clock Display'
- />
- }
- describe={describe}
- updateSection={handleUpdateClockSection}
- />
- );
- }
-
- if (this.props.activeSection === Preferences.MESSAGE_DISPLAY) {
- const messageDisplay = [false, false];
- if (this.state.messageDisplay === Preferences.MESSAGE_DISPLAY_CLEAN) {
- messageDisplay[0] = true;
- } else {
- messageDisplay[1] = true;
- }
-
- const inputs = [
- <div key='userDisplayNameOptions'>
- <div className='radio'>
- <label>
- <input
- id='messageFormatStandard'
- type='radio'
- name='messageDisplay'
- checked={messageDisplay[0]}
- onChange={this.handlemessageDisplayRadio.bind(this, Preferences.MESSAGE_DISPLAY_CLEAN)}
- />
- <FormattedMessage
- id='user.settings.display.messageDisplayClean'
- defaultMessage='Standard'
- />
- {': '}
- <span className='font-weight--normal'>
- <FormattedMessage
- id='user.settings.display.messageDisplayCleanDes'
- defaultMessage='Easy to scan and read.'
- />
- </span>
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='messageFormatCompact'
- type='radio'
- name='messageDisplay'
- checked={messageDisplay[1]}
- onChange={this.handlemessageDisplayRadio.bind(this, Preferences.MESSAGE_DISPLAY_COMPACT)}
- />
- <FormattedMessage
- id='user.settings.display.messageDisplayCompact'
- defaultMessage='Compact'
- />
- {': '}
- <span className='font-weight--normal'>
- <FormattedMessage
- id='user.settings.display.messageDisplayCompactDes'
- defaultMessage='Fit as many messages on the screen as we can.'
- />
- </span>
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='user.settings.display.messageDisplayDescription'
- defaultMessage='Select how messages in a channel should be displayed.'
- />
- </div>
- </div>
- ];
-
- messageDisplaySection = (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.display.messageDisplayTitle'
- defaultMessage='Message Display'
- />
- }
- inputs={inputs}
- submit={this.handleSubmit}
- server_error={serverError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- } else {
- let describe;
- if (this.state.messageDisplay === Preferences.MESSAGE_DISPLAY_CLEAN) {
- describe = (
- <FormattedMessage
- id='user.settings.display.messageDisplayClean'
- defaultMessage='Standard'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.display.messageDisplayCompact'
- defaultMessage='Compact'
- />
- );
- }
-
- messageDisplaySection = (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.display.messageDisplayTitle'
- defaultMessage='Message Display'
- />
- }
- describe={describe}
- updateSection={() => {
- this.props.updateSection(Preferences.MESSAGE_DISPLAY);
- }}
- />
- );
- }
-
- if (this.props.activeSection === Preferences.CHANNEL_DISPLAY_MODE) {
- const channelDisplayMode = [false, false];
- if (this.state.channelDisplayMode === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN) {
- channelDisplayMode[0] = true;
- } else {
- channelDisplayMode[1] = true;
- }
-
- const inputs = [
- <div key='userDisplayNameOptions'>
- <div className='radio'>
- <label>
- <input
- id='channelDisplayFormatFullScreen'
- type='radio'
- name='channelDisplayMode'
- checked={channelDisplayMode[0]}
- onChange={this.handleChannelDisplayModeRadio.bind(this, Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN)}
- />
- <FormattedMessage
- id='user.settings.display.fullScreen'
- defaultMessage='Full width'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='channelDisplayFormatCentered'
- type='radio'
- name='channelDisplayMode'
- checked={channelDisplayMode[1]}
- onChange={this.handleChannelDisplayModeRadio.bind(this, Preferences.CHANNEL_DISPLAY_MODE_CENTERED)}
- />
- <FormattedMessage
- id='user.settings.display.fixedWidthCentered'
- defaultMessage='Fixed width, centered'
- />
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='user.settings.display.channeldisplaymode'
- defaultMessage='Select the width of the center channel.'
- />
- </div>
- </div>
- ];
-
- channelDisplayModeSection = (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.display.channelDisplayTitle'
- defaultMessage='Channel Display Mode'
- />
- }
- inputs={inputs}
- submit={this.handleSubmit}
- server_error={serverError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- } else {
- let describe;
- if (this.state.channelDisplayMode === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN) {
- describe = (
- <FormattedMessage
- id='user.settings.display.fullScreen'
- defaultMessage='Full width'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.display.fixedWidthCentered'
- defaultMessage='Fixed width, centered'
- />
- );
- }
-
- channelDisplayModeSection = (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.display.channelDisplayTitle'
- defaultMessage='Channel Display Mode'
- />
- }
- describe={describe}
- updateSection={() => {
- this.props.updateSection(Preferences.CHANNEL_DISPLAY_MODE);
- }}
- />
- );
- }
-
- let userLocale = this.props.user.locale;
- if (this.props.activeSection === 'languages') {
- if (!I18n.isLanguageAvailable(userLocale)) {
- userLocale = global.window.mm_config.DefaultClientLocale;
- }
- languagesSection = (
- <ManageLanguages
- user={this.props.user}
- locale={userLocale}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- } else {
- let locale;
- if (I18n.isLanguageAvailable(userLocale)) {
- locale = I18n.getLanguageInfo(userLocale).name;
- } else {
- locale = I18n.getLanguageInfo(global.window.mm_config.DefaultClientLocale).name;
- }
-
- languagesSection = (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.display.language'
- defaultMessage='Language'
- />
- }
- width='medium'
- describe={locale}
- updateSection={() => {
- this.updateSection('languages');
- }}
- />
- );
- }
-
- let themeSection;
- if (global.mm_config.EnableThemeSelection !== 'false') {
- themeSection = (
- <ThemeSetting
- selected={this.props.activeSection === 'theme'}
- updateSection={this.updateSection}
- setRequireConfirm={this.props.setRequireConfirm}
- setEnforceFocus={this.props.setEnforceFocus}
- />
- );
- }
-
- return (
- <div>
- <div className='modal-header'>
- <button
- id='closeButton'
- type='button'
- className='close'
- data-dismiss='modal'
- aria-label='Close'
- onClick={this.props.closeModal}
- >
- <span aria-hidden='true'>{'×'}</span>
- </button>
- <h4
- className='modal-title'
- ref='title'
- >
- <div className='modal-back'>
- <i
- className='fa fa-angle-left'
- onClick={this.props.collapseModal}
- />
- </div>
- <FormattedMessage
- id='user.settings.display.title'
- defaultMessage='Display Settings'
- />
- </h4>
- </div>
- <div className='user-settings'>
- <h3 className='tab-header'>
- <FormattedMessage
- id='user.settings.display.title'
- defaultMessage='Display Settings'
- />
- </h3>
- <div className='divider-dark first'/>
- {themeSection}
- <div className='divider-dark'/>
- {clockSection}
- <div className='divider-dark'/>
- {collapseSection}
- <div className='divider-dark'/>
- {messageDisplaySection}
- <div className='divider-dark'/>
- {channelDisplayModeSection}
- <div className='divider-dark'/>
- {languagesSection}
- </div>
- </div>
- );
- }
-}
-
-UserSettingsDisplay.propTypes = {
- user: PropTypes.object,
- updateSection: PropTypes.func,
- updateTab: PropTypes.func,
- activeSection: PropTypes.string,
- closeModal: PropTypes.func.isRequired,
- collapseModal: PropTypes.func.isRequired,
- setRequireConfirm: PropTypes.func.isRequired,
- setEnforceFocus: PropTypes.func.isRequired
-};
diff --git a/webapp/components/user_settings/user_settings_general/index.js b/webapp/components/user_settings/user_settings_general/index.js
deleted file mode 100644
index 90fd58bf2..000000000
--- a/webapp/components/user_settings/user_settings_general/index.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {getMe} from 'mattermost-redux/actions/users';
-
-import UserSettingsGeneralTab from './user_settings_general.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getMe
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(UserSettingsGeneralTab);
diff --git a/webapp/components/user_settings/user_settings_general/user_settings_general.jsx b/webapp/components/user_settings/user_settings_general/user_settings_general.jsx
deleted file mode 100644
index fc5f82f29..000000000
--- a/webapp/components/user_settings/user_settings_general/user_settings_general.jsx
+++ /dev/null
@@ -1,1245 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import SettingItemMin from 'components/setting_item_min.jsx';
-import SettingItemMax from 'components/setting_item_max.jsx';
-import SettingPicture from 'components/setting_picture.jsx';
-
-import UserStore from 'stores/user_store.jsx';
-import ErrorStore from 'stores/error_store.jsx';
-
-import Constants from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage, FormattedDate} from 'react-intl';
-import {updateUser, uploadProfileImage} from 'actions/user_actions.jsx';
-import {trackEvent} from 'actions/diagnostics_actions.jsx';
-
-const holders = defineMessages({
- usernameReserved: {
- id: 'user.settings.general.usernameReserved',
- defaultMessage: 'This username is reserved, please choose a new one.'
- },
- usernameRestrictions: {
- id: 'user.settings.general.usernameRestrictions',
- defaultMessage: "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-', and '_'."
- },
- validEmail: {
- id: 'user.settings.general.validEmail',
- defaultMessage: 'Please enter a valid email address.'
- },
- emailMatch: {
- id: 'user.settings.general.emailMatch',
- defaultMessage: 'The new emails you entered do not match.'
- },
- checkEmail: {
- id: 'user.settings.general.checkEmail',
- defaultMessage: 'Check your email at {email} to verify the address.'
- },
- validImage: {
- id: 'user.settings.general.validImage',
- defaultMessage: 'Only JPG or PNG images may be used for profile pictures'
- },
- imageTooLarge: {
- id: 'user.settings.general.imageTooLarge',
- defaultMessage: 'Unable to upload profile image. File is too large.'
- },
- uploadImage: {
- id: 'user.settings.general.uploadImage',
- defaultMessage: "Click 'Edit' to upload an image."
- },
- uploadImageMobile: {
- id: 'user.settings.general.mobile.uploadImage',
- defaultMessage: 'Click to upload an image.'
- },
- fullName: {
- id: 'user.settings.general.fullName',
- defaultMessage: 'Full Name'
- },
- nickname: {
- id: 'user.settings.general.nickname',
- defaultMessage: 'Nickname'
- },
- username: {
- id: 'user.settings.general.username',
- defaultMessage: 'Username'
- },
- profilePicture: {
- id: 'user.settings.general.profilePicture',
- defaultMessage: 'Profile Picture'
- },
- close: {
- id: 'user.settings.general.close',
- defaultMessage: 'Close'
- },
- position: {
- id: 'user.settings.general.position',
- defaultMessage: 'Position'
- }
-});
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-class UserSettingsGeneralTab extends React.Component {
- static propTypes = {
- intl: intlShape.isRequired,
- user: PropTypes.object.isRequired,
- updateSection: PropTypes.func.isRequired,
- updateTab: PropTypes.func.isRequired,
- activeSection: PropTypes.string.isRequired,
- closeModal: PropTypes.func.isRequired,
- collapseModal: PropTypes.func.isRequired,
- actions: PropTypes.shape({
- getMe: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
- this.submitActive = false;
-
- this.submitUsername = this.submitUsername.bind(this);
- this.submitNickname = this.submitNickname.bind(this);
- this.submitName = this.submitName.bind(this);
- this.submitEmail = this.submitEmail.bind(this);
- this.submitUser = this.submitUser.bind(this);
- this.submitPicture = this.submitPicture.bind(this);
- this.submitPosition = this.submitPosition.bind(this);
-
- this.updateUsername = this.updateUsername.bind(this);
- this.updateFirstName = this.updateFirstName.bind(this);
- this.updateLastName = this.updateLastName.bind(this);
- this.updateNickname = this.updateNickname.bind(this);
- this.updateEmail = this.updateEmail.bind(this);
- this.updateConfirmEmail = this.updateConfirmEmail.bind(this);
- this.updatePicture = this.updatePicture.bind(this);
- this.updateSection = this.updateSection.bind(this);
- this.updatePosition = this.updatePosition.bind(this);
-
- this.state = this.setupInitialState(props);
- }
-
- submitUsername(e) {
- e.preventDefault();
-
- const user = Object.assign({}, this.props.user);
- const username = this.state.username.trim().toLowerCase();
-
- const {formatMessage} = this.props.intl;
- const usernameError = Utils.isValidUsername(username);
- if (usernameError === 'Cannot use a reserved word as a username.') {
- this.setState({clientError: formatMessage(holders.usernameReserved), serverError: ''});
- return;
- } else if (usernameError) {
- this.setState({clientError: formatMessage(holders.usernameRestrictions, {min: Constants.MIN_USERNAME_LENGTH, max: Constants.MAX_USERNAME_LENGTH}), serverError: ''});
- return;
- }
-
- if (user.username === username) {
- this.updateSection('');
- return;
- }
-
- user.username = username;
-
- trackEvent('settings', 'user_settings_update', {field: 'username'});
-
- this.submitUser(user, Constants.UserUpdateEvents.USERNAME, false);
- }
-
- submitNickname(e) {
- e.preventDefault();
-
- const user = Object.assign({}, this.props.user);
- const nickname = this.state.nickname.trim();
-
- if (user.nickname === nickname) {
- this.updateSection('');
- return;
- }
-
- user.nickname = nickname;
-
- trackEvent('settings', 'user_settings_update', {field: 'username'});
-
- this.submitUser(user, Constants.UserUpdateEvents.NICKNAME, false);
- }
-
- submitName(e) {
- e.preventDefault();
-
- const user = Object.assign({}, this.props.user);
- const firstName = this.state.firstName.trim();
- const lastName = this.state.lastName.trim();
-
- if (user.first_name === firstName && user.last_name === lastName) {
- this.updateSection('');
- return;
- }
-
- user.first_name = firstName;
- user.last_name = lastName;
-
- trackEvent('settings', 'user_settings_update', {field: 'fullname'});
-
- this.submitUser(user, Constants.UserUpdateEvents.FULLNAME, false);
- }
-
- submitEmail(e) {
- e.preventDefault();
-
- const user = Object.assign({}, this.props.user);
- const email = this.state.email.trim().toLowerCase();
- const confirmEmail = this.state.confirmEmail.trim().toLowerCase();
-
- const {formatMessage} = this.props.intl;
-
- if (email === user.email && (confirmEmail === '' || confirmEmail === user.email)) {
- this.updateSection('');
- return;
- }
-
- if (email === '' || !Utils.isEmail(email)) {
- this.setState({emailError: formatMessage(holders.validEmail), clientError: '', serverError: ''});
- return;
- }
-
- if (email !== confirmEmail) {
- this.setState({emailError: formatMessage(holders.emailMatch), clientError: '', serverError: ''});
- return;
- }
-
- user.email = email;
- trackEvent('settings', 'user_settings_update', {field: 'email'});
- this.submitUser(user, Constants.UserUpdateEvents.EMAIL, true);
- }
-
- submitUser(user, type, emailUpdated) {
- updateUser(user, type,
- () => {
- this.updateSection('');
- this.props.actions.getMe();
- const verificationEnabled = global.window.mm_config.SendEmailNotifications === 'true' && global.window.mm_config.RequireEmailVerification === 'true' && emailUpdated;
-
- if (verificationEnabled) {
- ErrorStore.storeLastError({message: this.props.intl.formatMessage(holders.checkEmail, {email: user.email})});
- ErrorStore.emitChange();
- this.setState({emailChangeInProgress: true});
- }
- },
- (err) => {
- let serverError;
- if (err.message) {
- serverError = err.message;
- } else {
- serverError = err;
- }
- this.setState({serverError, emailError: '', clientError: ''});
- }
- );
- }
-
- submitPicture(e) {
- e.preventDefault();
-
- if (!this.state.pictureFile) {
- return;
- }
-
- if (!this.submitActive) {
- return;
- }
-
- trackEvent('settings', 'user_settings_update', {field: 'picture'});
-
- const {formatMessage} = this.props.intl;
- const file = this.state.pictureFile;
-
- if (file.type !== 'image/jpeg' && file.type !== 'image/png') {
- this.setState({clientError: formatMessage(holders.validImage), serverError: ''});
- return;
- } else if (file.size > this.state.maxFileSize) {
- this.setState({clientError: formatMessage(holders.imageTooLarge), serverError: ''});
- return;
- }
-
- this.setState({loadingPicture: true});
-
- uploadProfileImage(
- file,
- () => {
- this.updateSection('');
- this.submitActive = false;
- },
- (err) => {
- var state = this.setupInitialState(this.props);
- state.serverError = err.message;
- this.setState(state);
- }
- );
- }
-
- submitPosition(e) {
- e.preventDefault();
-
- const user = Object.assign({}, this.props.user);
- const position = this.state.position.trim();
-
- if (user.position === position) {
- this.updateSection('');
- return;
- }
-
- user.position = position;
-
- trackEvent('settings', 'user_settings_update', {field: 'position'});
-
- this.submitUser(user, Constants.UserUpdateEvents.Position, false);
- }
-
- updateUsername(e) {
- this.setState({username: e.target.value});
- }
-
- updateFirstName(e) {
- this.setState({firstName: e.target.value});
- }
-
- updateLastName(e) {
- this.setState({lastName: e.target.value});
- }
-
- updateNickname(e) {
- this.setState({nickname: e.target.value});
- }
-
- updatePosition(e) {
- this.setState({position: e.target.value});
- }
-
- updateEmail(e) {
- this.setState({email: e.target.value});
- }
-
- updateConfirmEmail(e) {
- this.setState({confirmEmail: e.target.value});
- }
-
- updatePicture(e) {
- if (e.target.files && e.target.files[0]) {
- this.setState({pictureFile: e.target.files[0]});
-
- this.submitActive = true;
- this.setState({clientError: null});
- } else {
- this.setState({pictureFile: null});
- }
- }
-
- updateSection(section) {
- if ($('.section-max').length) {
- $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
- }
- const emailChangeInProgress = this.state.emailChangeInProgress;
- this.setState(Object.assign({}, this.setupInitialState(this.props), {emailChangeInProgress, clientError: '', serverError: '', emailError: ''}));
- this.submitActive = false;
- this.props.updateSection(section);
- }
-
- setupInitialState(props) {
- const user = props.user;
-
- return {
- username: user.username,
- firstName: user.first_name,
- lastName: user.last_name,
- nickname: user.nickname,
- position: user.position,
- originalEmail: user.email,
- email: '',
- confirmEmail: '',
- pictureFile: null,
- loadingPicture: false,
- emailChangeInProgress: false,
- maxFileSize: global.window.mm_config.MaxFileSize
- };
- }
-
- createEmailSection() {
- let emailSection;
-
- if (this.props.activeSection === 'email') {
- const emailEnabled = global.window.mm_config.SendEmailNotifications === 'true';
- const emailVerificationEnabled = global.window.mm_config.RequireEmailVerification === 'true';
- const inputs = [];
-
- let helpText = (
- <FormattedMessage
- id='user.settings.general.emailHelp1'
- defaultMessage='Email is used for sign-in, notifications, and password reset. Email requires verification if changed.'
- />
- );
-
- if (!emailEnabled) {
- helpText = (
- <div className='setting-list__hint col-sm-12 text-danger'>
- <FormattedMessage
- id='user.settings.general.emailHelp2'
- defaultMessage='Email has been disabled by your System Administrator. No notification emails will be sent until it is enabled.'
- />
- </div>
- );
- } else if (!emailVerificationEnabled) {
- helpText = (
- <FormattedMessage
- id='user.settings.general.emailHelp3'
- defaultMessage='Email is used for sign-in, notifications, and password reset.'
- />
- );
- } else if (this.state.emailChangeInProgress) {
- const newEmail = UserStore.getCurrentUser().email;
- if (newEmail) {
- helpText = (
- <FormattedMessage
- id='user.settings.general.emailHelp4'
- defaultMessage='A verification email was sent to {email}.'
- values={{
- email: newEmail
- }}
- />
- );
- }
- }
-
- let submit = null;
-
- if (this.props.user.auth_service === '') {
- inputs.push(
- <div key='currentEmailSetting'>
- <div className='form-group'>
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.general.currentEmail'
- defaultMessage='Current Email'
- />
- </label>
- <div className='col-sm-7'>
- <label className='control-label'>{this.state.originalEmail}</label>
- </div>
- </div>
- </div>
- );
-
- inputs.push(
- <div key='emailSetting'>
- <div className='form-group'>
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.general.newEmail'
- defaultMessage='New Email'
- />
- </label>
- <div className='col-sm-7'>
- <input
- id='primaryEmail'
- className='form-control'
- type='email'
- onChange={this.updateEmail}
- value={this.state.email}
- />
- </div>
- </div>
- </div>
- );
-
- inputs.push(
- <div key='confirmEmailSetting'>
- <div className='form-group'>
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.general.confirmEmail'
- defaultMessage='Confirm Email'
- />
- </label>
- <div className='col-sm-7'>
- <input
- id='confirmEmail'
- className='form-control'
- type='email'
- onChange={this.updateConfirmEmail}
- value={this.state.confirmEmail}
- />
- </div>
- </div>
- {helpText}
- </div>
- );
-
- submit = this.submitEmail;
- } else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.general.emailGitlabCantUpdate'
- defaultMessage='Login occurs through GitLab. Email cannot be updated. Email address used for notifications is {email}.'
- values={{
- email: this.state.originalEmail
- }}
- />
- </div>
- {helpText}
- </div>
- );
- } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.general.emailGoogleCantUpdate'
- defaultMessage='Login occurs through Google Apps. Email cannot be updated. Email address used for notifications is {email}.'
- values={{
- email: this.state.originalEmail
- }}
- />
- </div>
- {helpText}
- </div>
- );
- } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.general.emailOffice365CantUpdate'
- defaultMessage='Login occurs through Office 365. Email cannot be updated. Email address used for notifications is {email}.'
- values={{
- email: this.state.originalEmail
- }}
- />
- </div>
- {helpText}
- </div>
- );
- } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='padding-bottom'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.general.emailLdapCantUpdate'
- defaultMessage='Login occurs through AD/LDAP. Email cannot be updated. Email address used for notifications is {email}.'
- values={{
- email: this.state.originalEmail
- }}
- />
- </div>
- </div>
- );
- } else if (this.props.user.auth_service === Constants.SAML_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='padding-bottom'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.general.emailSamlCantUpdate'
- defaultMessage='Login occurs through SAML. Email cannot be updated. Email address used for notifications is {email}.'
- values={{
- email: this.state.originalEmail
- }}
- />
- </div>
- {helpText}
- </div>
- );
- }
-
- emailSection = (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.general.email'
- defaultMessage='Email'
- />
- }
- inputs={inputs}
- submit={submit}
- server_error={this.state.serverError}
- client_error={this.state.emailError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- />
- );
- } else {
- let describe = '';
- if (this.props.user.auth_service === '') {
- if (this.state.emailChangeInProgress) {
- const newEmail = UserStore.getCurrentUser().email;
- if (newEmail) {
- describe = (
- <FormattedHTMLMessage
- id='user.settings.general.newAddress'
- defaultMessage='New Address: {email}<br />Check your email to verify the above address.'
- values={{
- email: newEmail
- }}
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.general.checkEmailNoAddress'
- defaultMessage='Check your email to verify your new address'
- />
- );
- }
- } else {
- describe = UserStore.getCurrentUser().email;
- }
- } else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.general.loginGitlab'
- defaultMessage='Login done through GitLab ({email})'
- values={{
- email: this.state.originalEmail
- }}
- />
- );
- } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.general.loginGoogle'
- defaultMessage='Login done through Google Apps ({email})'
- values={{
- email: this.state.originalEmail
- }}
- />
- );
- } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.general.loginOffice365'
- defaultMessage='Login done through Office 365 ({email})'
- values={{
- email: this.state.originalEmail
- }}
- />
- );
- } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.general.loginLdap'
- defaultMessage='Login done through AD/LDAP ({email})'
- values={{
- email: this.state.originalEmail
- }}
- />
- );
- } else if (this.props.user.auth_service === Constants.SAML_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.general.loginSaml'
- defaultMessage='Login done through SAML ({email})'
- values={{
- email: this.state.originalEmail
- }}
- />
- );
- }
-
- emailSection = (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.general.email'
- defaultMessage='Email'
- />
- }
- describe={describe}
- updateSection={() => {
- this.updateSection('email');
- }}
- />
- );
- }
-
- return emailSection;
- }
-
- render() {
- const user = this.props.user;
- const {formatMessage} = this.props.intl;
-
- let clientError = null;
- if (this.state.clientError) {
- clientError = this.state.clientError;
- }
- let serverError = null;
- if (this.state.serverError) {
- serverError = this.state.serverError;
- }
-
- let nameSection;
- const inputs = [];
-
- if (this.props.activeSection === 'name') {
- let extraInfo;
- let submit = null;
- if (this.props.user.auth_service === '' ||
- ((this.props.user.auth_service === 'ldap' || this.props.user.auth_service === Constants.SAML_SERVICE) &&
- (global.window.mm_config.FirstNameAttributeSet === 'false' || global.window.mm_config.LastNameAttributeSet === 'false'))) {
- inputs.push(
- <div
- key='firstNameSetting'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.general.firstName'
- defaultMessage='First Name'
- />
- </label>
- <div className='col-sm-7'>
- <input
- id='firstName'
- className='form-control'
- type='text'
- onChange={this.updateFirstName}
- value={this.state.firstName}
- />
- </div>
- </div>
- );
-
- inputs.push(
- <div
- key='lastNameSetting'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.general.lastName'
- defaultMessage='Last Name'
- />
- </label>
- <div className='col-sm-7'>
- <input
- id='lastName'
- className='form-control'
- type='text'
- onChange={this.updateLastName}
- value={this.state.lastName}
- />
- </div>
- </div>
- );
-
- function notifClick(e) {
- e.preventDefault();
- this.updateSection('');
- this.props.updateTab('notifications');
- }
-
- const notifLink = (
- <a
- href='#'
- onClick={notifClick.bind(this)}
- >
- <FormattedMessage
- id='user.settings.general.notificationsLink'
- defaultMessage='Notifications'
- />
- </a>
- );
-
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.notificationsExtra'
- defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.'
- values={{
- notify: (notifLink)
- }}
- />
- </span>
- );
-
- submit = this.submitName;
- } else {
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.field_handled_externally'
- defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so through your login provider.'
- />
- </span>
- );
- }
-
- nameSection = (
- <SettingItemMax
- title={formatMessage(holders.fullName)}
- inputs={inputs}
- submit={submit}
- server_error={serverError}
- client_error={clientError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- extraInfo={extraInfo}
- />
- );
- } else {
- let describe = '';
-
- if (user.first_name && user.last_name) {
- describe = user.first_name + ' ' + user.last_name;
- } else if (user.first_name) {
- describe = user.first_name;
- } else if (user.last_name) {
- describe = user.last_name;
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.general.emptyName'
- defaultMessage="Click 'Edit' to add your full name"
- />
- );
- if (Utils.isMobile()) {
- describe = (
- <FormattedMessage
- id='user.settings.general.mobile.emptyName'
- defaultMessage='Click to add your full name'
- />
- );
- }
- }
-
- nameSection = (
- <SettingItemMin
- title={formatMessage(holders.fullName)}
- describe={describe}
- updateSection={() => {
- this.updateSection('name');
- }}
- />
- );
- }
-
- let nicknameSection;
- if (this.props.activeSection === 'nickname') {
- let extraInfo;
- let submit = null;
- if ((this.props.user.auth_service === 'ldap' || this.props.user.auth_service === Constants.SAML_SERVICE) && global.window.mm_config.NicknameAttributeSet === 'true') {
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.field_handled_externally'
- defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.'
- />
- </span>
- );
- } else {
- let nicknameLabel = (
- <FormattedMessage
- id='user.settings.general.nickname'
- defaultMessage='Nickname'
- />
- );
- if (Utils.isMobile()) {
- nicknameLabel = '';
- }
-
- inputs.push(
- <div
- key='nicknameSetting'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>{nicknameLabel}</label>
- <div className='col-sm-7'>
- <input
- id='nickname'
- className='form-control'
- type='text'
- onChange={this.updateNickname}
- value={this.state.nickname}
- maxLength={Constants.MAX_NICKNAME_LENGTH}
- autoCapitalize='off'
- />
- </div>
- </div>
- );
-
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.nicknameExtra'
- defaultMessage='Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.'
- />
- </span>
- );
-
- submit = this.submitNickname;
- }
-
- nicknameSection = (
- <SettingItemMax
- title={formatMessage(holders.nickname)}
- inputs={inputs}
- submit={submit}
- server_error={serverError}
- client_error={clientError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- extraInfo={extraInfo}
- />
- );
- } else {
- let describe = '';
- if (user.nickname) {
- describe = user.nickname;
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.general.emptyNickname'
- defaultMessage="Click 'Edit' to add a nickname"
- />
- );
- if (Utils.isMobile()) {
- describe = (
- <FormattedMessage
- id='user.settings.general.mobile.emptyNickname'
- defaultMessage='Click to add a nickname'
- />
- );
- }
- }
-
- nicknameSection = (
- <SettingItemMin
- title={formatMessage(holders.nickname)}
- describe={describe}
- updateSection={() => {
- this.updateSection('nickname');
- }}
- />
- );
- }
-
- let usernameSection;
- if (this.props.activeSection === 'username') {
- let extraInfo;
- let submit = null;
- if (this.props.user.auth_service === '') {
- let usernameLabel = (
- <FormattedMessage
- id='user.settings.general.username'
- defaultMessage='Username'
- />
- );
- if (Utils.isMobile()) {
- usernameLabel = '';
- }
-
- inputs.push(
- <div
- key='usernameSetting'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>{usernameLabel}</label>
- <div className='col-sm-7'>
- <input
- id='username'
- maxLength={Constants.MAX_USERNAME_LENGTH}
- className='form-control'
- type='text'
- onChange={this.updateUsername}
- value={this.state.username}
- autoCapitalize='off'
- />
- </div>
- </div>
- );
-
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.usernameInfo'
- defaultMessage='Pick something easy for teammates to recognize and recall.'
- />
- </span>
- );
-
- submit = this.submitUsername;
- } else {
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.field_handled_externally'
- defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.'
- />
- </span>
- );
- }
-
- usernameSection = (
- <SettingItemMax
- title={formatMessage(holders.username)}
- inputs={inputs}
- submit={submit}
- server_error={serverError}
- client_error={clientError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- extraInfo={extraInfo}
- />
- );
- } else {
- usernameSection = (
- <SettingItemMin
- title={formatMessage(holders.username)}
- describe={UserStore.getCurrentUser().username}
- updateSection={() => {
- this.updateSection('username');
- }}
- />
- );
- }
-
- let positionSection;
- if (this.props.activeSection === 'position') {
- let extraInfo;
- let submit = null;
- if ((this.props.user.auth_service === 'ldap' || this.props.user.auth_service === Constants.SAML_SERVICE) && global.window.mm_config.PositionAttributeSet === 'true') {
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.field_handled_externally'
- defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.'
- />
- </span>
- );
- } else {
- let positionLabel = (
- <FormattedMessage
- id='user.settings.general.position'
- defaultMessage='Position'
- />
- );
- if (Utils.isMobile()) {
- positionLabel = '';
- }
-
- inputs.push(
- <div
- key='positionSetting'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>{positionLabel}</label>
- <div className='col-sm-7'>
- <input
- id='position'
- className='form-control'
- type='text'
- onChange={this.updatePosition}
- value={this.state.position}
- maxLength={Constants.MAX_POSITION_LENGTH}
- autoCapitalize='off'
- />
- </div>
- </div>
- );
-
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.general.positionExtra'
- defaultMessage='Use Position for your role or job title. This will be shown in your profile popover.'
- />
- </span>
- );
-
- submit = this.submitPosition;
- }
-
- positionSection = (
- <SettingItemMax
- title={formatMessage(holders.position)}
- inputs={inputs}
- submit={submit}
- server_error={serverError}
- client_error={clientError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- extraInfo={extraInfo}
- />
- );
- } else {
- let describe = '';
- if (user.position) {
- describe = user.position;
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.general.emptyPosition'
- defaultMessage="Click 'Edit' to add your job title / position"
- />
- );
- if (Utils.isMobile()) {
- describe = (
- <FormattedMessage
- id='user.settings.general.mobile.emptyPosition'
- defaultMessage='Click to add your job title / position'
- />
- );
- }
- }
-
- positionSection = (
- <SettingItemMin
- title={formatMessage(holders.position)}
- describe={describe}
- updateSection={() => {
- this.updateSection('position');
- }}
- />
- );
- }
-
- const emailSection = this.createEmailSection();
-
- let pictureSection;
- if (this.props.activeSection === 'picture') {
- pictureSection = (
- <SettingPicture
- title={formatMessage(holders.profilePicture)}
- submit={this.submitPicture}
- src={Utils.imageURLForUser(user)}
- serverError={serverError}
- clientError={clientError}
- updateSection={(e) => {
- this.updateSection('');
- e.preventDefault();
- }}
- file={this.state.pictureFile}
- onFileChange={this.updatePicture}
- submitActive={this.submitActive}
- loadingPicture={this.state.loadingPicture}
- />
- );
- } else {
- let minMessage = formatMessage(holders.uploadImage);
- if (Utils.isMobile()) {
- minMessage = formatMessage(holders.uploadImageMobile);
- }
- if (user.last_picture_update) {
- minMessage = (
- <FormattedMessage
- id='user.settings.general.imageUpdated'
- defaultMessage='Image last updated {date}'
- values={{
- date: (
- <FormattedDate
- value={new Date(user.last_picture_update)}
- day='2-digit'
- month='short'
- year='numeric'
- />
- )
- }}
- />
- );
- }
- pictureSection = (
- <SettingItemMin
- title={formatMessage(holders.profilePicture)}
- describe={minMessage}
- updateSection={() => {
- this.updateSection('picture');
- }}
- />
- );
- }
-
- return (
- <div>
- <div className='modal-header'>
- <button
- id='closeUserSettings'
- type='button'
- className='close'
- data-dismiss='modal'
- aria-label={formatMessage(holders.close)}
- onClick={this.props.closeModal}
- >
- <span aria-hidden='true'>{'×'}</span>
- </button>
- <h4
- className='modal-title'
- ref='title'
- >
- <div className='modal-back'>
- <i
- className='fa fa-angle-left'
- onClick={this.props.collapseModal}
- />
- </div>
- <FormattedMessage
- id='user.settings.general.title'
- defaultMessage='General Settings'
- />
- </h4>
- </div>
- <div className='user-settings'>
- <h3 className='tab-header'>
- <FormattedMessage
- id='user.settings.general.title'
- defaultMessage='General Settings'
- />
- </h3>
- <div className='divider-dark first'/>
- {nameSection}
- <div className='divider-light'/>
- {usernameSection}
- <div className='divider-light'/>
- {nicknameSection}
- <div className='divider-light'/>
- {positionSection}
- <div className='divider-light'/>
- {emailSection}
- <div className='divider-light'/>
- {pictureSection}
- <div className='divider-dark'/>
- </div>
- </div>
- );
- }
-}
-
-export default injectIntl(UserSettingsGeneralTab);
diff --git a/webapp/components/user_settings/user_settings_modal.jsx b/webapp/components/user_settings/user_settings_modal.jsx
deleted file mode 100644
index 665dbed68..000000000
--- a/webapp/components/user_settings/user_settings_modal.jsx
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import ReactDOM from 'react-dom';
-import ConfirmModal from '../confirm_modal.jsx';
-import UserSettings from './user_settings.jsx';
-import SettingsSidebar from '../settings_sidebar.jsx';
-
-import ModalStore from 'stores/modal_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-
-import {Modal} from 'react-bootstrap';
-
-import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
-
-const holders = defineMessages({
- general: {
- id: 'user.settings.modal.general',
- defaultMessage: 'General'
- },
- security: {
- id: 'user.settings.modal.security',
- defaultMessage: 'Security'
- },
- notifications: {
- id: 'user.settings.modal.notifications',
- defaultMessage: 'Notifications'
- },
- display: {
- id: 'user.settings.modal.display',
- defaultMessage: 'Display'
- },
- advanced: {
- id: 'user.settings.modal.advanced',
- defaultMessage: 'Advanced'
- },
- confirmTitle: {
- id: 'user.settings.modal.confirmTitle',
- defaultMessage: 'Discard Changes?'
- },
- confirmMsg: {
- id: 'user.settings.modal.confirmMsg',
- defaultMessage: 'You have unsaved changes, are you sure you want to discard them?'
- },
- confirmBtns: {
- id: 'user.settings.modal.confirmBtns',
- defaultMessage: 'Yes, Discard'
- }
-});
-
-import React from 'react';
-
-class UserSettingsModal extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleHide = this.handleHide.bind(this);
- this.handleHidden = this.handleHidden.bind(this);
- this.handleCollapse = this.handleCollapse.bind(this);
- this.handleConfirm = this.handleConfirm.bind(this);
- this.handleCancelConfirmation = this.handleCancelConfirmation.bind(this);
- this.handleToggle = this.handleToggle.bind(this);
- this.handleKeyDown = this.handleKeyDown.bind(this);
-
- this.closeModal = this.closeModal.bind(this);
- this.collapseModal = this.collapseModal.bind(this);
-
- this.updateTab = this.updateTab.bind(this);
- this.updateSection = this.updateSection.bind(this);
- this.onUserChanged = this.onUserChanged.bind(this);
-
- this.state = {
- active_tab: 'general',
- active_section: '',
- showConfirmModal: false,
- enforceFocus: true,
- currentUser: UserStore.getCurrentUser(),
- show: false
- };
-
- this.requireConfirm = false;
- this.mounted = false;
- }
-
- onUserChanged() {
- if (this.mounted) {
- this.setState({currentUser: UserStore.getCurrentUser()});
- }
- }
-
- componentDidMount() {
- this.mounted = true;
- UserStore.addChangeListener(this.onUserChanged);
- ModalStore.addModalListener(Constants.ActionTypes.TOGGLE_ACCOUNT_SETTINGS_MODAL, this.handleToggle);
- document.addEventListener('keydown', this.handleKeyDown);
- }
-
- componentWillUnmount() {
- this.mounted = false;
- ModalStore.removeModalListener(Constants.ActionTypes.TOGGLE_ACCOUNT_SETTINGS_MODAL, this.handleToggle);
- document.removeEventListener('keydown', this.handleKeyDown);
- }
-
- componentDidUpdate() {
- UserStore.removeChangeListener(this.onUserChanged);
- if (!Utils.isMobile()) {
- $('.settings-modal .modal-body').perfectScrollbar();
- }
- }
-
- handleKeyDown(e) {
- if (Utils.cmdOrCtrlPressed(e) && e.shiftKey && e.keyCode === Constants.KeyCodes.A) {
- this.setState({
- show: !this.state.show
- });
- }
- }
-
- handleToggle(value) {
- this.setState({
- show: value
- });
- }
-
- // Called when the close button is pressed on the main modal
- handleHide() {
- if (this.requireConfirm) {
- this.afterConfirm = () => this.handleHide();
- this.showConfirmModal();
-
- return;
- }
-
- this.setState({
- show: false
- });
- }
-
- // called after the dialog is fully hidden and faded out
- handleHidden() {
- this.setState({
- active_tab: 'general',
- active_section: ''
- });
- }
-
- // Called to hide the settings pane when on mobile
- handleCollapse() {
- $(ReactDOM.findDOMNode(this.refs.modalBody)).closest('.modal-dialog').removeClass('display--content');
-
- this.setState({
- active_tab: '',
- active_section: ''
- });
- }
-
- handleConfirm() {
- this.setState({
- showConfirmModal: false,
- enforceFocus: true
- });
-
- this.requireConfirm = false;
-
- if (this.afterConfirm) {
- this.afterConfirm();
- this.afterConfirm = null;
- }
- }
-
- handleCancelConfirmation() {
- this.setState({
- showConfirmModal: false,
- enforceFocus: true
- });
-
- this.afterConfirm = null;
- }
-
- showConfirmModal(afterConfirm) {
- this.setState({
- showConfirmModal: true,
- enforceFocus: false
- });
-
- if (afterConfirm) {
- this.afterConfirm = afterConfirm;
- }
- }
-
- // Called by settings tabs when their close button is pressed
- closeModal() {
- if (this.requireConfirm) {
- this.showConfirmModal(this.closeModal);
- } else {
- this.handleHide();
- }
- }
-
- // Called by settings tabs when their back button is pressed
- collapseModal() {
- if (this.requireConfirm) {
- this.showConfirmModal(this.collapseModal);
- } else {
- this.handleCollapse();
- }
- }
-
- updateTab(tab, skipConfirm) {
- if (!skipConfirm && this.requireConfirm) {
- this.showConfirmModal(() => this.updateTab(tab, true));
- } else {
- this.setState({
- active_tab: tab,
- active_section: ''
- });
- }
-
- if (!Utils.isMobile()) {
- $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
- }
- }
-
- updateSection(section, skipConfirm) {
- if (!skipConfirm && this.requireConfirm) {
- this.showConfirmModal(() => this.updateSection(section, true));
- } else {
- this.setState({active_section: section});
- }
- }
-
- render() {
- const {formatMessage} = this.props.intl;
- if (this.state.currentUser == null) {
- return (<div/>);
- }
- var tabs = [];
-
- tabs.push({name: 'general', uiName: formatMessage(holders.general), icon: 'icon fa fa-gear'});
- tabs.push({name: 'security', uiName: formatMessage(holders.security), icon: 'icon fa fa-lock'});
- tabs.push({name: 'notifications', uiName: formatMessage(holders.notifications), icon: 'icon fa fa-exclamation-circle'});
- tabs.push({name: 'display', uiName: formatMessage(holders.display), icon: 'icon fa fa-eye'});
- tabs.push({name: 'advanced', uiName: formatMessage(holders.advanced), icon: 'icon fa fa-list-alt'});
-
- return (
- <Modal
- dialogClassName='settings-modal'
- show={this.state.show}
- onHide={this.handleHide}
- onExited={this.handleHidden}
- enforceFocus={this.state.enforceFocus}
- >
- <Modal.Header closeButton={true}>
- <Modal.Title>
- <FormattedMessage
- id='user.settings.modal.title'
- defaultMessage='Account Settings'
- />
- </Modal.Title>
- </Modal.Header>
- <Modal.Body ref='modalBody'>
- <div className='settings-table'>
- <div className='settings-links'>
- <SettingsSidebar
- tabs={tabs}
- activeTab={this.state.active_tab}
- updateTab={this.updateTab}
- />
- </div>
- <div className='settings-content minimize-settings'>
- <UserSettings
- ref='userSettings'
- activeTab={this.state.active_tab}
- activeSection={this.state.active_section}
- updateSection={this.updateSection}
- updateTab={this.updateTab}
- closeModal={this.closeModal}
- collapseModal={this.collapseModal}
- setEnforceFocus={(enforceFocus) => this.setState({enforceFocus})}
- setRequireConfirm={
- (requireConfirm) => {
- this.requireConfirm = requireConfirm;
- }
- }
- />
- </div>
- </div>
- </Modal.Body>
- <ConfirmModal
- title={formatMessage(holders.confirmTitle)}
- message={formatMessage(holders.confirmMsg)}
- confirmButtonText={formatMessage(holders.confirmBtns)}
- show={this.state.showConfirmModal}
- onConfirm={this.handleConfirm}
- onCancel={this.handleCancelConfirmation}
- />
- </Modal>
- );
- }
-}
-
-UserSettingsModal.propTypes = {
- intl: intlShape.isRequired
-};
-
-export default injectIntl(UserSettingsModal);
diff --git a/webapp/components/user_settings/user_settings_notifications.jsx b/webapp/components/user_settings/user_settings_notifications.jsx
deleted file mode 100644
index 5d6457527..000000000
--- a/webapp/components/user_settings/user_settings_notifications.jsx
+++ /dev/null
@@ -1,911 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import SettingItemMin from 'components/setting_item_min.jsx';
-import SettingItemMax from 'components/setting_item_max.jsx';
-import DesktopNotificationSettings from './desktop_notification_settings.jsx';
-
-import UserStore from 'stores/user_store.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-import {updateUserNotifyProps} from 'actions/user_actions.jsx';
-
-import EmailNotificationSetting from './email_notification_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-
-function getNotificationsStateFromStores() {
- const user = UserStore.getCurrentUser();
-
- let desktop = 'default';
- let sound = 'true';
- let desktopDuration = '5';
- let comments = 'never';
- let enableEmail = 'true';
- let pushActivity = 'mention';
- let pushStatus = Constants.UserStatuses.ONLINE;
-
- if (user.notify_props) {
- if (user.notify_props.desktop) {
- desktop = user.notify_props.desktop;
- }
- if (user.notify_props.desktop_sound) {
- sound = user.notify_props.desktop_sound;
- }
- if (user.notify_props.desktop_duration) {
- desktopDuration = user.notify_props.desktop_duration;
- }
- if (user.notify_props.comments) {
- comments = user.notify_props.comments;
- }
- if (user.notify_props.email) {
- enableEmail = user.notify_props.email;
- }
- if (user.notify_props.push) {
- pushActivity = user.notify_props.push;
- }
- if (user.notify_props.push_status) {
- pushStatus = user.notify_props.push_status;
- }
- }
-
- let usernameKey = false;
- let customKeys = '';
- let firstNameKey = false;
- let channelKey = false;
-
- if (user.notify_props) {
- if (user.notify_props.mention_keys) {
- const keys = user.notify_props.mention_keys.split(',');
-
- if (keys.indexOf(user.username) === -1) {
- usernameKey = false;
- } else {
- usernameKey = true;
- keys.splice(keys.indexOf(user.username), 1);
- if (keys.indexOf(`@${user.username}`) !== -1) {
- keys.splice(keys.indexOf(`@${user.username}`), 1);
- }
- }
-
- customKeys = keys.join(',');
- }
-
- if (user.notify_props.first_name) {
- firstNameKey = user.notify_props.first_name === 'true';
- }
-
- if (user.notify_props.channel) {
- channelKey = user.notify_props.channel === 'true';
- }
- }
-
- return {
- desktopActivity: desktop,
- desktopDuration,
- enableEmail,
- pushActivity,
- pushStatus,
- desktopSound: sound,
- usernameKey,
- customKeys,
- customKeysChecked: customKeys.length > 0,
- firstNameKey,
- channelKey,
- notifyCommentsLevel: comments
- };
-}
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-export default class NotificationsTab extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleSubmit = this.handleSubmit.bind(this);
- this.handleCancel = this.handleCancel.bind(this);
- this.updateSection = this.updateSection.bind(this);
- this.setStateValue = this.setStateValue.bind(this);
- this.onListenerChange = this.onListenerChange.bind(this);
- this.handleEmailRadio = this.handleEmailRadio.bind(this);
- this.updateUsernameKey = this.updateUsernameKey.bind(this);
- this.updateFirstNameKey = this.updateFirstNameKey.bind(this);
- this.updateChannelKey = this.updateChannelKey.bind(this);
- this.updateCustomMentionKeys = this.updateCustomMentionKeys.bind(this);
- this.updateState = this.updateState.bind(this);
- this.onCustomChange = this.onCustomChange.bind(this);
- this.createPushNotificationSection = this.createPushNotificationSection.bind(this);
-
- this.state = getNotificationsStateFromStores();
- }
-
- handleSubmit({enableEmail = this.state.enableEmail}) {
- const data = {};
- data.user_id = this.props.user.id;
- data.email = enableEmail;
- data.desktop_sound = this.state.desktopSound;
- data.desktop = this.state.desktopActivity;
- data.desktop_duration = this.state.desktopDuration;
- data.push = this.state.pushActivity;
- data.push_status = this.state.pushStatus;
- data.comments = this.state.notifyCommentsLevel;
-
- const mentionKeys = [];
- if (this.state.usernameKey) {
- mentionKeys.push(this.props.user.username);
- }
-
- let stringKeys = mentionKeys.join(',');
- if (this.state.customKeys.length > 0 && this.state.customKeysChecked) {
- stringKeys += ',' + this.state.customKeys;
- }
-
- data.mention_keys = stringKeys;
- data.first_name = this.state.firstNameKey.toString();
- data.channel = this.state.channelKey.toString();
-
- updateUserNotifyProps(
- data,
- () => {
- this.props.updateSection('');
- $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
- },
- (err) => {
- this.setState({serverError: err.message});
- }
- );
- }
-
- handleCancel(e) {
- e.preventDefault();
- this.updateState();
- this.props.updateSection('');
- $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
- }
-
- setStateValue(key, value) {
- const data = {};
- data[key] = value;
- this.setState(data);
- }
-
- updateSection(section) {
- this.updateState();
- this.props.updateSection(section);
- }
-
- updateState() {
- const newState = getNotificationsStateFromStores();
- if (!Utils.areObjectsEqual(newState, this.state)) {
- this.setState(newState);
- }
- }
-
- componentDidMount() {
- UserStore.addChangeListener(this.onListenerChange);
- }
-
- componentWillUnmount() {
- UserStore.removeChangeListener(this.onListenerChange);
- }
-
- onListenerChange() {
- this.updateState();
- }
-
- handleNotifyCommentsRadio(notifyCommentsLevel) {
- this.setState({notifyCommentsLevel});
- this.refs.wrapper.focus();
- }
-
- handlePushRadio(pushActivity) {
- this.setState({pushActivity});
- this.refs.wrapper.focus();
- }
-
- handlePushStatusRadio(pushStatus) {
- this.setState({pushStatus});
- this.refs.wrapper.focus();
- }
-
- handleEmailRadio(enableEmail) {
- this.setState({enableEmail});
- this.refs.wrapper.focus();
- }
-
- updateUsernameKey(val) {
- this.setState({usernameKey: val});
- }
-
- updateFirstNameKey(val) {
- this.setState({firstNameKey: val});
- }
-
- updateChannelKey(val) {
- this.setState({channelKey: val});
- }
-
- updateCustomMentionKeys() {
- const checked = this.refs.customcheck.checked;
-
- if (checked) {
- const text = this.refs.custommentions.value;
-
- // remove all spaces and split string into individual keys
- this.setState({customKeys: text.replace(/ /g, ''), customKeysChecked: true});
- } else {
- this.setState({customKeys: '', customKeysChecked: false});
- }
- }
-
- onCustomChange() {
- this.refs.customcheck.checked = true;
- this.updateCustomMentionKeys();
- }
-
- createPushNotificationSection() {
- if (this.props.activeSection === 'push') {
- const inputs = [];
- let extraInfo = null;
- let submit = null;
-
- if (global.window.mm_config.SendPushNotifications === 'true') {
- const pushActivityRadio = [false, false, false];
- if (this.state.pushActivity === 'all') {
- pushActivityRadio[0] = true;
- } else if (this.state.pushActivity === 'none') {
- pushActivityRadio[2] = true;
- } else {
- pushActivityRadio[1] = true;
- }
-
- const pushStatusRadio = [false, false, false];
- if (this.state.pushStatus === Constants.UserStatuses.ONLINE) {
- pushStatusRadio[0] = true;
- } else if (this.state.pushStatus === Constants.UserStatuses.AWAY) {
- pushStatusRadio[1] = true;
- } else {
- pushStatusRadio[2] = true;
- }
-
- let pushStatusSettings;
- if (this.state.pushActivity !== 'none') {
- pushStatusSettings = (
- <div>
- <hr/>
- <label>
- <FormattedMessage
- id='user.settings.notifications.push_notification.status'
- defaultMessage='Trigger push notifications when'
- />
- </label>
- <br/>
- <div className='radio'>
- <label>
- <input
- id='pushNotificationOnline'
- type='radio'
- name='pushNotificationStatus'
- checked={pushStatusRadio[0]}
- onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.ONLINE)}
- />
- <FormattedMessage
- id='user.settings.push_notification.online'
- defaultMessage='Online, away or offline'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='pushNotificationAway'
- type='radio'
- name='pushNotificationStatus'
- checked={pushStatusRadio[1]}
- onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.AWAY)}
- />
- <FormattedMessage
- id='user.settings.push_notification.away'
- defaultMessage='Away or offline'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='pushNotificationOffline'
- type='radio'
- name='pushNotificationStatus'
- checked={pushStatusRadio[2]}
- onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.OFFLINE)}
- />
- <FormattedMessage
- id='user.settings.push_notification.offline'
- defaultMessage='Offline'
- />
- </label>
- </div>
- </div>
- );
-
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.push_notification.status_info'
- defaultMessage='Notification alerts are only pushed to your mobile device when your online status matches the selection above.'
- />
- </span>
- );
- }
-
- inputs.push(
- <div key='userNotificationLevelOption'>
- <label>
- <FormattedMessage
- id='user.settings.push_notification.send'
- defaultMessage='Send mobile push notifications'
- />
- </label>
- <br/>
- <div className='radio'>
- <label>
- <input
- id='pushNotificationAllActivity'
- type='radio'
- name='pushNotificationLevel'
- checked={pushActivityRadio[0]}
- onChange={this.handlePushRadio.bind(this, 'all')}
- />
- <FormattedMessage
- id='user.settings.push_notification.allActivity'
- defaultMessage='For all activity'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='pushNotificationMentions'
- type='radio'
- name='pushNotificationLevel'
- checked={pushActivityRadio[1]}
- onChange={this.handlePushRadio.bind(this, 'mention')}
- />
- <FormattedMessage
- id='user.settings.push_notification.onlyMentions'
- defaultMessage='For mentions and direct messages'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='pushNotificationNever'
- type='radio'
- name='pushNotificationLevel'
- checked={pushActivityRadio[2]}
- onChange={this.handlePushRadio.bind(this, 'none')}
- />
- <FormattedMessage
- id='user.settings.notifications.never'
- defaultMessage='Never'
- />
- </label>
- </div>
- <br/>
- <span>
- <FormattedMessage
- id='user.settings.push_notification.info'
- defaultMessage='Notification alerts are pushed to your mobile device when there is activity in Mattermost.'
- />
- </span>
- {pushStatusSettings}
- </div>
- );
-
- submit = this.handleSubmit;
- } else {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='padding-top'
- >
- <FormattedMessage
- id='user.settings.push_notification.disabled_long'
- defaultMessage='Push notifications for mobile devices have been disabled by your System Administrator.'
- />
- </div>
- );
- }
-
- return (
- <SettingItemMax
- title={Utils.localizeMessage('user.settings.notifications.push', 'Mobile push notifications')}
- extraInfo={extraInfo}
- inputs={inputs}
- submit={submit}
- server_error={this.state.serverError}
- updateSection={this.handleCancel}
- />
- );
- }
-
- let describe = '';
- if (this.state.pushActivity === 'all') {
- if (this.state.pushStatus === Constants.UserStatuses.AWAY) {
- describe = (
- <FormattedMessage
- id='user.settings.push_notification.allActivityAway'
- defaultMessage='For all activity when away or offline'
- />
- );
- } else if (this.state.pushStatus === Constants.UserStatuses.OFFLINE) {
- describe = (
- <FormattedMessage
- id='user.settings.push_notification.allActivityOffline'
- defaultMessage='For all activity when offline'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.push_notification.allActivityOnline'
- defaultMessage='For all activity when online, away or offline'
- />
- );
- }
- } else if (this.state.pushActivity === 'none') {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.never'
- defaultMessage='Never'
- />
- );
- } else if (global.window.mm_config.SendPushNotifications === 'false') {
- describe = (
- <FormattedMessage
- id='user.settings.push_notification.disabled'
- defaultMessage='Disabled by System Administrator'
- />
- );
- } else {
- if (this.state.pushStatus === Constants.UserStatuses.AWAY) { //eslint-disable-line no-lonely-if
- describe = (
- <FormattedMessage
- id='user.settings.push_notification.onlyMentionsAway'
- defaultMessage='For mentions and direct messages when away or offline'
- />
- );
- } else if (this.state.pushStatus === Constants.UserStatuses.OFFLINE) {
- describe = (
- <FormattedMessage
- id='user.settings.push_notification.onlyMentionsOffline'
- defaultMessage='For mentions and direct messages when offline'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.push_notification.onlyMentionsOnline'
- defaultMessage='For mentions and direct messages when online, away or offline'
- />
- );
- }
- }
-
- const handleUpdatePushSection = () => {
- this.props.updateSection('push');
- };
-
- return (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.notifications.push', 'Mobile push notifications')}
- describe={describe}
- updateSection={handleUpdatePushSection}
- />
- );
- }
-
- render() {
- const serverError = this.state.serverError;
- const user = this.props.user;
-
- let keysSection;
- let handleUpdateKeysSection;
- if (this.props.activeSection === 'keys') {
- const inputs = [];
-
- if (user.first_name) {
- const handleUpdateFirstNameKey = (e) => {
- this.updateFirstNameKey(e.target.checked);
- };
- inputs.push(
- <div key='userNotificationFirstNameOption'>
- <div className='checkbox'>
- <label>
- <input
- id='notificationTriggerFirst'
- type='checkbox'
- checked={this.state.firstNameKey}
- onChange={handleUpdateFirstNameKey}
- />
- <FormattedMessage
- id='user.settings.notifications.sensitiveName'
- defaultMessage='Your case sensitive first name "{first_name}"'
- values={{
- first_name: user.first_name
- }}
- />
- </label>
- </div>
- </div>
- );
- }
-
- const handleUpdateUsernameKey = (e) => {
- this.updateUsernameKey(e.target.checked);
- };
- inputs.push(
- <div key='userNotificationUsernameOption'>
- <div className='checkbox'>
- <label>
- <input
- id='notificationTriggerUsername'
- type='checkbox'
- checked={this.state.usernameKey}
- onChange={handleUpdateUsernameKey}
- />
- <FormattedMessage
- id='user.settings.notifications.sensitiveUsername'
- defaultMessage='Your non-case sensitive username "{username}"'
- values={{
- username: user.username
- }}
- />
- </label>
- </div>
- </div>
- );
-
- const handleUpdateChannelKey = (e) => {
- this.updateChannelKey(e.target.checked);
- };
- inputs.push(
- <div key='userNotificationChannelOption'>
- <div className='checkbox'>
- <label>
- <input
- id='notificationTriggerShouts'
- type='checkbox'
- checked={this.state.channelKey}
- onChange={handleUpdateChannelKey}
- />
- <FormattedMessage
- id='user.settings.notifications.channelWide'
- defaultMessage='Channel-wide mentions "@channel", "@all", "@here"'
- />
- </label>
- </div>
- </div>
- );
-
- inputs.push(
- <div key='userNotificationCustomOption'>
- <div className='checkbox'>
- <label>
- <input
- id='notificationTriggerCustom'
- ref='customcheck'
- type='checkbox'
- checked={this.state.customKeysChecked}
- onChange={this.updateCustomMentionKeys}
- />
- <FormattedMessage
- id='user.settings.notifications.sensitiveWords'
- defaultMessage='Other non-case sensitive words, separated by commas:'
- />
- </label>
- </div>
- <input
- id='notificationTriggerCustomText'
- ref='custommentions'
- className='form-control mentions-input'
- type='text'
- defaultValue={this.state.customKeys}
- onChange={this.onCustomChange}
- />
- </div>
- );
-
- const extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.notifications.mentionsInfo'
- defaultMessage='Mentions trigger when someone sends a message that includes your username (@{username}) or any of the options selected above.'
- values={{
- username: user.username
- }}
- />
- </span>
- );
-
- keysSection = (
- <SettingItemMax
- title={Utils.localizeMessage('user.settings.notifications.wordsTrigger', 'Words that trigger mentions')}
- inputs={inputs}
- submit={this.handleSubmit}
- server_error={serverError}
- updateSection={this.handleCancel}
- extraInfo={extraInfo}
- />
- );
- } else {
- let keys = ['@' + user.username];
- if (this.state.firstNameKey) {
- keys.push(user.first_name);
- }
- if (this.state.usernameKey) {
- keys.push(user.username);
- }
-
- if (this.state.channelKey) {
- keys.push('@channel');
- keys.push('@all');
- keys.push('@here');
- }
- if (this.state.customKeys.length > 0) {
- keys = keys.concat(this.state.customKeys.split(','));
- }
-
- let describe = '';
- for (let i = 0; i < keys.length; i++) {
- if (keys[i] !== '') {
- describe += '"' + keys[i] + '", ';
- }
- }
-
- if (describe.length > 0) {
- describe = describe.substring(0, describe.length - 2);
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.noWords'
- defaultMessage='No words configured'
- />
- );
- }
-
- handleUpdateKeysSection = function updateKeysSection() {
- this.props.updateSection('keys');
- }.bind(this);
-
- keysSection = (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.notifications.wordsTrigger', 'Words that trigger mentions')}
- describe={describe}
- updateSection={handleUpdateKeysSection}
- />
- );
- }
-
- let commentsSection;
- let handleUpdateCommentsSection;
- if (this.props.activeSection === 'comments') {
- const commentsActive = [false, false, false];
- if (this.state.notifyCommentsLevel === 'never') {
- commentsActive[2] = true;
- } else if (this.state.notifyCommentsLevel === 'root') {
- commentsActive[1] = true;
- } else {
- commentsActive[0] = true;
- }
-
- const inputs = [];
-
- inputs.push(
- <div key='userNotificationLevelOption'>
- <div className='radio'>
- <label>
- <input
- id='notificationCommentsAny'
- type='radio'
- name='commentsNotificationLevel'
- checked={commentsActive[0]}
- onChange={this.handleNotifyCommentsRadio.bind(this, 'any')}
- />
- <FormattedMessage
- id='user.settings.notifications.commentsAny'
- defaultMessage='Mention any comments in a thread you participated in (This will include both mentions to your root post and any comments after you commented on a post)'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='notificationCommentsRoot'
- type='radio'
- name='commentsNotificationLevel'
- checked={commentsActive[1]}
- onChange={this.handleNotifyCommentsRadio.bind(this, 'root')}
- />
- <FormattedMessage
- id='user.settings.notifications.commentsRoot'
- defaultMessage='Mention any comments on your post'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- id='notificationCommentsNever'
- type='radio'
- name='commentsNotificationLevel'
- checked={commentsActive[2]}
- onChange={this.handleNotifyCommentsRadio.bind(this, 'never')}
- />
- <FormattedMessage
- id='user.settings.notifications.commentsNever'
- defaultMessage='No mentions for comments'
- />
- </label>
- </div>
- </div>
- );
-
- const extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.notifications.commentsInfo'
- defaultMessage="In addition to notifications for when you're mentioned, select if you would like to receive notifications on reply threads."
- />
- </span>
- );
-
- commentsSection = (
- <SettingItemMax
- title={Utils.localizeMessage('user.settings.notifications.comments', 'Reply notifications')}
- extraInfo={extraInfo}
- inputs={inputs}
- submit={this.handleSubmit}
- server_error={serverError}
- updateSection={this.handleCancel}
- />
- );
- } else {
- let describe = '';
- if (this.state.notifyCommentsLevel === 'never') {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.commentsNever'
- defaultMessage="Do not trigger notifications on messages in reply threads unless I'm mentioned"
- />
- );
- } else if (this.state.notifyCommentsLevel === 'root') {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.commentsRoot'
- defaultMessage='Trigger notifications on messages in threads that I start'
- />
- );
- } else {
- describe = (
- <FormattedMessage
- id='user.settings.notifications.commentsAny'
- defaultMessage='Trigger notifications on messages in reply threads that I start or participate in'
- />
- );
- }
-
- handleUpdateCommentsSection = function updateCommentsSection() {
- this.props.updateSection('comments');
- }.bind(this);
-
- commentsSection = (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.notifications.comments', 'Reply notifications')}
- describe={describe}
- updateSection={handleUpdateCommentsSection}
- />
- );
- }
-
- const pushNotificationSection = this.createPushNotificationSection();
- const enableEmail = this.state.enableEmail === 'true';
-
- return (
- <div>
- <div className='modal-header'>
- <button
- id='closeButton'
- type='button'
- className='close'
- data-dismiss='modal'
- onClick={this.props.closeModal}
- >
- <span aria-hidden='true'>{'×'}</span>
- </button>
- <h4
- className='modal-title'
- ref='title'
- >
- <div className='modal-back'>
- <i
- className='fa fa-angle-left'
- onClick={this.props.collapseModal}
- />
- </div>
- <FormattedMessage
- id='user.settings.notifications.title'
- defaultMessage='Notification Settings'
- />
- </h4>
- </div>
- <div
- ref='wrapper'
- className='user-settings'
- >
- <h3 className='tab-header'>
- <FormattedMessage
- id='user.settings.notifications.header'
- defaultMessage='Notifications'
- />
- </h3>
- <div className='divider-dark first'/>
- <DesktopNotificationSettings
- activity={this.state.desktopActivity}
- sound={this.state.desktopSound}
- duration={this.state.desktopDuration}
- updateSection={this.updateSection}
- setParentState={this.setStateValue}
- submit={this.handleSubmit}
- cancel={this.handleCancel}
- error={this.state.serverError}
- active={this.props.activeSection === 'desktop'}
- />
- <div className='divider-light'/>
- <EmailNotificationSetting
- activeSection={this.props.activeSection}
- updateSection={this.props.updateSection}
- enableEmail={enableEmail}
- emailInterval={Utils.getEmailInterval(enableEmail)}
- onSubmit={this.handleSubmit}
- onCancel={this.handleCancel}
- serverError={this.state.serverError}
- />
- <div className='divider-light'/>
- {pushNotificationSection}
- <div className='divider-light'/>
- {keysSection}
- <div className='divider-light'/>
- {commentsSection}
- <div className='divider-dark'/>
- </div>
- </div>
-
- );
- }
-}
-
-NotificationsTab.defaultProps = {
- user: null,
- activeSection: '',
- activeTab: ''
-};
-NotificationsTab.propTypes = {
- user: PropTypes.object,
- updateSection: PropTypes.func,
- updateTab: PropTypes.func,
- activeSection: PropTypes.string,
- activeTab: PropTypes.string,
- closeModal: PropTypes.func.isRequired,
- collapseModal: PropTypes.func.isRequired
-};
diff --git a/webapp/components/user_settings/user_settings_security/index.js b/webapp/components/user_settings/user_settings_security/index.js
deleted file mode 100644
index a3e83d7de..000000000
--- a/webapp/components/user_settings/user_settings_security/index.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {getMe, getUserAccessTokensForUser, createUserAccessToken, revokeUserAccessToken, clearUserAccessTokens} from 'mattermost-redux/actions/users';
-import * as UserUtils from 'mattermost-redux/utils/user_utils';
-
-import SecurityTab from './user_settings_security.jsx';
-
-function mapStateToProps(state, ownProps) {
- const tokensEnabled = state.entities.general.config.EnableUserAccessTokens === 'true';
- const userHasTokenRole = UserUtils.hasUserAccessTokenRole(ownProps.user.roles) || UserUtils.isSystemAdmin(ownProps.user.roles);
-
- return {
- ...ownProps,
- userAccessTokens: state.entities.users.myUserAccessTokens,
- canUseAccessTokens: tokensEnabled && userHasTokenRole
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getMe,
- getUserAccessTokensForUser,
- createUserAccessToken,
- revokeUserAccessToken,
- clearUserAccessTokens
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(SecurityTab);
diff --git a/webapp/components/user_settings/user_settings_security/user_settings_security.jsx b/webapp/components/user_settings/user_settings_security/user_settings_security.jsx
deleted file mode 100644
index cbf3814bd..000000000
--- a/webapp/components/user_settings/user_settings_security/user_settings_security.jsx
+++ /dev/null
@@ -1,1469 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import SettingItemMin from 'components/setting_item_min.jsx';
-import SettingItemMax from 'components/setting_item_max.jsx';
-import AccessHistoryModal from 'components/access_history_modal';
-import ActivityLogModal from 'components/activity_log_modal';
-import ToggleModalButton from 'components/toggle_modal_button.jsx';
-import ConfirmModal from 'components/confirm_modal.jsx';
-
-import PreferenceStore from 'stores/preference_store.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-
-import {updatePassword, getAuthorizedApps, deactivateMfa, deauthorizeOAuthApp} from 'actions/user_actions.jsx';
-import {trackEvent} from 'actions/diagnostics_actions.jsx';
-import {isMobile} from 'utils/user_agent.jsx';
-
-import $ from 'jquery';
-import PropTypes from 'prop-types';
-import React from 'react';
-import * as UserUtils from 'mattermost-redux/utils/user_utils';
-import {FormattedMessage, FormattedTime, FormattedDate, FormattedHTMLMessage} from 'react-intl';
-import {browserHistory, Link} from 'react-router/es6';
-
-import icon50 from 'images/icon50x50.png';
-
-const TOKEN_CREATING = 'creating';
-const TOKEN_CREATED = 'created';
-const TOKEN_NOT_CREATING = 'not_creating';
-
-export default class SecurityTab extends React.Component {
- static propTypes = {
- user: PropTypes.object,
- activeSection: PropTypes.string,
- updateSection: PropTypes.func,
- updateTab: PropTypes.func,
- closeModal: PropTypes.func.isRequired,
- collapseModal: PropTypes.func.isRequired,
- setEnforceFocus: PropTypes.func.isRequired,
-
- /*
- * The personal access tokens for the user
- */
- userAccessTokens: PropTypes.object,
-
- /*
- * Set if access tokens are enabled and this user can use them
- */
- canUseAccessTokens: PropTypes.bool,
-
- actions: PropTypes.shape({
- getMe: PropTypes.func.isRequired,
-
- /*
- * Function to get personal access tokens for a user
- */
- getUserAccessTokensForUser: PropTypes.func.isRequired,
-
- /*
- * Function to create a personal access token
- */
- createUserAccessToken: PropTypes.func.isRequired,
-
- /*
- * Function to revoke a personal access token
- */
- revokeUserAccessToken: PropTypes.func.isRequired,
-
- /*
- * Function to clear personal access tokens locally
- */
- clearUserAccessTokens: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = this.getDefaultState();
- }
-
- getDefaultState() {
- return {
- currentPassword: '',
- newPassword: '',
- confirmPassword: '',
- passwordError: '',
- serverError: '',
- tokenError: '',
- showConfirmModal: false,
- authService: this.props.user.auth_service
- };
- }
-
- componentDidMount() {
- if (global.mm_config.EnableOAuthServiceProvider === 'true') {
- getAuthorizedApps(
- (authorizedApps) => {
- this.setState({authorizedApps, serverError: null}); //eslint-disable-line react/no-did-mount-set-state
- },
- (err) => {
- this.setState({serverError: err.message}); //eslint-disable-line react/no-did-mount-set-state
- }
- );
- }
-
- if (this.props.canUseAccessTokens) {
- this.props.actions.clearUserAccessTokens();
- const userId = this.props.user ? this.props.user.id : '';
- this.props.actions.getUserAccessTokensForUser(userId, 0, 200);
- }
- }
-
- submitPassword = (e) => {
- e.preventDefault();
-
- var user = this.props.user;
- var currentPassword = this.state.currentPassword;
- var newPassword = this.state.newPassword;
- var confirmPassword = this.state.confirmPassword;
-
- if (currentPassword === '') {
- this.setState({passwordError: Utils.localizeMessage('user.settings.security.currentPasswordError', 'Please enter your current password.'), serverError: ''});
- return;
- }
-
- const passwordErr = Utils.isValidPassword(newPassword);
- if (passwordErr !== '') {
- this.setState({
- passwordError: passwordErr,
- serverError: ''
- });
- return;
- }
-
- if (newPassword !== confirmPassword) {
- var defaultState = Object.assign(this.getDefaultState(), {passwordError: Utils.localizeMessage('user.settings.security.passwordMatchError', 'The new passwords you entered do not match.'), serverError: ''});
- this.setState(defaultState);
- return;
- }
-
- updatePassword(
- user.id,
- currentPassword,
- newPassword,
- () => {
- this.props.updateSection('');
- this.props.actions.getMe();
- this.setState(this.getDefaultState());
- },
- (err) => {
- var state = this.getDefaultState();
- if (err.message) {
- state.serverError = err.message;
- } else {
- state.serverError = err;
- }
- state.passwordError = '';
- this.setState(state);
- }
- );
- }
-
- setupMfa = (e) => {
- e.preventDefault();
- browserHistory.push('/mfa/setup');
- }
-
- removeMfa = () => {
- deactivateMfa(
- () => {
- if (global.window.mm_license.MFA === 'true' &&
- global.window.mm_config.EnableMultifactorAuthentication === 'true' &&
- global.window.mm_config.EnforceMultifactorAuthentication === 'true') {
- window.location.href = '/mfa/setup';
- return;
- }
-
- this.props.updateSection('');
- this.setState(this.getDefaultState());
- },
- (err) => {
- const state = this.getDefaultState();
- if (err.message) {
- state.serverError = err.message;
- } else {
- state.serverError = err;
- }
- this.setState(state);
- }
- );
- }
-
- updateCurrentPassword = (e) => {
- this.setState({currentPassword: e.target.value});
- }
-
- updateNewPassword = (e) => {
- this.setState({newPassword: e.target.value});
- }
-
- updateConfirmPassword = (e) => {
- this.setState({confirmPassword: e.target.value});
- }
-
- deauthorizeApp = (e) => {
- e.preventDefault();
- const appId = e.currentTarget.getAttribute('data-app');
- deauthorizeOAuthApp(
- appId,
- () => {
- const authorizedApps = this.state.authorizedApps.filter((app) => {
- return app.id !== appId;
- });
-
- this.setState({authorizedApps, serverError: null});
- },
- (err) => {
- this.setState({serverError: err.message});
- }
- );
- }
-
- createMfaSection = () => {
- let updateSectionStatus;
- let submit;
-
- if (this.props.activeSection === 'mfa') {
- let content;
- let extraInfo;
- if (this.props.user.mfa_active) {
- let mfaRemoveHelp;
- let mfaButtonText;
-
- if (global.window.mm_config.EnforceMultifactorAuthentication === 'true') {
- mfaRemoveHelp = (
- <FormattedMessage
- id='user.settings.mfa.requiredHelp'
- defaultMessage='Multi-factor authentication is required on this server. Resetting is only recommended when you need to switch code generation to a new mobile device. You will be required to set it up again immediately.'
- />
- );
-
- mfaButtonText = (
- <FormattedMessage
- id='user.settings.mfa.reset'
- defaultMessage='Reset MFA on your account'
- />
- );
- } else {
- mfaRemoveHelp = (
- <FormattedMessage
- id='user.settings.mfa.removeHelp'
- defaultMessage='Removing multi-factor authentication means you will no longer require a phone-based passcode to sign-in to your account.'
- />
- );
-
- mfaButtonText = (
- <FormattedMessage
- id='user.settings.mfa.remove'
- defaultMessage='Remove MFA from your account'
- />
- );
- }
-
- content = (
- <div key='mfaQrCode'>
- <a
- className='btn btn-primary'
- href='#'
- onClick={this.removeMfa}
- >
- {mfaButtonText}
- </a>
- <br/>
- </div>
- );
-
- extraInfo = (
- <span>
- {mfaRemoveHelp}
- </span>
- );
- } else {
- content = (
- <div key='mfaQrCode'>
- <a
- className='btn btn-primary'
- href='#'
- onClick={this.setupMfa}
- >
- <FormattedMessage
- id='user.settings.mfa.add'
- defaultMessage='Add MFA to your account'
- />
- </a>
- <br/>
- </div>
- );
-
- extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.mfa.addHelp'
- defaultMessage='Adding multi-factor authentication will make your account more secure by requiring a code from your mobile phone each time you sign in.'
- />
- </span>
- );
- }
-
- const inputs = [];
- inputs.push(
- <div
- key='mfaSetting'
- className='padding-top'
- >
- {content}
- </div>
- );
-
- updateSectionStatus = function resetSection(e) {
- this.props.updateSection('');
- this.setState({serverError: null});
- e.preventDefault();
- }.bind(this);
-
- return (
- <SettingItemMax
- title={Utils.localizeMessage('user.settings.mfa.title', 'Multi-factor Authentication')}
- inputs={inputs}
- extraInfo={extraInfo}
- submit={submit}
- server_error={this.state.serverError}
- updateSection={updateSectionStatus}
- width='medium'
- />
- );
- }
-
- let describe;
- if (this.props.user.mfa_active) {
- describe = Utils.localizeMessage('user.settings.security.active', 'Active');
- } else {
- describe = Utils.localizeMessage('user.settings.security.inactive', 'Inactive');
- }
-
- updateSectionStatus = function updateSection() {
- this.props.updateSection('mfa');
- }.bind(this);
-
- return (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.mfa.title', 'Multi-factor Authentication')}
- describe={describe}
- updateSection={updateSectionStatus}
- />
- );
- }
-
- createPasswordSection = () => {
- let updateSectionStatus;
-
- if (this.props.activeSection === 'password') {
- const inputs = [];
- let submit;
-
- if (this.props.user.auth_service === '') {
- submit = this.submitPassword;
-
- inputs.push(
- <div
- key='currentPasswordUpdateForm'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.security.currentPassword'
- defaultMessage='Current Password'
- />
- </label>
- <div className='col-sm-7'>
- <input
- id='currentPassword'
- className='form-control'
- type='password'
- onChange={this.updateCurrentPassword}
- value={this.state.currentPassword}
- />
- </div>
- </div>
- );
- inputs.push(
- <div
- key='newPasswordUpdateForm'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.security.newPassword'
- defaultMessage='New Password'
- />
- </label>
- <div className='col-sm-7'>
- <input
- id='newPassword'
- className='form-control'
- type='password'
- onChange={this.updateNewPassword}
- value={this.state.newPassword}
- />
- </div>
- </div>
- );
- inputs.push(
- <div
- key='retypeNewPasswordUpdateForm'
- className='form-group'
- >
- <label className='col-sm-5 control-label'>
- <FormattedMessage
- id='user.settings.security.retypePassword'
- defaultMessage='Retype New Password'
- />
- </label>
- <div className='col-sm-7'>
- <input
- id='confirmPassword'
- className='form-control'
- type='password'
- onChange={this.updateConfirmPassword}
- value={this.state.confirmPassword}
- />
- </div>
- </div>
- );
- } else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.security.passwordGitlabCantUpdate'
- defaultMessage='Login occurs through GitLab. Password cannot be updated.'
- />
- </div>
- </div>
- );
- } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.security.passwordLdapCantUpdate'
- defaultMessage='Login occurs through AD/LDAP. Password cannot be updated.'
- />
- </div>
- </div>
- );
- } else if (this.props.user.auth_service === Constants.SAML_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.security.passwordSamlCantUpdate'
- defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so through your login provider.'
- />
- </div>
- </div>
- );
- } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.security.passwordGoogleCantUpdate'
- defaultMessage='Login occurs through Google Apps. Password cannot be updated.'
- />
- </div>
- </div>
- );
- } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) {
- inputs.push(
- <div
- key='oauthEmailInfo'
- className='form-group'
- >
- <div className='setting-list__hint col-sm-12'>
- <FormattedMessage
- id='user.settings.security.passwordOffice365CantUpdate'
- defaultMessage='Login occurs through Office 365. Password cannot be updated.'
- />
- </div>
- </div>
- );
- }
-
- updateSectionStatus = function resetSection(e) {
- this.props.updateSection('');
- this.setState({currentPassword: '', newPassword: '', confirmPassword: '', serverError: null, passwordError: null});
- e.preventDefault();
- $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
- }.bind(this);
-
- return (
- <SettingItemMax
- title={
- <FormattedMessage
- id='user.settings.security.password'
- defaultMessage='Password'
- />
- }
- inputs={inputs}
- submit={submit}
- server_error={this.state.serverError}
- client_error={this.state.passwordError}
- updateSection={updateSectionStatus}
- />
- );
- }
-
- let describe;
-
- if (this.props.user.auth_service === '') {
- const d = new Date(this.props.user.last_password_update);
- const hours12 = !PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, Constants.Preferences.USE_MILITARY_TIME, false);
-
- describe = (
- <FormattedMessage
- id='user.settings.security.lastUpdated'
- defaultMessage='Last updated {date} at {time}'
- values={{
- date: (
- <FormattedDate
- value={d}
- day='2-digit'
- month='short'
- year='numeric'
- />
- ),
- time: (
- <FormattedTime
- value={d}
- hour12={hours12}
- hour='2-digit'
- minute='2-digit'
- />
- )
- }}
- />
- );
- } else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.loginGitlab'
- defaultMessage='Login done through GitLab'
- />
- );
- } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.loginLdap'
- defaultMessage='Login done through AD/LDAP'
- />
- );
- } else if (this.props.user.auth_service === Constants.SAML_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.loginSaml'
- defaultMessage='Login done through SAML'
- />
- );
- } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.loginGoogle'
- defaultMessage='Login done through Google Apps'
- />
- );
- } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.loginOffice365'
- defaultMessage='Login done through Office 365'
- />
- );
- }
-
- updateSectionStatus = function updateSection() {
- this.props.updateSection('password');
- }.bind(this);
-
- return (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.security.password'
- defaultMessage='Password'
- />
- }
- describe={describe}
- updateSection={updateSectionStatus}
- />
- );
- }
-
- createSignInSection = () => {
- let updateSectionStatus;
- const user = this.props.user;
-
- if (this.props.activeSection === 'signin') {
- let emailOption;
- let gitlabOption;
- let googleOption;
- let office365Option;
- let ldapOption;
- let samlOption;
-
- if (user.auth_service === '') {
- if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
- gitlabOption = (
- <div className='padding-bottom x2'>
- <Link
- className='btn btn-primary'
- to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GITLAB_SERVICE}
- >
- <FormattedMessage
- id='user.settings.security.switchGitlab'
- defaultMessage='Switch to using GitLab SSO'
- />
- </Link>
- <br/>
- </div>
- );
- }
-
- if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
- googleOption = (
- <div className='padding-bottom x2'>
- <Link
- className='btn btn-primary'
- to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GOOGLE_SERVICE}
- >
- <FormattedMessage
- id='user.settings.security.switchGoogle'
- defaultMessage='Switch to using Google SSO'
- />
- </Link>
- <br/>
- </div>
- );
- }
-
- if (global.window.mm_config.EnableSignUpWithOffice365 === 'true') {
- office365Option = (
- <div className='padding-bottom x2'>
- <Link
- className='btn btn-primary'
- to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.OFFICE365_SERVICE}
- >
- <FormattedMessage
- id='user.settings.security.switchOffice365'
- defaultMessage='Switch to using Office 365 SSO'
- />
- </Link>
- <br/>
- </div>
- );
- }
-
- if (global.window.mm_config.EnableLdap === 'true') {
- ldapOption = (
- <div className='padding-bottom x2'>
- <Link
- className='btn btn-primary'
- to={'/claim/email_to_ldap?email=' + encodeURIComponent(user.email)}
- >
- <FormattedMessage
- id='user.settings.security.switchLdap'
- defaultMessage='Switch to using AD/LDAP'
- />
- </Link>
- <br/>
- </div>
- );
- }
-
- if (global.window.mm_config.EnableSaml === 'true') {
- samlOption = (
- <div className='padding-bottom x2'>
- <Link
- className='btn btn-primary'
- to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.SAML_SERVICE}
- >
- <FormattedMessage
- id='user.settings.security.switchSaml'
- defaultMessage='Switch to using SAML SSO'
- />
- </Link>
- <br/>
- </div>
- );
- }
- } else if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
- let link;
- if (user.auth_service === Constants.LDAP_SERVICE) {
- link = '/claim/ldap_to_email?email=' + encodeURIComponent(user.email);
- } else {
- link = '/claim/oauth_to_email?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service;
- }
-
- emailOption = (
- <div className='padding-bottom x2'>
- <Link
- className='btn btn-primary'
- to={link}
- >
- <FormattedMessage
- id='user.settings.security.switchEmail'
- defaultMessage='Switch to using email and password'
- />
- </Link>
- <br/>
- </div>
- );
- }
-
- const inputs = [];
- inputs.push(
- <div key='userSignInOption'>
- {emailOption}
- {gitlabOption}
- {googleOption}
- {office365Option}
- {ldapOption}
- {samlOption}
- </div>
- );
-
- updateSectionStatus = function updateSection(e) {
- this.props.updateSection('');
- this.setState({serverError: null});
- e.preventDefault();
- }.bind(this);
-
- const extraInfo = (
- <span>
- <FormattedMessage
- id='user.settings.security.oneSignin'
- defaultMessage='You may only have one sign-in method at a time. Switching sign-in method will send an email notifying you if the change was successful.'
- />
- </span>
- );
-
- return (
- <SettingItemMax
- title={Utils.localizeMessage('user.settings.security.method', 'Sign-in Method')}
- extraInfo={extraInfo}
- inputs={inputs}
- server_error={this.state.serverError}
- updateSection={updateSectionStatus}
- />
- );
- }
-
- updateSectionStatus = function updateSection() {
- this.props.updateSection('signin');
- }.bind(this);
-
- let describe = (
- <FormattedMessage
- id='user.settings.security.emailPwd'
- defaultMessage='Email and Password'
- />
- );
- if (this.props.user.auth_service === Constants.GITLAB_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.gitlab'
- defaultMessage='GitLab'
- />
- );
- } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.google'
- defaultMessage='Google'
- />
- );
- } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.office365'
- defaultMessage='Office 365'
- />
- );
- } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.ldap'
- defaultMessage='AD/LDAP'
- />
- );
- } else if (this.props.user.auth_service === Constants.SAML_SERVICE) {
- describe = (
- <FormattedMessage
- id='user.settings.security.saml'
- defaultMessage='SAML'
- />
- );
- }
-
- return (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.security.method', 'Sign-in Method')}
- describe={describe}
- updateSection={updateSectionStatus}
- />
- );
- }
-
- createOAuthAppsSection = () => {
- let updateSectionStatus;
-
- if (this.props.activeSection === 'apps') {
- let apps;
- if (this.state.authorizedApps && this.state.authorizedApps.length > 0) {
- apps = this.state.authorizedApps.map((app) => {
- const homepage = (
- <a
- href={app.homepage}
- target='_blank'
- rel='noopener noreferrer'
- >
- {app.homepage}
- </a>
- );
-
- return (
- <div
- key={app.id}
- className='padding-bottom x2 authorized-app'
- >
- <div className='col-sm-10'>
- <div className='authorized-app__name'>
- {app.name}
- <span className='authorized-app__url'>
- {' -'} {homepage}
- </span>
- </div>
- <div className='authorized-app__description'>{app.description}</div>
- <div className='authorized-app__deauthorize'>
- <a
- href='#'
- data-app={app.id}
- onClick={this.deauthorizeApp}
- >
- <FormattedMessage
- id='user.settings.security.deauthorize'
- defaultMessage='Deauthorize'
- />
- </a>
- </div>
- </div>
- <div className='col-sm-2 pull-right'>
- <img
- alt={app.name}
- src={app.icon_url || icon50}
- />
- </div>
- <br/>
- </div>
- );
- });
- } else {
- apps = (
- <div className='padding-bottom x2 authorized-app'>
- <div className='setting-list__hint'>
- <FormattedMessage
- id='user.settings.security.noApps'
- defaultMessage='No OAuth 2.0 Applications are authorized.'
- />
- </div>
- </div>
- );
- }
-
- const inputs = [];
- let wrapperClass;
- let helpText;
- if (Array.isArray(apps)) {
- wrapperClass = 'authorized-apps__wrapper';
-
- helpText = (
- <div className='authorized-apps__help'>
- <FormattedMessage
- id='user.settings.security.oauthAppsHelp'
- defaultMessage='Applications act on your behalf to access your data based on the permissions you grant them.'
- />
- </div>
- );
- }
-
- inputs.push(
- <div
- className={wrapperClass}
- key='authorizedApps'
- >
- {apps}
- </div>
- );
-
- updateSectionStatus = function updateSection(e) {
- this.props.updateSection('');
- this.setState({serverError: null});
- e.preventDefault();
- }.bind(this);
-
- const title = (
- <div>
- <FormattedMessage
- id='user.settings.security.oauthApps'
- defaultMessage='OAuth 2.0 Applications'
- />
- {helpText}
- </div>
- );
-
- return (
- <SettingItemMax
- title={title}
- inputs={inputs}
- server_error={this.state.serverError}
- updateSection={updateSectionStatus}
- width='full'
- cancelButtonText={
- <FormattedMessage
- id='user.settings.security.close'
- defaultMessage='Close'
- />
- }
- />
- );
- }
-
- updateSectionStatus = function updateSection() {
- this.props.updateSection('apps');
- }.bind(this);
-
- return (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.security.oauthApps', 'OAuth 2.0 Applications')}
- describe={
- <FormattedMessage
- id='user.settings.security.oauthAppsDescription'
- defaultMessage="Click 'Edit' to manage your OAuth 2.0 Applications"
- />
- }
- updateSection={updateSectionStatus}
- />
- );
- }
-
- startCreatingToken = () => {
- this.setState({tokenCreationState: TOKEN_CREATING});
- }
-
- stopCreatingToken = () => {
- this.setState({tokenCreationState: TOKEN_NOT_CREATING});
- }
-
- handleCreateToken = async () => {
- this.handleCancelConfirm();
-
- const description = this.refs.newtokendescription ? this.refs.newtokendescription.value : '';
-
- if (description === '') {
- this.setState({tokenError: Utils.localizeMessage('user.settings.tokens.nameRequired', 'Please enter a description.')});
- return;
- }
-
- this.setState({tokenError: ''});
-
- const userId = this.props.user ? this.props.user.id : '';
- const {data, error} = await this.props.actions.createUserAccessToken(userId, description);
-
- if (data) {
- this.setState({tokenCreationState: TOKEN_CREATED, newToken: data});
- } else if (error) {
- this.setState({serverError: error.message});
- }
- }
-
- handleCancelConfirm = () => {
- this.setState({
- showConfirmModal: false,
- confirmTitle: null,
- confirmMessage: null,
- confirmButton: null,
- confirmComplete: null
- });
- }
-
- confirmCreateToken = () => {
- if (UserUtils.isSystemAdmin(this.props.user.roles)) {
- this.setState({
- showConfirmModal: true,
- confirmTitle: (
- <FormattedMessage
- id='user.settings.tokens.confirmCreateTitle'
- defaultMessage='Create System Admin Personal Access Token'
- />
- ),
- confirmMessage: (
- <div className='alert alert-danger'>
- <FormattedHTMLMessage
- id='user.settings.tokens.confirmCreateMessage'
- defaultMessage='You are generating a personal access token with System Admin permissions. Are you sure want to create this token?'
- />
- </div>
- ),
- confirmButton: (
- <FormattedMessage
- id='user.settings.tokens.confirmCreateButton'
- defaultMessage='Yes, Create'
- />
- ),
- confirmComplete: () => {
- this.handleCreateToken();
- trackEvent('settings', 'system_admin_create_user_access_token');
- }
- });
-
- return;
- }
-
- this.handleCreateToken();
- }
-
- saveTokenKeyPress = (e) => {
- if (e.which === Constants.KeyCodes.ENTER) {
- this.confirmCreateToken();
- }
- }
-
- confirmRevokeToken = (tokenId) => {
- const token = this.props.userAccessTokens[tokenId];
-
- this.setState({
- showConfirmModal: true,
- confirmTitle: (
- <FormattedMessage
- id='user.settings.tokens.confirmDeleteTitle'
- defaultMessage='Delete Token?'
- />
- ),
- confirmMessage: (
- <div className='alert alert-danger'>
- <FormattedHTMLMessage
- id='user.settings.tokens.confirmDeleteMessage'
- defaultMessage='Any integrations using this token will no longer be able to access the Mattermost API. You cannot undo this action. <br /><br />Are you sure want to delete the {description} token?'
- values={{
- description: token.description
- }}
- />
- </div>
- ),
- confirmButton: (
- <FormattedMessage
- id='user.settings.tokens.confirmDeleteButton'
- defaultMessage='Yes, Delete'
- />
- ),
- confirmComplete: () => {
- this.revokeToken(tokenId);
- trackEvent('settings', 'revoke_user_access_token');
- }
- });
- }
-
- revokeToken = async (tokenId) => {
- const {error} = await this.props.actions.revokeUserAccessToken(tokenId);
- if (error) {
- this.setState({serverError: error.message});
- }
- this.handleCancelConfirm();
- }
-
- createTokensSection = () => {
- let updateSectionStatus;
- let tokenListClass = '';
-
- if (this.props.activeSection === 'tokens') {
- const tokenList = [];
- Object.values(this.props.userAccessTokens).forEach((token) => {
- if (this.state.newToken && this.state.newToken.id === token.id) {
- return;
- }
-
- tokenList.push(
- <div
- key={token.id}
- className='setting-box__item'
- >
- <div className='whitespace--nowrap overflow--ellipsis'>
- <FormattedMessage
- id='user.settings.tokens.tokenDesc'
- defaultMessage='Token Description: '
- />
- {token.description}
- </div>
- <div className='setting-box__token-id whitespace--nowrap overflow--ellipsis'>
- <FormattedMessage
- id='user.settings.tokens.tokenId'
- defaultMessage='Token ID: '
- />
- {token.id}
- </div>
- <div>
- <a
- name={token.id}
- href='#'
- onClick={(e) => {
- e.preventDefault();
- this.confirmRevokeToken(token.id);
- }}
- >
- <FormattedMessage
- id='user.settings.tokens.delete'
- defaultMessage='Delete'
- />
- </a>
- </div>
- <hr className='margin-bottom margin-top x2'/>
- </div>
- );
- });
-
- let noTokenText;
- if (tokenList.length === 0) {
- noTokenText = (
- <FormattedMessage
- key='notokens'
- id='user.settings.tokens.userAccessTokensNone'
- defaultMessage='No personal access tokens.'
- />
- );
- }
-
- let extraInfo;
- if (isMobile()) {
- extraInfo = (
- <span>
- <FormattedHTMLMessage
- id='user.settings.tokens.description_mobile'
- defaultMessage='<a href="https://about.mattermost.com/default-user-access-tokens" target="_blank">Personal access tokens</a> function similar to session tokens and can be used by integrations to <a href="https://about.mattermost.com/default-api-authentication" target="_blank">authenticate against the REST API</a>. Create new tokens on your desktop.'
- />
- </span>
- );
- } else {
- extraInfo = (
- <span>
- <FormattedHTMLMessage
- id='user.settings.tokens.description'
- defaultMessage='<a href="https://about.mattermost.com/default-user-access-tokens" target="_blank">Personal access tokens</a> function similar to session tokens and can be used by integrations to <a href="https://about.mattermost.com/default-api-authentication" target="_blank">authenticate against the REST API</a>.'
- />
- </span>
- );
- }
-
- let newTokenSection;
- if (this.state.tokenCreationState === TOKEN_CREATING) {
- newTokenSection = (
- <div className='padding-left x2'>
- <div className='row'>
- <label className='col-sm-auto control-label padding-right x2'>
- <FormattedMessage
- id='user.settings.tokens.name'
- defaultMessage='Token Description: '
- />
- </label>
- <div className='col-sm-5'>
- <input
- ref='newtokendescription'
- className='form-control'
- type='text'
- maxLength={64}
- onKeyPress={this.saveTokenKeyPress}
- />
- </div>
- </div>
- <div>
- <div className='padding-top x2'>
- <FormattedMessage
- id='user.settings.tokens.nameHelp'
- defaultMessage='Enter a description for your token to remember what it does.'
- />
- </div>
- <div>
- <label
- id='clientError'
- className='has-error margin-top margin-bottom'
- >
- {this.state.tokenError}
- </label>
- </div>
- <button
- className='btn btn-primary'
- onClick={this.confirmCreateToken}
- >
- <FormattedMessage
- id='user.settings.tokens.save'
- defaultMessage='Save'
- />
- </button>
- <button
- className='btn btn-default'
- onClick={this.stopCreatingToken}
- >
- <FormattedMessage
- id='user.settings.tokens.cancel'
- defaultMessage='Cancel'
- />
- </button>
- </div>
- </div>
- );
- } else if (this.state.tokenCreationState === TOKEN_CREATED) {
- if (tokenList.length === 0) {
- tokenListClass = ' hidden';
- }
-
- newTokenSection = (
- <div
- className='alert alert-warning'
- >
- <i className='fa fa-warning margin-right'/>
- <FormattedMessage
- id='user.settings.tokens.copy'
- defaultMessage="Please copy the access token below. You won't be able to see it again!"
- />
- <br/>
- <br/>
- <div className='whitespace--nowrap overflow--ellipsis'>
- <FormattedMessage
- id='user.settings.tokens.name'
- defaultMessage='Token Description: '
- />
- {this.state.newToken.description}
- </div>
- <div className='whitespace--nowrap overflow--ellipsis'>
- <FormattedMessage
- id='user.settings.tokens.id'
- defaultMessage='Token ID: '
- />
- {this.state.newToken.id}
- </div>
- <strong className='word-break--all'>
- <FormattedMessage
- id='user.settings.tokens.token'
- defaultMessage='Access Token: '
- />
- {this.state.newToken.token}
- </strong>
- </div>
- );
- } else {
- newTokenSection = (
- <a
- className='btn btn-primary'
- href='#'
- onClick={this.startCreatingToken}
- >
- <FormattedMessage
- id='user.settings.tokens.create'
- defaultMessage='Create New Token'
- />
- </a>
- );
- }
-
- const inputs = [];
- inputs.push(
- <div
- key='tokensSetting'
- className='padding-top'
- >
- <div key='tokenList'>
- <div className={'alert alert-transparent' + tokenListClass}>
- {tokenList}
- {noTokenText}
- </div>
- {newTokenSection}
- </div>
- </div>
- );
-
- updateSectionStatus = function resetSection(e) {
- this.props.updateSection('');
- this.setState({newToken: null, tokenCreationState: TOKEN_NOT_CREATING, serverError: null, tokenError: ''});
- e.preventDefault();
- }.bind(this);
-
- return (
- <SettingItemMax
- title={Utils.localizeMessage('user.settings.tokens.title', 'Personal Access Tokens')}
- inputs={inputs}
- extraInfo={extraInfo}
- infoPosition='top'
- server_error={this.state.serverError}
- updateSection={updateSectionStatus}
- width='full'
- cancelButtonText={
- <FormattedMessage
- id='user.settings.security.close'
- defaultMessage='Close'
- />
- }
- />
- );
- }
-
- const describe = Utils.localizeMessage('user.settings.tokens.clickToEdit', "Click 'Edit' to manage your personal access tokens");
-
- updateSectionStatus = function updateSection() {
- this.props.updateSection('tokens');
- }.bind(this);
-
- return (
- <SettingItemMin
- title={Utils.localizeMessage('user.settings.tokens.title', 'Personal Access Tokens')}
- describe={describe}
- updateSection={updateSectionStatus}
- />
- );
- }
-
- render() {
- const user = this.props.user;
- const config = window.mm_config;
-
- const passwordSection = this.createPasswordSection();
-
- let numMethods = 0;
- numMethods = config.EnableSignUpWithGitLab === 'true' ? numMethods + 1 : numMethods;
- numMethods = config.EnableSignUpWithGoogle === 'true' ? numMethods + 1 : numMethods;
- numMethods = config.EnableLdap === 'true' ? numMethods + 1 : numMethods;
- numMethods = config.EnableSaml === 'true' ? numMethods + 1 : numMethods;
-
- // If there are other sign-in methods and either email is enabled or the user's account is email, then allow switching
- let signInSection;
- if ((config.EnableSignUpWithEmail === 'true' || user.auth_service === '') && numMethods > 0) {
- signInSection = this.createSignInSection();
- }
-
- let mfaSection;
- if (config.EnableMultifactorAuthentication === 'true' &&
- global.window.mm_license.IsLicensed === 'true' &&
- (user.auth_service === '' || user.auth_service === Constants.LDAP_SERVICE)) {
- mfaSection = this.createMfaSection();
- }
-
- let oauthSection;
- if (config.EnableOAuthServiceProvider === 'true') {
- oauthSection = this.createOAuthAppsSection();
- }
-
- let tokensSection;
- if (this.props.canUseAccessTokens) {
- tokensSection = this.createTokensSection();
- }
-
- return (
- <div>
- <div className='modal-header'>
- <button
- type='button'
- className='close'
- data-dismiss='modal'
- aria-label={Utils.localizeMessage('user.settings.security.close', 'Close')}
- onClick={this.props.closeModal}
- >
- <span aria-hidden='true'>{'×'}</span>
- </button>
- <h4
- className='modal-title'
- ref='title'
- >
- <div className='modal-back'>
- <i
- className='fa fa-angle-left'
- onClick={this.props.collapseModal}
- />
- </div>
- <FormattedMessage
- id='user.settings.security.title'
- defaultMessage='Security Settings'
- />
- </h4>
- </div>
- <div className='user-settings'>
- <h3 className='tab-header'>
- <FormattedMessage
- id='user.settings.security.title'
- defaultMessage='Security Settings'
- />
- </h3>
- <div className='divider-dark first'/>
- {passwordSection}
- <div className='divider-light'/>
- {mfaSection}
- <div className='divider-light'/>
- {oauthSection}
- <div className='divider-light'/>
- {tokensSection}
- <div className='divider-light'/>
- {signInSection}
- <div className='divider-dark'/>
- <br/>
- <ToggleModalButton
- className='security-links theme'
- dialogType={AccessHistoryModal}
- >
- <i className='fa fa-clock-o'/>
- <FormattedMessage
- id='user.settings.security.viewHistory'
- defaultMessage='View Access History'
- />
- </ToggleModalButton>
- <br/>
- <ToggleModalButton
- className='security-links theme'
- dialogType={ActivityLogModal}
- >
- <i className='fa fa-clock-o'/>
- <FormattedMessage
- id='user.settings.security.logoutActiveSessions'
- defaultMessage='View and Logout of Active Sessions'
- />
- </ToggleModalButton>
- </div>
- <ConfirmModal
- title={this.state.confirmTitle}
- message={this.state.confirmMessage}
- confirmButtonText={this.state.confirmButton}
- show={this.state.showConfirmModal}
- onConfirm={this.state.confirmComplete || (() => {})} //eslint-disable-line no-empty-function
- onCancel={this.handleCancelConfirm}
- />
- </div>
- );
- }
-}
-
-SecurityTab.defaultProps = {
- user: {},
- activeSection: ''
-};
diff --git a/webapp/components/user_settings/user_settings_theme.jsx b/webapp/components/user_settings/user_settings_theme.jsx
deleted file mode 100644
index 871e3ccae..000000000
--- a/webapp/components/user_settings/user_settings_theme.jsx
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import ReactDOM from 'react-dom';
-import CustomThemeChooser from './custom_theme_chooser.jsx';
-import PremadeThemeChooser from './premade_theme_chooser.jsx';
-import SettingItemMin from '../setting_item_min.jsx';
-import SettingItemMax from '../setting_item_max.jsx';
-
-import PreferenceStore from 'stores/preference_store.jsx';
-import TeamStore from 'stores/team_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-
-import AppDispatcher from '../../dispatcher/app_dispatcher.jsx';
-import * as UserActions from 'actions/user_actions.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import {FormattedMessage} from 'react-intl';
-
-import {ActionTypes, Constants, Preferences} from 'utils/constants.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-export default class ThemeSetting extends React.Component {
- constructor(props) {
- super(props);
-
- this.onChange = this.onChange.bind(this);
- this.submitTheme = this.submitTheme.bind(this);
- this.updateTheme = this.updateTheme.bind(this);
- this.resetFields = this.resetFields.bind(this);
- this.handleImportModal = this.handleImportModal.bind(this);
-
- this.state = this.getStateFromStores();
-
- this.originalTheme = Object.assign({}, this.state.theme);
- }
-
- componentDidMount() {
- UserStore.addChangeListener(this.onChange);
-
- if (this.props.selected) {
- $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
- }
- }
-
- componentDidUpdate() {
- if (this.props.selected) {
- $('.color-btn').removeClass('active-border');
- $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
- }
- }
-
- componentWillReceiveProps(nextProps) {
- if (this.props.selected && !nextProps.selected) {
- this.resetFields();
- }
- }
-
- componentWillUnmount() {
- UserStore.removeChangeListener(this.onChange);
-
- if (this.props.selected) {
- const state = this.getStateFromStores();
- Utils.applyTheme(state.theme);
- }
- }
-
- getStateFromStores() {
- const teamId = TeamStore.getCurrentId();
-
- const theme = PreferenceStore.getTheme(teamId);
- if (!theme.codeTheme) {
- theme.codeTheme = Constants.DEFAULT_CODE_THEME;
- }
-
- let showAllTeamsCheckbox = false;
- let applyToAllTeams = true;
-
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.LDAP === 'true') {
- // show the "apply to all teams" checkbox if the user is on more than one team
- showAllTeamsCheckbox = Object.keys(TeamStore.getAll()).length > 1;
-
- // check the "apply to all teams" checkbox by default if the user has any team-specific themes
- applyToAllTeams = PreferenceStore.getCategory(Preferences.CATEGORY_THEME).size <= 1;
- }
-
- return {
- teamId: TeamStore.getCurrentId(),
- theme,
- type: theme.type || 'premade',
- showAllTeamsCheckbox,
- applyToAllTeams
- };
- }
-
- onChange() {
- const newState = this.getStateFromStores();
-
- if (!Utils.areObjectsEqual(this.state, newState)) {
- this.setState(newState);
- }
-
- this.props.setEnforceFocus(true);
- }
-
- scrollToTop() {
- $('.ps-container.modal-body').scrollTop(0);
- }
-
- submitTheme(e) {
- e.preventDefault();
-
- const teamId = this.state.applyToAllTeams ? '' : this.state.teamId;
-
- UserActions.saveTheme(
- teamId,
- this.state.theme,
- () => {
- this.props.setRequireConfirm(false);
- this.originalTheme = Object.assign({}, this.state.theme);
- this.scrollToTop();
- this.props.updateSection('');
- }
- );
- }
-
- updateTheme(theme) {
- let themeChanged = this.state.theme.length === theme.length;
- if (!themeChanged) {
- for (const field in theme) {
- if (theme.hasOwnProperty(field)) {
- if (this.state.theme[field] !== theme[field]) {
- themeChanged = true;
- break;
- }
- }
- }
- }
-
- this.props.setRequireConfirm(themeChanged);
-
- this.setState({theme});
- Utils.applyTheme(theme);
- }
-
- updateType(type) {
- this.setState({type});
- }
-
- resetFields() {
- const state = this.getStateFromStores();
- state.serverError = null;
- this.setState(state);
- this.scrollToTop();
-
- Utils.applyTheme(state.theme);
-
- this.props.setRequireConfirm(false);
- }
-
- handleImportModal() {
- AppDispatcher.handleViewAction({
- type: ActionTypes.TOGGLE_IMPORT_THEME_MODAL,
- value: true,
- callback: this.updateTheme
- });
-
- this.props.setEnforceFocus(false);
- }
-
- render() {
- var serverError;
- if (this.state.serverError) {
- serverError = this.state.serverError;
- }
-
- const displayCustom = this.state.type === 'custom';
- const allowCustomThemes = global.mm_config.AllowCustomThemes !== 'false';
-
- let custom;
- let premade;
- if (displayCustom && allowCustomThemes) {
- custom = (
- <div key='customThemeChooser'>
- <CustomThemeChooser
- theme={this.state.theme}
- updateTheme={this.updateTheme}
- />
- </div>
- );
- } else {
- premade = (
- <div key='premadeThemeChooser'>
- <br/>
- <PremadeThemeChooser
- theme={this.state.theme}
- updateTheme={this.updateTheme}
- />
- </div>
- );
- }
-
- let themeUI;
- if (this.props.selected) {
- const inputs = [];
-
- if (allowCustomThemes) {
- inputs.push(
- <div
- className='radio'
- key='premadeThemeColorLabel'
- >
- <label>
- <input
- id='standardThemes'
- type='radio'
- name='theme'
- checked={!displayCustom}
- onChange={this.updateType.bind(this, 'premade')}
- />
- <FormattedMessage
- id='user.settings.display.theme.themeColors'
- defaultMessage='Theme Colors'
- />
- </label>
- <br/>
- </div>
- );
- }
-
- inputs.push(premade);
-
- if (allowCustomThemes) {
- inputs.push(
- <div
- className='radio'
- key='customThemeColorLabel'
- >
- <label>
- <input
- id='customThemes'
- type='radio'
- name='theme'
- checked={displayCustom}
- onChange={this.updateType.bind(this, 'custom')}
- />
- <FormattedMessage
- id='user.settings.display.theme.customTheme'
- defaultMessage='Custom Theme'
- />
- </label>
- </div>
- );
-
- inputs.push(custom);
-
- inputs.push(
- <div key='otherThemes'>
- <br/>
- <a
- id='otherThemes'
- href='http://docs.mattermost.com/help/settings/theme-colors.html#custom-theme-examples'
- target='_blank'
- rel='noopener noreferrer'
- >
- <FormattedMessage
- id='user.settings.display.theme.otherThemes'
- defaultMessage='See other themes'
- />
- </a>
- </div>
- );
-
- inputs.push(
- <div
- key='importSlackThemeButton'
- className='padding-top'
- >
- <a
- id='slackImportTheme'
- className='theme'
- onClick={this.handleImportModal}
- >
- <FormattedMessage
- id='user.settings.display.theme.import'
- defaultMessage='Import theme colors from Slack'
- />
- </a>
- </div>
- );
- }
-
- let allTeamsCheckbox = null;
- if (this.state.showAllTeamsCheckbox) {
- allTeamsCheckbox = (
- <div className='checkbox user-settings__submit-checkbox'>
- <label>
- <input
- id='applyThemeToAllTeams'
- type='checkbox'
- checked={this.state.applyToAllTeams}
- onChange={(e) => this.setState({applyToAllTeams: e.target.checked})}
- />
- <FormattedMessage
- id='user.settings.display.theme.applyToAllTeams'
- defaultMessage='Apply new theme to all my teams'
- />
- </label>
- </div>
- );
- }
-
- themeUI = (
- <SettingItemMax
- inputs={inputs}
- submitExtra={allTeamsCheckbox}
- submit={this.submitTheme}
- server_error={serverError}
- width='full'
- updateSection={(e) => {
- this.props.updateSection('');
- e.preventDefault();
- }}
- />
- );
- } else {
- themeUI = (
- <SettingItemMin
- title={
- <FormattedMessage
- id='user.settings.display.theme.title'
- defaultMessage='Theme'
- />
- }
- describe={
- <FormattedMessage
- id='user.settings.display.theme.describe'
- defaultMessage='Open to manage your theme'
- />
- }
- updateSection={() => {
- this.props.updateSection('theme');
- }}
- />
- );
- }
-
- return themeUI;
- }
-}
-
-ThemeSetting.propTypes = {
- selected: PropTypes.bool.isRequired,
- updateSection: PropTypes.func.isRequired,
- setRequireConfirm: PropTypes.func.isRequired,
- setEnforceFocus: PropTypes.func.isRequired
-};