summaryrefslogtreecommitdiffstats
path: root/webapp/components/admin_console
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/components/admin_console')
-rw-r--r--webapp/components/admin_console/admin_console.jsx68
-rw-r--r--webapp/components/admin_console/admin_navbar_dropdown.jsx223
-rw-r--r--webapp/components/admin_console/admin_settings.jsx147
-rw-r--r--webapp/components/admin_console/admin_sidebar.jsx702
-rw-r--r--webapp/components/admin_console/admin_sidebar_category.jsx86
-rw-r--r--webapp/components/admin_console/admin_sidebar_header.jsx69
-rw-r--r--webapp/components/admin_console/admin_sidebar_section.jsx102
-rw-r--r--webapp/components/admin_console/audits/audits.jsx101
-rw-r--r--webapp/components/admin_console/audits/index.js27
-rw-r--r--webapp/components/admin_console/banner.jsx39
-rw-r--r--webapp/components/admin_console/boolean_setting.jsx99
-rw-r--r--webapp/components/admin_console/brand_image_setting.jsx213
-rw-r--r--webapp/components/admin_console/client_versions_settings.jsx169
-rw-r--r--webapp/components/admin_console/cluster_settings.jsx273
-rw-r--r--webapp/components/admin_console/cluster_table.jsx172
-rw-r--r--webapp/components/admin_console/cluster_table_container.jsx72
-rw-r--r--webapp/components/admin_console/color_setting.jsx119
-rw-r--r--webapp/components/admin_console/compliance_reports/compliance_reports.jsx394
-rw-r--r--webapp/components/admin_console/compliance_reports/index.js46
-rw-r--r--webapp/components/admin_console/compliance_settings.jsx126
-rw-r--r--webapp/components/admin_console/configuration_settings.jsx356
-rw-r--r--webapp/components/admin_console/connection_security_dropdown_setting.jsx191
-rw-r--r--webapp/components/admin_console/connection_settings.jsx87
-rw-r--r--webapp/components/admin_console/custom_brand_settings.jsx156
-rw-r--r--webapp/components/admin_console/custom_emoji_settings.jsx121
-rw-r--r--webapp/components/admin_console/custom_integrations_settings.jsx197
-rw-r--r--webapp/components/admin_console/database_settings.jsx238
-rw-r--r--webapp/components/admin_console/developer_settings.jsx106
-rw-r--r--webapp/components/admin_console/dropdown_setting.jsx66
-rw-r--r--webapp/components/admin_console/elasticsearch_settings.jsx333
-rw-r--r--webapp/components/admin_console/elasticsearch_status/index.js28
-rw-r--r--webapp/components/admin_console/elasticsearch_status/status.jsx361
-rw-r--r--webapp/components/admin_console/email_authentication_settings.jsx102
-rw-r--r--webapp/components/admin_console/email_connection_test.jsx130
-rw-r--r--webapp/components/admin_console/email_settings.jsx395
-rw-r--r--webapp/components/admin_console/external_service_settings.jsx66
-rw-r--r--webapp/components/admin_console/file_upload_setting.jsx126
-rw-r--r--webapp/components/admin_console/generated_setting.jsx106
-rw-r--r--webapp/components/admin_console/gitlab_settings.jsx179
-rw-r--r--webapp/components/admin_console/index.js27
-rw-r--r--webapp/components/admin_console/ldap_settings.jsx504
-rw-r--r--webapp/components/admin_console/legal_and_support_settings.jsx159
-rw-r--r--webapp/components/admin_console/license_settings.jsx286
-rw-r--r--webapp/components/admin_console/link_previews_settings.jsx64
-rw-r--r--webapp/components/admin_console/localization_settings.jsx134
-rw-r--r--webapp/components/admin_console/log_settings.jsx282
-rw-r--r--webapp/components/admin_console/manage_roles_modal/index.js25
-rw-r--r--webapp/components/admin_console/manage_roles_modal/manage_roles_modal.jsx349
-rw-r--r--webapp/components/admin_console/manage_teams_modal/manage_teams_dropdown.jsx148
-rw-r--r--webapp/components/admin_console/manage_teams_modal/manage_teams_modal.jsx218
-rw-r--r--webapp/components/admin_console/manage_teams_modal/remove_from_team_button.jsx54
-rw-r--r--webapp/components/admin_console/manage_tokens_modal/index.js27
-rw-r--r--webapp/components/admin_console/manage_tokens_modal/manage_tokens_modal.jsx181
-rw-r--r--webapp/components/admin_console/metrics_settings.jsx94
-rw-r--r--webapp/components/admin_console/mfa_settings.jsx97
-rw-r--r--webapp/components/admin_console/multiselect_settings.jsx81
-rw-r--r--webapp/components/admin_console/native_app_link_settings.jsx102
-rw-r--r--webapp/components/admin_console/oauth_settings.jsx430
-rw-r--r--webapp/components/admin_console/password_settings.jsx281
-rw-r--r--webapp/components/admin_console/plugin_settings/index.js27
-rw-r--r--webapp/components/admin_console/plugin_settings/plugin_settings.jsx293
-rw-r--r--webapp/components/admin_console/policy_settings.jsx413
-rw-r--r--webapp/components/admin_console/post_edit_setting.jsx101
-rw-r--r--webapp/components/admin_console/privacy_settings.jsx83
-rw-r--r--webapp/components/admin_console/public_link_settings.jsx84
-rw-r--r--webapp/components/admin_console/push_settings.jsx233
-rw-r--r--webapp/components/admin_console/radio_setting.jsx65
-rw-r--r--webapp/components/admin_console/rate_settings.jsx179
-rw-r--r--webapp/components/admin_console/remove_file_setting.jsx62
-rw-r--r--webapp/components/admin_console/request_button/request_button.jsx262
-rw-r--r--webapp/components/admin_console/reset_password_modal.jsx165
-rw-r--r--webapp/components/admin_console/revoke_token_button/index.js24
-rw-r--r--webapp/components/admin_console/revoke_token_button/revoke_token_button.jsx56
-rw-r--r--webapp/components/admin_console/saml_settings.jsx584
-rw-r--r--webapp/components/admin_console/save_button.jsx64
-rw-r--r--webapp/components/admin_console/server_logs/index.js27
-rw-r--r--webapp/components/admin_console/server_logs/logs.jsx123
-rw-r--r--webapp/components/admin_console/session_settings.jsx127
-rw-r--r--webapp/components/admin_console/setting.jsx35
-rw-r--r--webapp/components/admin_console/settings_group.jsx44
-rw-r--r--webapp/components/admin_console/signup_settings.jsx117
-rw-r--r--webapp/components/admin_console/storage_settings.jsx340
-rw-r--r--webapp/components/admin_console/system_users/index.js31
-rw-r--r--webapp/components/admin_console/system_users/system_users.jsx372
-rw-r--r--webapp/components/admin_console/system_users/system_users_dropdown.jsx529
-rw-r--r--webapp/components/admin_console/system_users/system_users_list.jsx295
-rw-r--r--webapp/components/admin_console/text_setting.jsx88
-rw-r--r--webapp/components/admin_console/users_and_teams_settings.jsx218
-rw-r--r--webapp/components/admin_console/webrtc_settings.jsx218
-rw-r--r--webapp/components/admin_console/webserver_mode_dropdown_setting.jsx101
90 files changed, 0 insertions, 15494 deletions
diff --git a/webapp/components/admin_console/admin_console.jsx b/webapp/components/admin_console/admin_console.jsx
deleted file mode 100644
index 17670d6ab..000000000
--- a/webapp/components/admin_console/admin_console.jsx
+++ /dev/null
@@ -1,68 +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 'bootstrap';
-
-import AnnouncementBar from 'components/announcement_bar';
-import AdminSidebar from './admin_sidebar.jsx';
-
-import {reloadIfServerVersionChanged} from 'actions/global_actions.jsx';
-
-export default class AdminConsole extends React.Component {
- static propTypes = {
-
- /*
- * Children components to render
- */
- children: PropTypes.node.isRequired,
-
- /*
- * Object representing the config file
- */
- config: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /*
- * Function to get the config file
- */
- getConfig: PropTypes.func.isRequired
- }).isRequired
- }
-
- componentWillMount() {
- this.props.actions.getConfig();
- reloadIfServerVersionChanged();
- }
-
- render() {
- const config = this.props.config;
- if (Object.keys(config).length === 0) {
- return <div/>;
- }
- if (config && Object.keys(config).length === 0 && config.constructor === 'Object') {
- return (
- <div className='admin-console__wrapper'>
- <AnnouncementBar/>
- <div className='admin-console'/>
- </div>
- );
- }
-
- // not every page in the system console will need the config, but the vast majority will
- const children = React.cloneElement(this.props.children, {
- config
- });
- return (
- <div className='admin-console__wrapper'>
- <AnnouncementBar/>
- <div className='admin-console'>
- <AdminSidebar/>
- {children}
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/admin_navbar_dropdown.jsx b/webapp/components/admin_console/admin_navbar_dropdown.jsx
deleted file mode 100644
index 6ef4906f5..000000000
--- a/webapp/components/admin_console/admin_navbar_dropdown.jsx
+++ /dev/null
@@ -1,223 +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 TeamStore from 'stores/team_store.jsx';
-import Constants from 'utils/constants.jsx';
-import AboutBuildModal from 'components/about_build_modal.jsx';
-import {sortTeamsByDisplayName} from 'utils/team_utils.jsx';
-import * as GlobalActions from 'actions/global_actions.jsx';
-
-import {FormattedMessage} from 'react-intl';
-
-import {Link} from 'react-router/es6';
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-export default class AdminNavbarDropdown extends React.Component {
- constructor(props) {
- super(props);
- this.blockToggle = false;
- this.onTeamChange = this.onTeamChange.bind(this);
- this.handleAboutModal = this.handleAboutModal.bind(this);
- this.aboutModalDismissed = this.aboutModalDismissed.bind(this);
-
- this.state = {
- teams: TeamStore.getAll(),
- teamMembers: TeamStore.getMyTeamMembers(),
- showAboutModal: false
- };
- }
-
- componentDidMount() {
- $(ReactDOM.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
- this.blockToggle = true;
- setTimeout(() => {
- this.blockToggle = false;
- }, 100);
- });
-
- TeamStore.addChangeListener(this.onTeamChange);
- }
-
- componentWillUnmount() {
- $(ReactDOM.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown');
- TeamStore.removeChangeListener(this.onTeamChange);
- }
-
- handleAboutModal(e) {
- e.preventDefault();
-
- this.setState({showAboutModal: true});
- }
-
- aboutModalDismissed() {
- this.setState({showAboutModal: false});
- }
-
- onTeamChange() {
- this.setState({
- teams: TeamStore.getAll(),
- teamMembers: TeamStore.getMyTeamMembers()
- });
- }
-
- render() {
- var teamsArray = []; // Array of team objects
- var teams = []; // Array of team components
- let switchTeams;
-
- if (this.state.teamMembers && this.state.teamMembers.length > 0) {
- for (const index in this.state.teamMembers) {
- if (this.state.teamMembers.hasOwnProperty(index)) {
- const teamMember = this.state.teamMembers[index];
- const team = this.state.teams[teamMember.team_id];
- teamsArray.push(team);
- }
- }
-
- // Sort teams alphabetically with display_name
- teamsArray = teamsArray.sort(sortTeamsByDisplayName);
-
- for (const team of teamsArray) {
- teams.push(
- <li key={'team_' + team.name}>
- <Link
- id={'swithTo' + Utils.createSafeId(team.name)}
- to={'/' + team.name + '/channels/town-square'}
- >
- <FormattedMessage
- id='navbar_dropdown.switchTo'
- defaultMessage='Switch to '
- />
- {team.display_name}
- </Link>
- </li>
- );
- }
-
- teams.push(
- <li
- key='teamDiv'
- className='divider'
- />
- );
- } else {
- switchTeams = (
- <li>
- <Link
- to={'/select_team'}
- >
- <i className='fa fa-exchange'/>
- <FormattedMessage
- id='admin.nav.switch'
- defaultMessage='Team Selection'
- />
- </Link>
- </li>
- );
- }
-
- return (
- <ul className='nav navbar-nav navbar-right admin-navbar-dropdown'>
- <li
- ref='dropdown'
- className='dropdown'
- >
- <a
- href='#'
- id='adminNavbarDropdownButton'
- className='dropdown-toggle admin-navbar-dropdown__toggle'
- data-toggle='dropdown'
- role='button'
- aria-expanded='false'
- >
- <span
- className='dropdown__icon admin-navbar-dropdown__icon'
- dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}}
- />
- </a>
- <ul
- className='dropdown-menu'
- role='menu'
- >
- {teams}
- {switchTeams}
- <li
- key='teamDiv'
- className='divider'
- />
- <li>
- <Link
- to='https://about.mattermost.com/administrators-guide/'
- rel='noopener noreferrer'
- target='_blank'
- >
- <FormattedMessage
- id='admin.nav.administratorsGuide'
- defaultMessage='Administrator Guide'
- />
- </Link>
- </li>
- <li>
- <Link
- to='https://about.mattermost.com/troubleshooting-forum/'
- rel='noopener noreferrer'
- target='_blank'
- >
- <FormattedMessage
- id='admin.nav.troubleshootingForum'
- defaultMessage='Troubleshooting Forum'
- />
- </Link>
- </li>
- <li>
- <Link
- to='https://about.mattermost.com/commercial-support/'
- rel='noopener noreferrer'
- target='_blank'
- >
- <FormattedMessage
- id='admin.nav.commercialSupport'
- defaultMessage='Commercial Support'
- />
- </Link>
- </li>
- <li>
- <a
- href='#'
- onClick={this.handleAboutModal}
- >
- <FormattedMessage
- id='navbar_dropdown.about'
- defaultMessage='About Mattermost'
- />
- </a>
- </li>
- <li className='divider'/>
- <li>
- <a
- href='#'
- id='logout'
- onClick={() => GlobalActions.emitUserLoggedOutEvent()}
- >
- <FormattedMessage
- id='admin.nav.logout'
- defaultMessage='Logout'
- />
- </a>
- </li>
- <AboutBuildModal
- show={this.state.showAboutModal}
- onModalDismissed={this.aboutModalDismissed}
- />
- </ul>
- </li>
- </ul>
- );
- }
-}
diff --git a/webapp/components/admin_console/admin_settings.jsx b/webapp/components/admin_console/admin_settings.jsx
deleted file mode 100644
index 2411fbdb8..000000000
--- a/webapp/components/admin_console/admin_settings.jsx
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import FormError from 'components/form_error.jsx';
-import SaveButton from 'components/admin_console/save_button.jsx';
-
-import {saveConfig} from 'actions/admin_actions.jsx';
-
-export default class AdminSettings extends React.Component {
- static propTypes = {
-
- /*
- * Object representing the config file
- */
- config: PropTypes.object
- }
-
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- this.doSubmit = this.doSubmit.bind(this);
-
- this.state = Object.assign(this.getStateFromConfig(props.config), {
- saveNeeded: false,
- saving: false,
- serverError: null
- });
- }
-
- handleChange(id, value) {
- this.setState({
- saveNeeded: true,
- [id]: value
- });
- }
-
- handleSubmit(e) {
- e.preventDefault();
-
- this.doSubmit();
- }
-
- doSubmit(callback) {
- this.setState({
- saving: true,
- serverError: null
- });
-
- // clone config so that we aren't modifying data in the stores
- let config = JSON.parse(JSON.stringify(this.props.config));
- config = this.getConfigFromState(config);
-
- saveConfig(
- config,
- (savedConfig) => {
- this.setState(this.getStateFromConfig(savedConfig));
-
- this.setState({
- saveNeeded: false,
- saving: false
- });
-
- if (callback) {
- callback();
- }
-
- if (this.handleSaved) {
- this.handleSaved(config);
- }
- },
- (err) => {
- this.setState({
- saving: false,
- serverError: err.message
- });
-
- if (callback) {
- callback();
- }
-
- if (this.handleSaved) {
- this.handleSaved(config);
- }
- }
- );
- }
-
- parseInt(str, defaultValue) {
- const n = parseInt(str, 10);
-
- if (isNaN(n)) {
- if (defaultValue) {
- return defaultValue;
- }
- return 0;
- }
-
- return n;
- }
-
- parseIntNonZero(str, defaultValue) {
- const n = parseInt(str, 10);
-
- if (isNaN(n) || n < 1) {
- if (defaultValue) {
- return defaultValue;
- }
- return 1;
- }
-
- return n;
- }
-
- render() {
- return (
- <div className='wrapper--fixed'>
- <h3 className='admin-console-header'>
- {this.renderTitle()}
- </h3>
- <form
- className='form-horizontal'
- role='form'
- onSubmit={this.handleSubmit}
- >
- {this.renderSettings()}
- <div className='form-group'>
- <FormError error={this.state.serverError}/>
- </div>
- <div className='form-group'>
- <div className='col-sm-12'>
- <SaveButton
- saving={this.state.saving}
- disabled={!this.state.saveNeeded || (this.canSave && !this.canSave())}
- onClick={this.handleSubmit}
- />
- </div>
- </div>
- </form>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx
deleted file mode 100644
index 4918cdac0..000000000
--- a/webapp/components/admin_console/admin_sidebar.jsx
+++ /dev/null
@@ -1,702 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import PropTypes from 'prop-types';
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSidebarCategory from './admin_sidebar_category.jsx';
-import AdminSidebarHeader from './admin_sidebar_header.jsx';
-import AdminSidebarSection from './admin_sidebar_section.jsx';
-
-export default class AdminSidebar extends React.Component {
- static get contextTypes() {
- return {
- router: PropTypes.object.isRequired
- };
- }
-
- constructor(props) {
- super(props);
-
- this.updateTitle = this.updateTitle.bind(this);
- }
-
- componentDidMount() {
- this.updateTitle();
-
- if (!Utils.isMobile()) {
- $('.admin-sidebar .nav-pills__container').perfectScrollbar({
- suppressScrollX: true
- });
- }
- }
-
- componentDidUpdate() {
- if (!Utils.isMobile()) {
- $('.admin-sidebar .nav-pills__container').perfectScrollbar({
- suppressScrollX: true
- });
- }
- }
-
- updateTitle() {
- let currentSiteName = '';
- if (global.window.mm_config.SiteName != null) {
- currentSiteName = global.window.mm_config.SiteName;
- }
-
- document.title = Utils.localizeMessage('sidebar_right_menu.console', 'System Console') + ' - ' + currentSiteName;
- }
-
- render() {
- let oauthSettings = null;
- let ldapSettings = null;
- let samlSettings = null;
- let clusterSettings = null;
- let metricsSettings = null;
- let complianceSettings = null;
- let mfaSettings = null;
- let pluginSettings = null;
-
- let license = null;
- let audits = null;
- let policy = null;
-
- if (window.mm_config.BuildEnterpriseReady === 'true') {
- license = (
- <AdminSidebarSection
- name='license'
- title={
- <FormattedMessage
- id='admin.sidebar.license'
- defaultMessage='Edition and License'
- />
- }
- />
- );
- }
-
- if (window.mm_license.IsLicensed === 'true') {
- if (global.window.mm_license.LDAP === 'true') {
- ldapSettings = (
- <AdminSidebarSection
- name='ldap'
- title={
- <FormattedMessage
- id='admin.sidebar.ldap'
- defaultMessage='AD/LDAP'
- />
- }
- />
- );
- }
-
- if (global.window.mm_license.Cluster === 'true') {
- clusterSettings = (
- <AdminSidebarSection
- name='cluster'
- title={
- <FormattedMessage
- id='admin.sidebar.cluster'
- defaultMessage='High Availability'
- />
- }
- />
- );
- }
-
- if (global.window.mm_license.Metrics === 'true') {
- metricsSettings = (
- <AdminSidebarSection
- name='metrics'
- title={
- <FormattedMessage
- id='admin.sidebar.metrics'
- defaultMessage='Performance Monitoring'
- />
- }
- />
- );
- }
-
- if (global.window.mm_license.SAML === 'true') {
- samlSettings = (
- <AdminSidebarSection
- name='saml'
- title={
- <FormattedMessage
- id='admin.sidebar.saml'
- defaultMessage='SAML 2.0'
- />
- }
- />
- );
- }
-
- if (global.window.mm_license.Compliance === 'true') {
- complianceSettings = (
- <AdminSidebarSection
- name='compliance'
- title={
- <FormattedMessage
- id='admin.sidebar.compliance'
- defaultMessage='Compliance'
- />
- }
- />
- );
- }
-
- if (global.window.mm_license.MFA === 'true') {
- mfaSettings = (
- <AdminSidebarSection
- name='mfa'
- title={
- <FormattedMessage
- id='admin.sidebar.mfa'
- defaultMessage='MFA'
- />
- }
- />
- );
- }
-
- oauthSettings = (
- <AdminSidebarSection
- name='oauth'
- title={
- <FormattedMessage
- id='admin.sidebar.oauth'
- defaultMessage='OAuth 2.0'
- />
- }
- />
- );
-
- policy = (
- <AdminSidebarSection
- name='policy'
- title={
- <FormattedMessage
- id='admin.sidebar.policy'
- defaultMessage='Policy'
- />
- }
- />
- );
- } else {
- oauthSettings = (
- <AdminSidebarSection
- name='gitlab'
- title={
- <FormattedMessage
- id='admin.sidebar.gitlab'
- defaultMessage='GitLab'
- />
- }
- />
- );
- }
-
- if (window.mm_license.IsLicensed === 'true') {
- audits = (
- <AdminSidebarSection
- name='audits'
- title={
- <FormattedMessage
- id='admin.sidebar.audits'
- defaultMessage='Complaince and Auditing'
- />
- }
- />
- );
- }
-
- let customBranding = null;
-
- if (window.mm_license.IsLicensed === 'true') {
- customBranding = (
- <AdminSidebarSection
- name='custom_brand'
- title={
- <FormattedMessage
- id='admin.sidebar.customBrand'
- defaultMessage='Custom Branding'
- />
- }
- />
- );
- }
-
- let otherCategory = null;
- if (license || audits) {
- otherCategory = (
- <AdminSidebarCategory
- parentLink='/admin_console'
- icon='fa-wrench'
- title={
- <FormattedMessage
- id='admin.sidebar.other'
- defaultMessage='OTHER'
- />
- }
- >
- {license}
- {audits}
- </AdminSidebarCategory>
- );
- }
-
- const webrtcSettings = (
- <AdminSidebarSection
- name='webrtc'
- title={
- <FormattedMessage
- id='admin.sidebar.webrtc'
- defaultMessage='WebRTC (Beta)'
- />
- }
- />
- );
-
- let elasticSearchSettings = null;
- if (window.mm_license.IsLicensed === 'true') {
- elasticSearchSettings = (
- <AdminSidebarSection
- name='elasticsearch'
- title={
- <FormattedMessage
- id='admin.sidebar.elasticsearch'
- defaultMessage='Elasticsearch (Beta)'
- />
- }
- />
- );
- }
-
- if (window.mm_config.PluginsEnabled === 'true' && window.mm_license.IsLicensed === 'true') {
- pluginSettings = (
- <AdminSidebarSection
- name='plugins'
- title={
- <FormattedMessage
- id='admin.sidebar.plugins'
- defaultMessage='Plugins (experimental)'
- />
- }
- />
- );
- }
-
- const SHOW_CLIENT_VERSIONS = false;
- let clientVersions = null;
- if (SHOW_CLIENT_VERSIONS) {
- clientVersions = (
- <AdminSidebarSection
- name='client_versions'
- title={
- <FormattedMessage
- id='admin.sidebar.client_versions'
- defaultMessage='Client Versions'
- />
- }
- />
- );
- }
-
- return (
- <div className='admin-sidebar'>
- <AdminSidebarHeader/>
- <div className='nav-pills__container'>
- <ul className='nav nav-pills nav-stacked'>
- <AdminSidebarCategory
- parentLink='/admin_console'
- icon='fa-bar-chart'
- title={
- <FormattedMessage
- id='admin.sidebar.reports'
- defaultMessage='REPORTING'
- />
- }
- >
- <AdminSidebarSection
- name='system_analytics'
- title={
- <FormattedMessage
- id='admin.sidebar.view_statistics'
- defaultMessage='Site Statistics'
- />
- }
- />
- <AdminSidebarSection
- name='team_analytics'
- title={
- <FormattedMessage
- id='admin.sidebar.statistics'
- defaultMessage='Team Statistics'
- />
- }
- />
- <AdminSidebarSection
- name='users'
- title={
- <FormattedMessage
- id='admin.sidebar.users'
- defaultMessage='Users'
- />
- }
- />
- <AdminSidebarSection
- name='logs'
- title={
- <FormattedMessage
- id='admin.sidebar.logs'
- defaultMessage='Logs'
- />
- }
- />
- </AdminSidebarCategory>
- <AdminSidebarCategory
- sectionClass='sections--settings'
- parentLink='/admin_console'
- icon='fa-gear'
- title={
- <FormattedMessage
- id='admin.sidebar.settings'
- defaultMessage='SETTINGS'
- />
- }
- >
- <AdminSidebarSection
- name='general'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.general'
- defaultMessage='General'
- />
- }
- >
- <AdminSidebarSection
- name='configuration'
- title={
- <FormattedMessage
- id='admin.sidebar.configuration'
- defaultMessage='Configuration'
- />
- }
- />
- <AdminSidebarSection
- name='localization'
- title={
- <FormattedMessage
- id='admin.sidebar.localization'
- defaultMessage='Localization'
- />
- }
- />
- <AdminSidebarSection
- name='users_and_teams'
- title={
- <FormattedMessage
- id='admin.sidebar.usersAndTeams'
- defaultMessage='Users and Teams'
- />
- }
- />
- {policy}
- <AdminSidebarSection
- name='privacy'
- title={
- <FormattedMessage
- id='admin.sidebar.privacy'
- defaultMessage='Privacy'
- />
- }
- />
- {complianceSettings}
- <AdminSidebarSection
- name='logging'
- title={
- <FormattedMessage
- id='admin.sidebar.logging'
- defaultMessage='Logging'
- />
- }
- />
- </AdminSidebarSection>
- <AdminSidebarSection
- name='authentication'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.authentication'
- defaultMessage='Authentication'
- />
- }
- >
- <AdminSidebarSection
- name='authentication_email'
- title={
- <FormattedMessage
- id='admin.sidebar.email'
- defaultMessage='Email'
- />
- }
- />
- {oauthSettings}
- {ldapSettings}
- {samlSettings}
- {mfaSettings}
- </AdminSidebarSection>
- <AdminSidebarSection
- name='security'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.security'
- defaultMessage='Security'
- />
- }
- >
- <AdminSidebarSection
- name='sign_up'
- title={
- <FormattedMessage
- id='admin.sidebar.signUp'
- defaultMessage='Sign Up'
- />
- }
- />
- <AdminSidebarSection
- name='password'
- title={
- <FormattedMessage
- id='admin.sidebar.password'
- defaultMessage='Password'
- />
- }
- />
- <AdminSidebarSection
- name='public_links'
- title={
- <FormattedMessage
- id='admin.sidebar.publicLinks'
- defaultMessage='Public Links'
- />
- }
- />
- <AdminSidebarSection
- name='sessions'
- title={
- <FormattedMessage
- id='admin.sidebar.sessions'
- defaultMessage='Sessions'
- />
- }
- />
- <AdminSidebarSection
- name='connections'
- title={
- <FormattedMessage
- id='admin.sidebar.connections'
- defaultMessage='Connections'
- />
- }
- />
- {clientVersions}
- </AdminSidebarSection>
- <AdminSidebarSection
- name='notifications'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.notifications'
- defaultMessage='Notifications'
- />
- }
- >
- <AdminSidebarSection
- name='notifications_email'
- title={
- <FormattedMessage
- id='admin.sidebar.email'
- defaultMessage='Email'
- />
- }
- />
- <AdminSidebarSection
- name='push'
- title={
- <FormattedMessage
- id='admin.sidebar.push'
- defaultMessage='Mobile Push'
- />
- }
- />
- </AdminSidebarSection>
- <AdminSidebarSection
- name='integrations'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.integrations'
- defaultMessage='Integrations'
- />
- }
- >
- <AdminSidebarSection
- name='custom'
- title={
- <FormattedMessage
- id='admin.sidebar.customIntegrations'
- defaultMessage='Custom Integrations'
- />
- }
- />
- <AdminSidebarSection
- name='jira'
- title={
- <FormattedMessage
- id='admin.sidebar.jira'
- defaultMessage='JIRA (Beta)'
- />
- }
- />
- {webrtcSettings}
- <AdminSidebarSection
- name='external'
- title={
- <FormattedMessage
- id='admin.sidebar.external'
- defaultMessage='External Services'
- />
- }
- />
- {pluginSettings}
- </AdminSidebarSection>
- <AdminSidebarSection
- name='files'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.files'
- defaultMessage='Files'
- />
- }
- >
- <AdminSidebarSection
- key='storage'
- name='storage'
- title={
- <FormattedMessage
- id='admin.sidebar.storage'
- defaultMessage='Storage'
- />
- }
- />
- </AdminSidebarSection>
- <AdminSidebarSection
- name='customization'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.customization'
- defaultMessage='Customization'
- />
- }
- >
- {customBranding}
- <AdminSidebarSection
- name='emoji'
- title={
- <FormattedMessage
- id='admin.sidebar.emoji'
- defaultMessage='Emoji'
- />
-
- }
- />
- <AdminSidebarSection
- name='link_previews'
- title={
- <FormattedMessage
- id='admin.sidebar.linkPreviews'
- defaultMessage='Link Previews'
- />
-
- }
- />
- <AdminSidebarSection
- name='legal_and_support'
- title={
- <FormattedMessage
- id='admin.sidebar.legalAndSupport'
- defaultMessage='Legal and Support'
- />
- }
- />
- <AdminSidebarSection
- name='native_app_links'
- title={
- <FormattedMessage
- id='admin.sidebar.nativeAppLinks'
- defaultMessage='Mattermost App Links'
- />
-
- }
- />
- </AdminSidebarSection>
- <AdminSidebarSection
- name='advanced'
- type='text'
- title={
- <FormattedMessage
- id='admin.sidebar.advanced'
- defaultMessage='Advanced'
- />
- }
- >
- <AdminSidebarSection
- name='rate'
- title={
- <FormattedMessage
- id='admin.sidebar.rateLimiting'
- defaultMessage='Rate Limiting'
- />
- }
- />
- <AdminSidebarSection
- name='database'
- title={
- <FormattedMessage
- id='admin.sidebar.database'
- defaultMessage='Database'
- />
- }
- />
- {elasticSearchSettings}
- <AdminSidebarSection
- name='developer'
- title={
- <FormattedMessage
- id='admin.sidebar.developer'
- defaultMessage='Developer'
- />
- }
- />
- {clusterSettings}
- {metricsSettings}
- </AdminSidebarSection>
- </AdminSidebarCategory>
- {otherCategory}
- </ul>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/admin_sidebar_category.jsx b/webapp/components/admin_console/admin_sidebar_category.jsx
deleted file mode 100644
index 5db68e876..000000000
--- a/webapp/components/admin_console/admin_sidebar_category.jsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {Link} from 'react-router/es6';
-
-export default class AdminSidebarCategory extends React.Component {
- static get propTypes() {
- return {
- name: PropTypes.string,
- title: PropTypes.node.isRequired,
- icon: PropTypes.string.isRequired,
- sectionClass: PropTypes.string,
- parentLink: PropTypes.string,
- children: PropTypes.node,
- action: PropTypes.node
- };
- }
-
- static get defaultProps() {
- return {
- parentLink: ''
- };
- }
-
- static get contextTypes() {
- return {
- router: PropTypes.object.isRequired
- };
- }
-
- render() {
- let link = this.props.parentLink;
- let title = (
- <div className='category-title category-title--active'>
- <i className={'category-icon fa ' + this.props.icon}/>
- <span className='category-title__text'>
- {this.props.title}
- </span>
- {this.props.action}
- </div>
- );
-
- if (this.props.name) {
- link += '/' + name;
- title = (
- <Link
- to={link}
- className='category-title'
- activeClassName='category-title category-title--active'
- >
- {title}
- </Link>
- );
- }
-
- let clonedChildren = null;
- if (this.props.children && this.context.router.isActive(link)) {
- clonedChildren = (
- <ul className={'sections ' + this.props.sectionClass}>
- {
- React.Children.map(this.props.children, (child) => {
- if (child === null) {
- return null;
- }
-
- return React.cloneElement(child, {
- parentLink: link
- });
- })
- }
- </ul>
- );
- }
-
- return (
- <li className='sidebar-category'>
- {title}
- {clonedChildren}
- </li>
- );
- }
-}
diff --git a/webapp/components/admin_console/admin_sidebar_header.jsx b/webapp/components/admin_console/admin_sidebar_header.jsx
deleted file mode 100644
index 1c64eb6d1..000000000
--- a/webapp/components/admin_console/admin_sidebar_header.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import AdminNavbarDropdown from './admin_navbar_dropdown.jsx';
-import UserStore from 'stores/user_store.jsx';
-import {Client4} from 'mattermost-redux/client';
-
-import {FormattedMessage} from 'react-intl';
-
-import React from 'react';
-
-export default class SidebarHeader extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {};
- }
-
- toggleDropdown = (e) => {
- e.preventDefault();
-
- if (this.refs.dropdown.blockToggle) {
- this.refs.dropdown.blockToggle = false;
- return;
- }
-
- $('.team__header').find('.dropdown-toggle').dropdown('toggle');
- }
-
- render() {
- var me = UserStore.getCurrentUser();
- var profilePicture = null;
-
- if (!me) {
- return null;
- }
-
- if (me.last_picture_update) {
- profilePicture = (
- <img
- className='user__picture'
- src={Client4.getProfilePictureUrl(me.id, me.last_picture_update)}
- />
- );
- }
-
- return (
- <div className='team__header theme'>
- <a
- href='#'
- onClick={this.toggleDropdown}
- >
- {profilePicture}
- <div className='header__info'>
- <div className='team__name'>
- <FormattedMessage
- id='admin.sidebarHeader.systemConsole'
- defaultMessage='System Console'
- />
- </div>
- <div className='user__name'>{'@' + me.username}</div>
- </div>
- </a>
- <AdminNavbarDropdown ref='dropdown'/>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/admin_sidebar_section.jsx b/webapp/components/admin_console/admin_sidebar_section.jsx
deleted file mode 100644
index 2a8ecab71..000000000
--- a/webapp/components/admin_console/admin_sidebar_section.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {Link} from 'react-router/es6';
-import * as Utils from 'utils/utils.jsx';
-
-export default class AdminSidebarSection extends React.Component {
- static get propTypes() {
- return {
- name: PropTypes.string.isRequired,
- title: PropTypes.node.isRequired,
- type: PropTypes.string,
- parentLink: PropTypes.string,
- subsection: PropTypes.bool,
- children: PropTypes.node,
- action: PropTypes.node,
- onlyActiveOnIndex: PropTypes.bool
- };
- }
-
- static get defaultProps() {
- return {
- parentLink: '',
- subsection: false,
- children: [],
- onlyActiveOnIndex: true
- };
- }
-
- getLink() {
- return this.props.parentLink + '/' + this.props.name;
- }
-
- render() {
- const link = this.getLink();
-
- let clonedChildren = null;
- if (this.props.children) {
- clonedChildren = (
- <ul className='nav nav__sub-menu subsections'>
- {
- React.Children.map(this.props.children, (child) => {
- if (child === null) {
- return null;
- }
-
- return React.cloneElement(child, {
- parentLink: link,
- subsection: true
- });
- })
- }
- </ul>
- );
- }
-
- let className = 'sidebar-section';
- if (this.props.subsection) {
- className += ' sidebar-subsection';
- }
-
- let sidebarItem = (
- <Link
- id={Utils.createSafeId(this.props.name)}
- className={`${className}-title`}
- activeClassName={`${className}-title ${className}-title--active`}
- onlyActiveOnIndex={this.props.onlyActiveOnIndex}
- onClick={this.handleClick}
- to={link}
- >
- <span className={`${className}-title__text`}>
- {this.props.title}
- </span>
- {this.props.action}
- </Link>
- );
-
- if (this.props.type === 'text') {
- sidebarItem = (
- <div
- className={`${className}-title`}
- >
- <span className={`${className}-title__text`}>
- {this.props.title}
- </span>
- {this.props.action}
- </div>
- );
- }
-
- return (
- <li className={className}>
- {sidebarItem}
- {clonedChildren}
- </li>
- );
- }
-}
diff --git a/webapp/components/admin_console/audits/audits.jsx b/webapp/components/admin_console/audits/audits.jsx
deleted file mode 100644
index 0811c216f..000000000
--- a/webapp/components/admin_console/audits/audits.jsx
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import LoadingScreen from 'components/loading_screen.jsx';
-import AuditTable from 'components/audit_table.jsx';
-import ComplianceReports from 'components/admin_console/compliance_reports';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage} from 'react-intl';
-
-export default class Audits extends React.PureComponent {
- static propTypes = {
-
- /*
- * Array of audits to render
- */
- audits: PropTypes.arrayOf(PropTypes.object).isRequired,
-
- actions: PropTypes.shape({
-
- /*
- * Function to fetch audits
- */
- getAudits: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- loadingAudits: true
- };
- }
-
- componentDidMount() {
- this.props.actions.getAudits().then(
- () => this.setState({loadingAudits: false})
- );
- }
-
- reload = () => {
- this.setState({loadingAudits: true});
- this.props.actions.getAudits().then(
- () => this.setState({loadingAudits: false})
- );
- }
-
- render() {
- let content = null;
-
- if (global.window.mm_license.IsLicensed !== 'true') {
- return <div/>;
- }
-
- if (this.state.loadingAudits) {
- content = <LoadingScreen/>;
- } else {
- content = (
- <div style={{margin: '10px'}}>
- <AuditTable
- audits={this.props.audits}
- showUserId={true}
- showIp={true}
- showSession={true}
- />
- </div>
- );
- }
-
- return (
- <div>
- <ComplianceReports/>
-
- <div className='panel audit-panel'>
- <h3 className='admin-console-header'>
- <FormattedMessage
- id='admin.audits.title'
- defaultMessage='User Activity Logs'
- />
- <button
- type='submit'
- className='btn btn-link pull-right'
- onClick={this.reload}
- >
- <i className='fa fa-refresh'/>
- <FormattedMessage
- id='admin.audits.reload'
- defaultMessage='Reload User Activity Logs'
- />
- </button>
- </h3>
- <div className='audit-panel__table'>
- {content}
- </div>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/audits/index.js b/webapp/components/admin_console/audits/index.js
deleted file mode 100644
index a48e33538..000000000
--- a/webapp/components/admin_console/audits/index.js
+++ /dev/null
@@ -1,27 +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 {getAudits} from 'mattermost-redux/actions/admin';
-
-import * as Selectors from 'mattermost-redux/selectors/entities/admin';
-
-import Audits from './audits.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- audits: Object.values(Selectors.getAudits(state))
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getAudits
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(Audits);
diff --git a/webapp/components/admin_console/banner.jsx b/webapp/components/admin_console/banner.jsx
deleted file mode 100644
index 6395ef4a1..000000000
--- a/webapp/components/admin_console/banner.jsx
+++ /dev/null
@@ -1,39 +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 {FormattedMessage} from 'react-intl';
-
-export default function Banner(props) {
- let title = (
- <FormattedMessage
- id='admin.banner.heading'
- defaultMessage='Note:'
- />
- );
-
- if (props.title) {
- title = props.title;
- }
-
- return (
- <div className='banner'>
- <div className='banner__content'>
- <h4 className='banner__heading'>
- {title}
- </h4>
- <p>
- {props.description}
- </p>
- </div>
- </div>
- );
-}
-
-Banner.defaultProps = {
-};
-Banner.propTypes = {
- title: PropTypes.node,
- description: PropTypes.node.isRequired
-};
diff --git a/webapp/components/admin_console/boolean_setting.jsx b/webapp/components/admin_console/boolean_setting.jsx
deleted file mode 100644
index 45c23c869..000000000
--- a/webapp/components/admin_console/boolean_setting.jsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import Setting from './setting.jsx';
-
-import {FormattedMessage} from 'react-intl';
-
-import * as Utils from 'utils/utils.jsx';
-
-export default class BooleanSetting extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- }
-
- handleChange(e) {
- this.props.onChange(this.props.id, e.target.value === 'true');
- }
-
- render() {
- let helpText;
- if (this.props.disabled && this.props.disabledText) {
- helpText = (
- <div>
- <span className='admin-console__disabled-text'>
- {this.props.disabledText}
- </span>
- {this.props.helpText}
- </div>
- );
- } else {
- helpText = this.props.helpText;
- }
-
- return (
- <Setting
- label={this.props.label}
- helpText={helpText}
- >
- <label className='radio-inline'>
- <input
- type='radio'
- value='true'
- id={Utils.createSafeId(this.props.id) + 'true'}
- name={this.props.id}
- checked={this.props.value}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- {this.props.trueText}
- </label>
- <label className='radio-inline'>
- <input
- type='radio'
- value='false'
- id={Utils.createSafeId(this.props.id) + 'false'}
- name={this.props.id}
- checked={!this.props.value}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- {this.props.falseText}
- </label>
- </Setting>
- );
- }
-}
-BooleanSetting.defaultProps = {
- trueText: (
- <FormattedMessage
- id='admin.true'
- defaultMessage='true'
- />
- ),
- falseText: (
- <FormattedMessage
- id='admin.false'
- defaultMessage='false'
- />
- ),
- disabled: false
-};
-
-BooleanSetting.propTypes = {
- id: PropTypes.string.isRequired,
- label: PropTypes.node.isRequired,
- value: PropTypes.bool.isRequired,
- onChange: PropTypes.func.isRequired,
- trueText: PropTypes.node,
- falseText: PropTypes.node,
- disabled: PropTypes.bool.isRequired,
- disabledText: PropTypes.node,
- helpText: PropTypes.node.isRequired
-};
diff --git a/webapp/components/admin_console/brand_image_setting.jsx b/webapp/components/admin_console/brand_image_setting.jsx
deleted file mode 100644
index d2eae3f6e..000000000
--- a/webapp/components/admin_console/brand_image_setting.jsx
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import {Client4} from 'mattermost-redux/client';
-import * as Utils from 'utils/utils.jsx';
-import {uploadBrandImage} from 'actions/admin_actions.jsx';
-
-import FormError from 'components/form_error.jsx';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-
-const HTTP_STATUS_OK = 200;
-
-export default class BrandImageSetting extends React.PureComponent {
- static propTypes = {
-
- /*
- * Set to disable the setting
- */
- disabled: PropTypes.bool.isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.handleImageChange = this.handleImageChange.bind(this);
- this.handleImageSubmit = this.handleImageSubmit.bind(this);
-
- this.state = {
- brandImage: null,
- brandImageExists: false,
- brandImageTimestamp: Date.now(),
- uploading: false,
- uploadCompleted: false,
- error: ''
- };
- }
-
- componentWillMount() {
- fetch(Client4.getBrandImageUrl(this.state.brandImageTimestamp)).then(
- (resp) => {
- if (resp.status === HTTP_STATUS_OK) {
- this.setState({brandImageExists: true});
- } else {
- this.setState({brandImageExists: false});
- }
- }
- );
- }
-
- componentDidUpdate() {
- if (this.refs.image) {
- const reader = new FileReader();
-
- const img = this.refs.image;
- reader.onload = (e) => {
- $(img).attr('src', e.target.result);
- };
-
- reader.readAsDataURL(this.state.brandImage);
- }
- }
-
- handleImageChange() {
- const element = $(this.refs.fileInput);
-
- if (element.prop('files').length > 0) {
- this.setState({
- brandImage: element.prop('files')[0]
- });
- }
- }
-
- handleImageSubmit(e) {
- e.preventDefault();
-
- if (!this.state.brandImage) {
- return;
- }
-
- if (this.state.uploading) {
- return;
- }
-
- $(this.refs.upload).button('loading');
-
- this.setState({
- uploading: true,
- error: ''
- });
-
- uploadBrandImage(
- this.state.brandImage,
- () => {
- $(this.refs.upload).button('complete');
-
- this.setState({
- brandImageExists: true,
- brandImage: null,
- brandImageTimestamp: Date.now(),
- uploading: false
- });
- },
- (err) => {
- $(this.refs.upload).button('reset');
-
- this.setState({
- uploading: false,
- error: err.message
- });
- }
- );
- }
-
- render() {
- let btnPrimaryClass = 'btn';
- if (this.state.brandImage) {
- btnPrimaryClass += ' btn-primary';
- }
-
- let letbtnDefaultClass = 'btn';
- if (!this.props.disabled) {
- letbtnDefaultClass += ' btn-default';
- }
-
- let img = null;
- if (this.state.brandImage) {
- img = (
- <img
- ref='image'
- className='brand-img'
- src=''
- />
- );
- } else if (this.state.brandImageExists) {
- img = (
- <img
- className='brand-img'
- src={Client4.getBrandImageUrl(this.state.brandImageTimestamp)}
- />
- );
- } else {
- img = (
- <p>
- <FormattedMessage
- id='admin.team.noBrandImage'
- defaultMessage='No brand image uploaded'
- />
- </p>
- );
- }
-
- return (
- <div className='form-group'>
- <label className='control-label col-sm-4'>
- <FormattedMessage
- id='admin.team.brandImageTitle'
- defaultMessage='Custom Brand Image:'
- />
- </label>
- <div className='col-sm-8'>
- {img}
- </div>
- <div className='col-sm-4'/>
- <div className='col-sm-8'>
- <div className='file__upload'>
- <button
- className={letbtnDefaultClass}
- disabled={this.props.disabled}
- >
- <FormattedMessage
- id='admin.team.chooseImage'
- defaultMessage='Choose New Image'
- />
- </button>
- <input
- ref='fileInput'
- type='file'
- accept='.jpg,.png,.bmp'
- disabled={this.props.disabled}
- onChange={this.handleImageChange}
- />
- </div>
- <button
- className={btnPrimaryClass}
- disabled={this.props.disabled || !this.state.brandImage}
- onClick={this.handleImageSubmit}
- id='upload-button'
- ref='upload'
- data-loading-text={'<span class=\'fa fa-refresh fa-rotate\'></span> ' + Utils.localizeMessage('admin.team.uploading', 'Uploading..')}
- data-complete-text={'<span class=\'fa fa-check\'></span> ' + Utils.localizeMessage('admin.team.uploaded', 'Uploaded!')}
- >
- <FormattedMessage
- id='admin.team.upload'
- defaultMessage='Upload'
- />
- </button>
- <br/>
- <FormError error={this.state.error}/>
- <p className='help-text no-margin'>
- <FormattedHTMLMessage
- id='admin.team.uploadDesc'
- defaultMessage='Customize your user experience by adding a custom image to your login screen. See examples at <a href="http://docs.mattermost.com/administration/config-settings.html#custom-branding" target="_blank">docs.mattermost.com/administration/config-settings.html#custom-branding</a>.'
- />
- </p>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/client_versions_settings.jsx b/webapp/components/admin_console/client_versions_settings.jsx
deleted file mode 100644
index 0c9a5f58a..000000000
--- a/webapp/components/admin_console/client_versions_settings.jsx
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class ClientVersionsSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ClientRequirements.AndroidLatestVersion = this.state.androidLatestVersion;
- config.ClientRequirements.AndroidMinVersion = this.state.androidMinVersion;
- config.ClientRequirements.DesktopLatestVersion = this.state.desktopLatestVersion;
- config.ClientRequirements.DesktopMinVersion = this.state.desktopMinVersion;
- config.ClientRequirements.IosLatestVersion = this.state.iosLatestVersion;
- config.ClientRequirements.IosMinVersion = this.state.iosMinVersion;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- androidLatestVersion: config.ClientRequirements.AndroidLatestVersion,
- androidMinVersion: config.ClientRequirements.AndroidMinVersion,
- desktopLatestVersion: config.ClientRequirements.DesktopLatestVersion,
- desktopMinVersion: config.ClientRequirements.DesktopMinVersion,
- iosLatestVersion: config.ClientRequirements.IosLatestVersion,
- iosMinVersion: config.ClientRequirements.IosMinVersion
- };
- }
-
- renderTitle() {
- return (
- <h3>
- <FormattedMessage
- id='admin.security.client_versions'
- defaultMessage='Client Versions'
- />
- </h3>
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <TextSetting
- id='androidLatestVersion'
- label={
- <FormattedMessage
- id='admin.client_versions.androidLatestVersion'
- defaultMessage='Latest Android Version'
- />
- }
- placeholder={Utils.localizeMessage('admin.client_versions.androidLatestVersion', 'X.X.X')}
- helpText={
- <FormattedMessage
- id='admin.client_versions.androidLatestVersionHelp'
- defaultMessage='The latest released Android version'
- />
- }
- value={this.state.androidLatestVersion}
- onChange={this.handleChange}
- />
- <TextSetting
- id='androidMinVersion'
- label={
- <FormattedMessage
- id='admin.client_versions.androidMinVersion'
- defaultMessage='Minimum Android Version'
- />
- }
- placeholder={Utils.localizeMessage('admin.client_versions.androidMinVersion', 'X.X.X')}
- helpText={
- <FormattedMessage
- id='admin.client_versions.androidMinVersionHelp'
- defaultMessage='The minimum compliant Android version'
- />
- }
- value={this.state.androidMinVersion}
- onChange={this.handleChange}
- />
- <TextSetting
- id='desktopLatestVersion'
- label={
- <FormattedMessage
- id='admin.client_versions.desktopLatestVersion'
- defaultMessage='Latest Desktop Version'
- />
- }
- placeholder={Utils.localizeMessage('admin.client_versions.desktopLatestVersion', 'X.X.X')}
- helpText={
- <FormattedMessage
- id='admin.client_versions.desktopLatestVersionHelp'
- defaultMessage='The latest released Desktop version'
- />
- }
- value={this.state.desktopLatestVersion}
- onChange={this.handleChange}
- />
- <TextSetting
- id='desktopMinVersion'
- label={
- <FormattedMessage
- id='admin.client_versions.desktopMinVersion'
- defaultMessage='Minimum Destop Version'
- />
- }
- placeholder={Utils.localizeMessage('admin.client_versions.desktopMinVersion', 'X.X.X')}
- helpText={
- <FormattedMessage
- id='admin.client_versions.desktopMinVersionHelp'
- defaultMessage='The minimum compliant Desktop version'
- />
- }
- value={this.state.desktopMinVersion}
- onChange={this.handleChange}
- />
- <TextSetting
- id='iosLatestVersion'
- label={
- <FormattedMessage
- id='admin.client_versions.iosLatestVersion'
- defaultMessage='Latest IOS Version'
- />
- }
- placeholder={Utils.localizeMessage('admin.client_versions.iosLatestVersion', 'X.X.X')}
- helpText={
- <FormattedMessage
- id='admin.client_versions.iosLatestVersionHelp'
- defaultMessage='The latest released IOS version'
- />
- }
- value={this.state.iosLatestVersion}
- onChange={this.handleChange}
- />
- <TextSetting
- id='iosMinVersion'
- label={
- <FormattedMessage
- id='admin.client_versions.iosMinVersion'
- defaultMessage='Minimum IOS Version'
- />
- }
- placeholder={Utils.localizeMessage('admin.client_versions.iosMinVersion', 'X.X.X')}
- helpText={
- <FormattedMessage
- id='admin.client_versions.iosMinVersionHelp'
- defaultMessage='The minimum compliant IOS version'
- />
- }
- value={this.state.iosMinVersion}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/cluster_settings.jsx b/webapp/components/admin_console/cluster_settings.jsx
deleted file mode 100644
index 36f86f0ef..000000000
--- a/webapp/components/admin_console/cluster_settings.jsx
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import TextSetting from './text_setting.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import ClusterTableContainer from './cluster_table_container.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import {Client4} from 'mattermost-redux/client';
-
-export default class ClusterSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
- this.renderSettings = this.renderSettings.bind(this);
- this.overrideHandleChange = this.overrideHandleChange.bind(this);
- }
-
- getConfigFromState(config) {
- config.ClusterSettings.Enable = this.state.Enable;
- config.ClusterSettings.ClusterName = this.state.ClusterName;
- config.ClusterSettings.OverrideHostname = this.state.OverrideHostname;
- config.ClusterSettings.UseIpAddress = this.state.UseIpAddress;
- config.ClusterSettings.UseExperimentalGossip = this.state.UseExperimentalGossip;
- config.ClusterSettings.ReadOnlyConfig = this.state.ReadOnlyConfig;
- config.ClusterSettings.GossipPort = this.parseIntNonZero(this.state.GossipPort, 8074);
- config.ClusterSettings.StreamingPort = this.parseIntNonZero(this.state.StreamingPort, 8075);
- return config;
- }
-
- getStateFromConfig(config) {
- const settings = config.ClusterSettings;
-
- return {
- Enable: settings.Enable,
- ClusterName: settings.ClusterName,
- OverrideHostname: settings.OverrideHostname,
- UseIpAddress: settings.UseIpAddress,
- UseExperimentalGossip: settings.UseExperimentalGossip,
- ReadOnlyConfig: settings.ReadOnlyConfig,
- GossipPort: settings.GossipPort,
- StreamingPort: settings.StreamingPort,
- showWarning: false
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.advance.cluster'
- defaultMessage='High Availability'
- />
- );
- }
-
- overrideHandleChange(id, value) {
- this.setState({
- showWarning: true
- });
-
- this.handleChange(id, value);
- }
-
- renderSettings() {
- const licenseEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.Cluster === 'true';
- if (!licenseEnabled) {
- return null;
- }
-
- var configLoadedFromCluster = null;
-
- if (Client4.clusterId) {
- configLoadedFromCluster = (
- <div
- style={{marginBottom: '10px'}}
- className='alert alert-warning'
- >
- <i className='fa fa-warning'/>
- <FormattedHTMLMessage
- id='admin.cluster.loadedFrom'
- defaultMessage='This configuration file was loaded from Node ID {clusterId}. Please see the Troubleshooting Guide in our <a href="http://docs.mattermost.com/deployment/cluster.html" target="_blank">documentation</a> if you are accessing the System Console through a load balancer and experiencing issues.'
- values={{
- clusterId: Client4.clusterId
- }}
- />
- </div>
- );
- }
-
- var warning = null;
- if (this.state.showWarning) {
- warning = (
- <div
- style={{marginBottom: '10px'}}
- className='alert alert-warning'
- >
- <i className='fa fa-warning'/>
- <FormattedHTMLMessage
- id='admin.cluster.should_not_change'
- defaultMessage='WARNING: These settings may not sync with the other servers in the cluster. High Availability inter-node communication will not start until you modify the config.json to be identical on all servers and restart Mattermost. Please see the <a href="http://docs.mattermost.com/deployment/cluster.html" target="_blank">documentation</a> on how to add or remove a server from the cluster. If you are accessing the System Console through a load balancer and experiencing issues, please see the Troubleshooting Guide in our <a href="http://docs.mattermost.com/deployment/cluster.html" target="_blank">documentation</a>.'
- />
- </div>
- );
- }
-
- var clusterTableContainer = null;
- if (this.state.Enable) {
- clusterTableContainer = (<ClusterTableContainer/>);
- }
-
- return (
- <SettingsGroup>
- {configLoadedFromCluster}
- {clusterTableContainer}
- <div className='banner'>
- <FormattedMessage
- id='admin.cluster.noteDescription'
- defaultMessage='Changing properties in this section will require a server restart before taking effect. When High Availability mode is enabled, the System Console is set to read-only and can only be changed from the configuration file unless ReadOnlyConfig is disabled in the configuration file.'
- />
- </div>
- {warning}
- <BooleanSetting
- id='Enable'
- label={
- <FormattedMessage
- id='admin.cluster.enableTitle'
- defaultMessage='Enable High Availability Mode:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.cluster.enableDescription'
- defaultMessage='When true, Mattermost will run in High Availability mode. Please see <a href="http://docs.mattermost.com/deployment/cluster.html" target="_blank">documentation</a> to learn more about configuring High Availability for Mattermost.'
- />
- }
- value={this.state.Enable}
- onChange={this.overrideHandleChange}
- />
- <TextSetting
- id='ClusterName'
- label={
- <FormattedMessage
- id='admin.cluster.ClusterName'
- defaultMessage='Cluster Name:'
- />
- }
- placeholder={Utils.localizeMessage('admin.cluster.ClusterNameEx', 'Ex "Production" or "Staging"')}
- helpText={
- <FormattedMessage
- id='admin.cluster.ClusterNameDesc'
- defaultMessage='The cluster to join by name. Only nodes with the same cluster name will join together. This is to support Blue-Green deployments or staging pointing to the same database.'
- />
- }
- value={this.state.ClusterName}
- onChange={this.overrideHandleChange}
- />
- <TextSetting
- id='OverrideHostname'
- label={
- <FormattedMessage
- id='admin.cluster.OverrideHostname'
- defaultMessage='Override Hostname:'
- />
- }
- placeholder={Utils.localizeMessage('admin.cluster.OverrideHostnameEx', 'Ex "app-server-01"')}
- helpText={
- <FormattedMessage
- id='admin.cluster.OverrideHostnameDesc'
- defaultMessage='The default value of <blank> will attempt to get the Hostname from the OS or use the IP Address. You can override the hostname of this server with this property. It is not recommended to override the Hostname unless needed. This property can also be set to a specific IP Address if needed.'
- />
- }
- value={this.state.OverrideHostname}
- onChange={this.overrideHandleChange}
- />
- <BooleanSetting
- id='UseIpAddress'
- label={
- <FormattedMessage
- id='admin.cluster.UseIpAddress'
- defaultMessage='Use IP Address:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.cluster.UseIpAddressDesc'
- defaultMessage='When true, the cluster will attempt to communicate via IP Address vs using the hostname.'
- />
- }
- value={this.state.UseIpAddress}
- onChange={this.overrideHandleChange}
- />
- <BooleanSetting
- id='UseExperimentalGossip'
- label={
- <FormattedMessage
- id='admin.cluster.UseExperimentalGossip'
- defaultMessage='Use Experimental Gossip:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.cluster.UseExperimentalGossipDesc'
- defaultMessage='When true, the server will attempt to communicate via the gossip protocol over the gossip port. When false the server will attempt to communicate over the streaming port. When false the gossip port and protocol are still used to determine cluster health.'
- />
- }
- value={this.state.UseExperimentalGossip}
- onChange={this.overrideHandleChange}
- />
- <BooleanSetting
- id='ReadOnlyConfig'
- label={
- <FormattedMessage
- id='admin.cluster.ReadOnlyConfig'
- defaultMessage='Read Only Config:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.cluster.ReadOnlyConfigDesc'
- defaultMessage='When true, the server will reject changes made to the configuration file from the system console. When running in production it is recommened to set this to true.'
- />
- }
- value={this.state.ReadOnlyConfig}
- onChange={this.overrideHandleChange}
- />
- <TextSetting
- id='GossipPort'
- label={
- <FormattedMessage
- id='admin.cluster.GossipPort'
- defaultMessage='Gossip Port:'
- />
- }
- placeholder={Utils.localizeMessage('admin.cluster.GossipPortEx', 'Ex "8074"')}
- helpText={
- <FormattedMessage
- id='admin.cluster.GossipPortDesc'
- defaultMessage='The port used for the gossip protocol. Both UDP and TCP should abe allowed on this port.'
- />
- }
- value={this.state.GossipPort}
- onChange={this.overrideHandleChange}
- />
- <TextSetting
- id='StreamingPort'
- label={
- <FormattedMessage
- id='admin.cluster.StreamingPort'
- defaultMessage='Streaming Port:'
- />
- }
- placeholder={Utils.localizeMessage('admin.cluster.StreamingPortEx', 'Ex "8075"')}
- helpText={
- <FormattedMessage
- id='admin.cluster.StreamingPortDesc'
- defaultMessage='The port used for streaming data between servers.'
- />
- }
- value={this.state.StreamingPort}
- onChange={this.overrideHandleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/cluster_table.jsx b/webapp/components/admin_console/cluster_table.jsx
deleted file mode 100644
index e7157635d..000000000
--- a/webapp/components/admin_console/cluster_table.jsx
+++ /dev/null
@@ -1,172 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {FormattedMessage} from 'react-intl';
-import * as Utils from 'utils/utils.jsx';
-
-import statusGreen from 'images/status_green.png';
-import statusYellow from 'images/status_yellow.png';
-
-export default class ClusterTable extends React.Component {
- static propTypes = {
- clusterInfos: PropTypes.array.isRequired,
- reload: PropTypes.func.isRequired
- }
-
- render() {
- var versionMismatch = (
- <img
- className='cluster-status'
- src={statusGreen}
- />
- );
-
- var configMismatch = (
- <img
- className='cluster-status'
- src={statusGreen}
- />
- );
-
- var version = '';
- var configHash = '';
- var singleItem = false;
-
- if (this.props.clusterInfos.length) {
- version = this.props.clusterInfos[0].version;
- configHash = this.props.clusterInfos[0].config_hash;
- singleItem = this.props.clusterInfos.length === 1;
- }
-
- this.props.clusterInfos.map((clusterInfo) => {
- if (clusterInfo.version !== version) {
- versionMismatch = (
- <img
- className='cluster-status'
- src={statusYellow}
- />
- );
- }
-
- if (clusterInfo.config_hash !== configHash) {
- configMismatch = (
- <img
- className='cluster-status'
- src={statusYellow}
- />
- );
- }
-
- return null;
- });
-
- var items = this.props.clusterInfos.map((clusterInfo) => {
- var status = null;
-
- if (clusterInfo.hostname === '') {
- clusterInfo.hostname = Utils.localizeMessage('admin.cluster.unknown', 'unknown');
- }
-
- if (clusterInfo.version === '') {
- clusterInfo.version = Utils.localizeMessage('admin.cluster.unknown', 'unknown');
- }
-
- if (clusterInfo.config_hash === '') {
- clusterInfo.config_hash = Utils.localizeMessage('admin.cluster.unknown', 'unknown');
- }
-
- if (singleItem) {
- status = (
- <img
- className='cluster-status'
- src={statusYellow}
- />
- );
- } else {
- status = (
- <img
- className='cluster-status'
- src={statusGreen}
- />
- );
- }
-
- return (
- <tr key={clusterInfo.ipaddress}>
- <td style={{whiteSpace: 'nowrap'}}>{status}</td>
- <td style={{whiteSpace: 'nowrap'}}>{clusterInfo.hostname}</td>
- <td style={{whiteSpace: 'nowrap'}}>{versionMismatch} {clusterInfo.version}</td>
- <td style={{whiteSpace: 'nowrap'}}><div className='config-hash'>{configMismatch} {clusterInfo.config_hash}</div></td>
- <td style={{whiteSpace: 'nowrap'}}>{clusterInfo.ipaddress}</td>
- </tr>
- );
- });
-
- return (
- <div
- className='cluster-panel__table'
- style={{
- margin: '10px',
- marginBottom: '30px'
- }}
- >
- <div className='text-right'>
- <button
- type='submit'
- className='btn btn-link'
- onClick={this.props.reload}
- >
- <i className='fa fa-refresh'/>
- <FormattedMessage
- id='admin.cluster.status_table.reload'
- defaultMessage=' Reload Cluster Status'
- />
- </button>
- </div>
- <table className='table'>
- <thead>
- <tr>
- <th>
- <FormattedMessage
- id='admin.cluster.status_table.status'
- defaultMessage='Status'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.cluster.status_table.hostname'
- defaultMessage='Hostname'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.cluster.status_table.version'
- defaultMessage='Version'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.cluster.status_table.config_hash'
- defaultMessage='Config File MD5'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.cluster.status_table.url'
- defaultMessage='Gossip Address'
- />
- </th>
- </tr>
- </thead>
- <tbody>
- {items}
- </tbody>
- </table>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/cluster_table_container.jsx b/webapp/components/admin_console/cluster_table_container.jsx
deleted file mode 100644
index 7a67bb842..000000000
--- a/webapp/components/admin_console/cluster_table_container.jsx
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import ClusterTable from './cluster_table.jsx';
-import LoadingScreen from '../loading_screen.jsx';
-
-import {getClusterStatus} from 'actions/admin_actions.jsx';
-
-export default class ClusterTableContainer extends React.Component {
- constructor(props) {
- super(props);
-
- this.load = this.load.bind(this);
- this.reload = this.reload.bind(this);
-
- this.interval = null;
-
- this.state = {
- clusterInfos: null
- };
- }
-
- load() {
- getClusterStatus(
- (data) => {
- this.setState({
- clusterInfos: data
- });
- },
- null
- );
- }
-
- componentWillMount() {
- this.load();
-
- // reload the cluster status every 15 seconds
- this.interval = setInterval(this.load, 15000);
- }
-
- componentWillUnmount() {
- if (this.interval) {
- clearInterval(this.interval);
- }
- }
-
- reload(e) {
- if (e) {
- e.preventDefault();
- }
-
- this.setState({
- clusterInfos: null
- });
-
- this.load();
- }
-
- render() {
- if (this.state.clusterInfos == null) {
- return (<LoadingScreen/>);
- }
-
- return (
- <ClusterTable
- clusterInfos={this.state.clusterInfos}
- reload={this.reload}
- />
- );
- }
-}
diff --git a/webapp/components/admin_console/color_setting.jsx b/webapp/components/admin_console/color_setting.jsx
deleted file mode 100644
index 483b585ee..000000000
--- a/webapp/components/admin_console/color_setting.jsx
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import Setting from './setting.jsx';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {ChromePicker} from 'react-color';
-
-export default class ColorSetting extends React.PureComponent {
- static propTypes = {
-
- /*
- * The unique identifer for the admin console setting
- */
- id: PropTypes.string.isRequired,
-
- /*
- * The text/jsx display name for the setting
- */
- label: PropTypes.node.isRequired,
-
- /*
- * The text/jsx help text to display underneath the setting
- */
- helpText: PropTypes.node,
-
- /*
- * The hex color value
- */
- value: PropTypes.string.isRequired,
-
- /*
- * Function called when the input changes
- */
- onChange: PropTypes.func,
-
- /*
- * Set to disable the setting
- */
- disabled: PropTypes.bool
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- showPicker: false
- };
- }
-
- componentDidMount() {
- document.addEventListener('click', this.closePicker);
- }
-
- componentWillUnmount() {
- document.removeEventListener('click', this.closePicker);
- }
-
- handleChange = (color) => {
- this.props.onChange(this.props.id, color.hex);
- }
-
- togglePicker = () => {
- if (this.props.disabled) {
- this.setState({showPicker: false});
- }
- this.setState({showPicker: !this.state.showPicker});
- }
-
- closePicker = (e) => {
- if (!e.target.closest('.picker-' + this.props.id)) {
- this.setState({showPicker: false});
- }
- }
-
- onTextInput = (e) => {
- this.props.onChange(this.props.id, e.target.value);
- }
-
- render() {
- let picker;
- if (this.state.showPicker) {
- picker = (
- <div className={'color-picker__popover picker-' + this.props.id}>
- <ChromePicker
- color={this.props.value}
- onChange={this.handleChange}
- />
- </div>
- );
- }
-
- return (
- <Setting
- label={this.props.label}
- helpText={this.props.helpText}
- inputId={this.props.id}
- >
- <div className='input-group color-picker colorpicker-element'>
- <input
- type='text'
- className='form-control'
- value={this.props.value}
- onChange={this.onTextInput}
- disabled={this.props.disabled}
- />
- <span
- className={'input-group-addon picker-' + this.props.id}
- onClick={this.togglePicker}
- >
- <i style={{backgroundColor: this.props.value}}/>
- </span>
- {picker}
- </div>
- </Setting>
- );
- }
-}
diff --git a/webapp/components/admin_console/compliance_reports/compliance_reports.jsx b/webapp/components/admin_console/compliance_reports/compliance_reports.jsx
deleted file mode 100644
index af361bace..000000000
--- a/webapp/components/admin_console/compliance_reports/compliance_reports.jsx
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import LoadingScreen from 'components/loading_screen.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-import UserStore from 'stores/user_store.jsx';
-import {Client4} from 'mattermost-redux/client';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage, FormattedDate, FormattedTime} from 'react-intl';
-
-export default class ComplianceReports extends React.PureComponent {
- static propTypes = {
-
- /*
- * Set if compliance reports are enabled in the config
- */
- enabled: PropTypes.bool.isRequired,
-
- /*
- * Array of reports to render
- */
- reports: PropTypes.arrayOf(PropTypes.object).isRequired,
-
- /*
- * Error message to display
- */
- serverError: PropTypes.string,
-
- actions: PropTypes.shape({
-
- /*
- * Function to get compliance reports
- */
- getComplianceReports: PropTypes.func.isRequired,
-
- /*
- * Function to save compliance reports
- */
- createComplianceReport: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- loadingReports: true
- };
- }
-
- componentDidMount() {
- if (global.window.mm_license.IsLicensed !== 'true' || !this.props.enabled) {
- return;
- }
-
- this.props.actions.getComplianceReports().then(
- () => this.setState({loadingReports: false})
- );
- }
-
- reload = () => {
- this.setState({loadingReports: true});
-
- this.props.actions.getComplianceReports().then(
- () => this.setState({loadingReports: false})
- );
- }
-
- runReport = (e) => {
- e.preventDefault();
-
- this.setState({runningReport: true});
-
- const job = {};
- job.desc = this.refs.desc.value;
- job.emails = this.refs.emails.value;
- job.keywords = this.refs.keywords.value;
- job.start_at = Date.parse(this.refs.from.value);
- job.end_at = Date.parse(this.refs.to.value);
-
- this.props.actions.createComplianceReport(job).then(
- (data) => {
- if (data) {
- this.refs.emails.value = '';
- this.refs.keywords.value = '';
- this.refs.desc.value = '';
- this.refs.from.value = '';
- this.refs.to.value = '';
- }
- this.setState({runningReport: false});
- }
- );
- }
-
- getDateTime(millis) {
- const date = new Date(millis);
- return (
- <span style={{whiteSpace: 'nowrap'}}>
- <FormattedDate
- value={date}
- day='2-digit'
- month='short'
- year='numeric'
- />
- {' - '}
- <FormattedTime
- value={date}
- hour='2-digit'
- minute='2-digit'
- />
- </span>
- );
- }
-
- render() {
- if (global.window.mm_license.IsLicensed !== 'true' || !this.props.enabled) {
- return <div/>;
- }
-
- let content = null;
- if (this.state.loadingReports) {
- content = <LoadingScreen/>;
- } else {
- var list = [];
-
- for (var i = 0; i < this.props.reports.length; i++) {
- const report = this.props.reports[i];
-
- let params = '';
- if (report.type === 'adhoc') {
- params = (
- <span>
- <FormattedMessage
- id='admin.compliance_reports.from'
- defaultMessage='From:'
- />{' '}{this.getDateTime(report.start_at)}
- <br/>
- <FormattedMessage
- id='admin.compliance_reports.to'
- defaultMessage='To:'
- />{' '}{this.getDateTime(report.end_at)}
- <br/>
- <FormattedMessage
- id='admin.compliance_reports.emails'
- defaultMessage='Emails:'
- />{' '}{report.emails}
- <br/>
- <FormattedMessage
- id='admin.compliance_reports.keywords'
- defaultMessage='Keywords:'
- />{' '}{report.keywords}
- </span>);
- }
-
- let download = '';
- if (report.status === 'finished') {
- download = (
- <a href={`${Client4.getBaseRoute()}/compliance/reports/${report.id}/download`}>
- <FormattedMessage
- id='admin.compliance_table.download'
- defaultMessage='Download'
- />
- </a>
- );
- }
-
- let status = report.status;
- if (report.status === 'finished') {
- status = (
- <span style={{color: 'green'}}>{report.status}</span>
- );
- }
-
- if (report.status === 'failed') {
- status = (
- <span style={{color: 'red'}}>{report.status}</span>
- );
- }
-
- let user = report.user_id;
- const profile = UserStore.getProfile(report.user_id);
- if (profile) {
- user = profile.email;
- }
-
- list[i] = (
- <tr key={report.id}>
- <td style={{whiteSpace: 'nowrap'}}>{download}</td>
- <td>{this.getDateTime(report.create_at)}</td>
- <td>{status}</td>
- <td>{report.count}</td>
- <td>{report.type}</td>
- <td style={{whiteSpace: 'nowrap'}}>{report.desc}</td>
- <td>{user}</td>
- <td style={{whiteSpace: 'nowrap'}}>{params}</td>
- </tr>
- );
- }
-
- content = (
- <div style={{margin: '10px'}}>
- <table className='table'>
- <thead>
- <tr>
- <th/>
- <th>
- <FormattedMessage
- id='admin.compliance_table.timestamp'
- defaultMessage='Timestamp'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.compliance_table.status'
- defaultMessage='Status'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.compliance_table.records'
- defaultMessage='Records'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.compliance_table.type'
- defaultMessage='Type'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.compliance_table.desc'
- defaultMessage='Description'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.compliance_table.userId'
- defaultMessage='Requested By'
- />
- </th>
- <th>
- <FormattedMessage
- id='admin.compliance_table.params'
- defaultMessage='Params'
- />
- </th>
- </tr>
- </thead>
- <tbody>
- {list}
- </tbody>
- </table>
- </div>
- );
- }
-
- let serverError = '';
- if (this.props.serverError) {
- serverError = (
- <div
- className='form-group has-error'
- style={{marginTop: '10px'}}
- >
- <label className='control-label'>{this.props.serverError}</label>
- </div>
- );
- }
-
- return (
- <div className='panel compliance-panel'>
- <h3>
- <FormattedMessage
- id='admin.compliance_reports.title'
- defaultMessage='Compliance Reports'
- />
- </h3>
- <div className='row'>
- <div className='col-sm-6 col-md-4 form-group'>
- <label>
- <FormattedMessage
- id='admin.compliance_reports.desc'
- defaultMessage='Job Name:'
- />
- </label>
- <input
- type='text'
- className='form-control'
- id='desc'
- ref='desc'
- placeholder={Utils.localizeMessage('admin.compliance_reports.desc_placeholder', 'E.g. "Audit 445 for HR"')}
- />
- </div>
- <div className='col-sm-3 col-md-2 form-group'>
- <label>
- <FormattedMessage
- id='admin.compliance_reports.from'
- defaultMessage='From:'
- />
- </label>
- <input
- type='text'
- className='form-control'
- id='from'
- ref='from'
- placeholder={Utils.localizeMessage('admin.compliance_reports.from_placeholder', 'E.g. "2016-03-11"')}
- />
- </div>
- <div className='col-sm-3 col-md-2 form-group'>
- <label>
- <FormattedMessage
- id='admin.compliance_reports.to'
- defaultMessage='To:'
- />
- </label>
- <input
- type='text'
- className='form-control'
- id='to'
- ref='to'
- placeholder={Utils.localizeMessage('admin.compliance_reports.to_placeholder', 'E.g. "2016-03-15"')}
- />
- </div>
- </div>
- <div className='row'>
- <div className='col-sm-6 col-md-4 form-group'>
- <label>
- <FormattedMessage
- id='admin.compliance_reports.emails'
- defaultMessage='Emails:'
- />
- </label>
- <input
- type='text'
- className='form-control'
- id='emails'
- ref='emails'
- placeholder={Utils.localizeMessage('admin.compliance_reports.emails_placeholder', 'E.g. "bill@example.com, bob@example.com"')}
- />
- </div>
- <div className='col-sm-6 col-md-4 form-group'>
- <label>
- <FormattedMessage
- id='admin.compliance_reports.keywords'
- defaultMessage='Keywords:'
- />
- </label>
- <input
- type='text'
- className='form-control'
- id='keywords'
- ref='keywords'
- placeholder={Utils.localizeMessage('admin.compliance_reports.keywords_placeholder', 'E.g. "shorting stock"')}
- />
- </div>
- </div>
- <div className='clearfix'>
- <button
- id='run-button'
- type='submit'
- className='btn btn-primary'
- onClick={this.runReport}
- >
- <FormattedMessage
- id='admin.compliance_reports.run'
- defaultMessage='Run Compliance Report'
- />
- </button>
- </div>
- {serverError}
- <div className='text-right'>
- <button
- type='submit'
- className='btn btn-link'
- disabled={this.state.runningReport}
- onClick={this.reload}
- >
- <i className='fa fa-refresh'/>
- <FormattedMessage
- id='admin.compliance_reports.reload'
- defaultMessage='Reload Completed Compliance Reports'
- />
- </button>
- </div>
- <div className='compliance-panel__table'>
- {content}
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/compliance_reports/index.js b/webapp/components/admin_console/compliance_reports/index.js
deleted file mode 100644
index 1cbf669e5..000000000
--- a/webapp/components/admin_console/compliance_reports/index.js
+++ /dev/null
@@ -1,46 +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 {getComplianceReports, createComplianceReport} from 'mattermost-redux/actions/admin';
-
-import {getComplianceReports as selectComplianceReports, getConfig} from 'mattermost-redux/selectors/entities/admin';
-
-import ComplianceReports from './compliance_reports.jsx';
-
-function mapStateToProps(state, ownProps) {
- let enabled = false;
- const config = getConfig(state);
- if (config && config.ComplianceSettings) {
- enabled = config.ComplianceSettings.Enable;
- }
-
- let serverError;
- const error = state.requests.admin.createCompliance.error;
- if (error) {
- serverError = error.message;
- }
-
- const reports = Object.values(selectComplianceReports(state)).sort((a, b) => {
- return b.create_at - a.create_at;
- });
-
- return {
- ...ownProps,
- enabled,
- reports,
- serverError
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getComplianceReports,
- createComplianceReport
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ComplianceReports);
diff --git a/webapp/components/admin_console/compliance_settings.jsx b/webapp/components/admin_console/compliance_settings.jsx
deleted file mode 100644
index 5521c6e39..000000000
--- a/webapp/components/admin_console/compliance_settings.jsx
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class ComplianceSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ComplianceSettings.Enable = this.state.enable;
- config.ComplianceSettings.Directory = this.state.directory;
- config.ComplianceSettings.EnableDaily = this.state.enableDaily;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enable: config.ComplianceSettings.Enable,
- directory: config.ComplianceSettings.Directory,
- enableDaily: config.ComplianceSettings.EnableDaily
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.compliance.title'
- defaultMessage='Compliance Settings'
- />
- );
- }
-
- renderSettings() {
- const licenseEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.Compliance === 'true';
-
- let bannerContent;
- if (!licenseEnabled) {
- bannerContent = (
- <div className='banner warning'>
- <div className='banner__content'>
- <FormattedHTMLMessage
- id='admin.compliance.noLicense'
- defaultMessage='<h4 class="banner__heading">Note:</h4><p>Compliance is an enterprise feature. Your current license does not support Compliance. Click <a href="http://mattermost.com"target="_blank">here</a> for information and pricing on enterprise licenses.</p>'
- />
- </div>
- </div>
- );
- }
-
- return (
- <SettingsGroup>
- {bannerContent}
- <BooleanSetting
- id='enable'
- label={
- <FormattedMessage
- id='admin.compliance.enableTitle'
- defaultMessage='Enable Compliance Reporting:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.compliance.enableDesc'
- defaultMessage='When true, Mattermost allows compliance reporting from the <strong>Compliance and Auditing</strong> tab. See <a href="https://docs.mattermost.com/administration/compliance.html" target="_blank">documentation</a> to learn more.'
- />
- }
- value={this.state.enable}
- onChange={this.handleChange}
- disabled={!licenseEnabled}
- />
- <TextSetting
- id='directory'
- label={
- <FormattedMessage
- id='admin.compliance.directoryTitle'
- defaultMessage='Compliance Report Directory:'
- />
- }
- placeholder={Utils.localizeMessage('admin.sql.maxOpenExample', 'Ex "10"')}
- helpText={
- <FormattedMessage
- id='admin.compliance.directoryDescription'
- defaultMessage='Directory to which compliance reports are written. If blank, will be set to ./data/.'
- />
- }
- value={this.state.directory}
- onChange={this.handleChange}
- disabled={!licenseEnabled || !this.state.enable}
- />
- <BooleanSetting
- id='enableDaily'
- label={
- <FormattedMessage
- id='admin.compliance.enableDailyTitle'
- defaultMessage='Enable Daily Report:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.compliance.enableDailyDesc'
- defaultMessage='When true, Mattermost will generate a daily compliance report.'
- />
- }
- value={this.state.enableDaily}
- onChange={this.handleChange}
- disabled={!licenseEnabled || !this.state.enable}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/configuration_settings.jsx b/webapp/components/admin_console/configuration_settings.jsx
deleted file mode 100644
index 6ac68a3bb..000000000
--- a/webapp/components/admin_console/configuration_settings.jsx
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-import ErrorStore from 'stores/error_store.jsx';
-
-import {ErrorBarTypes} from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import {invalidateAllCaches, reloadConfig} from 'actions/admin_actions.jsx';
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {ConnectionSecurityDropdownSettingWebserver} from './connection_security_dropdown_setting.jsx';
-import SettingsGroup from './settings_group.jsx';
-import RequestButton from './request_button/request_button';
-import TextSetting from './text_setting.jsx';
-import WebserverModeDropdownSetting from './webserver_mode_dropdown_setting.jsx';
-
-export default class ConfigurationSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.handleSaved = this.handleSaved.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- componentWillReceiveProps(nextProps) {
- // special case for this page since we don't update AdminSettings components when the
- // stored config changes, but we want this page to update when you reload the config
- this.setState(this.getStateFromConfig(nextProps.config));
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.SiteURL = this.state.siteURL;
- config.ServiceSettings.ListenAddress = this.state.listenAddress;
- config.ServiceSettings.WebserverMode = this.state.webserverMode;
- config.ServiceSettings.ConnectionSecurity = this.state.connectionSecurity;
- config.ServiceSettings.TLSCertFile = this.state.TLSCertFile;
- config.ServiceSettings.TLSKeyFile = this.state.TLSKeyFile;
- config.ServiceSettings.UseLetsEncrypt = this.state.useLetsEncrypt;
- config.ServiceSettings.LetsEncryptCertificateCacheFile = this.state.letsEncryptCertificateCacheFile;
- config.ServiceSettings.Forward80To443 = this.state.forward80To443;
- config.ServiceSettings.ReadTimeout = this.parseIntNonZero(this.state.readTimeout);
- config.ServiceSettings.WriteTimeout = this.parseIntNonZero(this.state.writeTimeout);
- config.ServiceSettings.EnableAPIv3 = this.state.enableAPIv3;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- siteURL: config.ServiceSettings.SiteURL,
- listenAddress: config.ServiceSettings.ListenAddress,
- webserverMode: config.ServiceSettings.WebserverMode,
- connectionSecurity: config.ServiceSettings.ConnectionSecurity,
- TLSCertFile: config.ServiceSettings.TLSCertFile,
- TLSKeyFile: config.ServiceSettings.TLSKeyFile,
- useLetsEncrypt: config.ServiceSettings.UseLetsEncrypt,
- letsEncryptCertificateCacheFile: config.ServiceSettings.LetsEncryptCertificateCacheFile,
- forward80To443: config.ServiceSettings.Forward80To443,
- readTimeout: config.ServiceSettings.ReadTimeout,
- writeTimeout: config.ServiceSettings.WriteTimeout,
- enableAPIv3: config.ServiceSettings.EnableAPIv3
- };
- }
-
- handleSaved(newConfig) {
- if (newConfig.ServiceSettings.SiteURL) {
- ErrorStore.clearError(ErrorBarTypes.SITE_URL);
- }
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.general.configuration'
- defaultMessage='Configuration'
- />
- );
- }
-
- renderSettings() {
- const reloadConfigurationHelpText = (
- <FormattedMessage
- id='admin.reload.reloadDescription'
- defaultMessage='Deployments using multiple databases can switch from one master database to another without restarting the Mattermost server by updating "config.json" to the new desired configuration and using the {featureName} feature to load the new settings while the server is running. The administrator should then use the {recycleDatabaseConnections} feature to recycle the database connections based on the new settings.'
- values={{
- featureName: (
- <b>
- <FormattedMessage
- id='admin.reload.reloadDescription.featureName'
- defaultMessage='Reload Configuration from Disk'
- />
- </b>
- ),
- recycleDatabaseConnections: (
- <a href='../advanced/database'>
- <b>
- <FormattedMessage
- id='admin.reload.reloadDescription.recycleDatabaseConnections'
- defaultMessage='Database > Recycle Database Connections'
- />
- </b>
- </a>
- )
- }}
- />
- );
-
- let reloadConfigButton = <div/>;
- if (global.window.mm_license.IsLicensed === 'true') {
- reloadConfigButton = (
- <RequestButton
- requestAction={reloadConfig}
- helpText={reloadConfigurationHelpText}
- buttonText={
- <FormattedMessage
- id='admin.reload.button'
- defaultMessage='Reload Configuration From Disk'
- />
- }
- showSuccessMessage={false}
- errorMessage={{
- id: 'admin.reload.reloadFail',
- defaultMessage: 'Reload unsuccessful: {error}'
- }}
- />
- );
- }
-
- return (
- <SettingsGroup>
- <div className='banner'>
- <div className='banner__content'>
- <FormattedMessage
- id='admin.rate.noteDescription'
- defaultMessage='Changing properties other than Site URL in this section will require a server restart before taking effect.'
- />
- </div>
- </div>
- <TextSetting
- id='siteURL'
- label={
- <FormattedMessage
- id='admin.service.siteURL'
- defaultMessage='Site URL:'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.siteURLExample', 'Ex "https://mattermost.example.com:1234"')}
- helpText={
- <FormattedMessage
- id='admin.service.siteURLDescription'
- defaultMessage='The URL that users will use to access Mattermost. Standard ports, such as 80 and 443, can be omitted, but non-standard ports are required. For example: http://mattermost.example.com:8065. This setting is required.'
- />
- }
- value={this.state.siteURL}
- onChange={this.handleChange}
- />
- <TextSetting
- id='listenAddress'
- label={
- <FormattedMessage
- id='admin.service.listenAddress'
- defaultMessage='Listen Address:'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.listenExample', 'Ex ":8065"')}
- helpText={
- <FormattedMessage
- id='admin.service.listenDescription'
- defaultMessage='The address and port to which to bind and listen. Specifying ":8065" will bind to all network interfaces. Specifying "127.0.0.1:8065" will only bind to the network interface having that IP address. If you choose a port of a lower level (called "system ports" or "well-known ports", in the range of 0-1023), you must have permissions to bind to that port. On Linux you can use: "sudo setcap cap_net_bind_service=+ep ./bin/platform" to allow Mattermost to bind to well-known ports.'
- />
- }
- value={this.state.listenAddress}
- onChange={this.handleChange}
- />
- <ConnectionSecurityDropdownSettingWebserver
- value={this.state.connectionSecurity}
- onChange={this.handleChange}
- disabled={false}
- />
- <TextSetting
- id='TLSCertFile'
- label={
- <FormattedMessage
- id='admin.service.tlsCertFile'
- defaultMessage='TLS Certificate File:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.tlsCertFileDescription'
- defaultMessage='The certificate file to use.'
- />
- }
- disabled={this.state.useLetsEncrypt}
- value={this.state.TLSCertFile}
- onChange={this.handleChange}
- />
- <TextSetting
- id='TLSKeyFile'
- label={
- <FormattedMessage
- id='admin.service.tlsKeyFile'
- defaultMessage='TLS Key File:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.tlsKeyFileDescription'
- defaultMessage='The private key file to use.'
- />
- }
- disabled={this.state.useLetsEncrypt}
- value={this.state.TLSKeyFile}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='useLetsEncrypt'
- label={
- <FormattedMessage
- id='admin.service.useLetsEncrypt'
- defaultMessage="Use Let's Encrypt:"
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.useLetsEncryptDescription'
- defaultMessage="Enable the automatic retreval of certificates from the Let's Encrypt. The certificate will be retrieved when a client attempts to connect from a new domain. This will work with multiple domains."
- />
- }
- value={this.state.useLetsEncrypt}
- onChange={this.handleChange}
- />
- <TextSetting
- id='letsEncryptCertificateCacheFile'
- label={
- <FormattedMessage
- id='admin.service.letsEncryptCertificateCacheFile'
- defaultMessage="Let's Encrypt Certificate Cache File:"
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.letsEncryptCertificateCacheFileDescription'
- defaultMessage="Certificates retrieved and other data about the Let's Encrypt service will be stored in this file."
- />
- }
- disabled={!this.state.useLetsEncrypt}
- value={this.state.letsEncryptCertificateCacheFile}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='forward80To443'
- label={
- <FormattedMessage
- id='admin.service.forward80To443'
- defaultMessage='Forward port 80 to 443:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.forward80To443Description'
- defaultMessage='Forwards all insecure traffic from port 80 to secure port 443'
- />
- }
- value={this.state.forward80To443}
- onChange={this.handleChange}
- />
- <TextSetting
- id='readTimeout'
- label={
- <FormattedMessage
- id='admin.service.readTimeout'
- defaultMessage='Read Timeout:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.readTimeoutDescription'
- defaultMessage='Maximum time allowed from when the connection is accepted to when the request body is fully read.'
- />
- }
- value={this.state.readTimeout}
- onChange={this.handleChange}
- />
- <TextSetting
- id='writeTimeout'
- label={
- <FormattedMessage
- id='admin.service.writeTimeout'
- defaultMessage='Write Timeout:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.writeTimeoutDescription'
- defaultMessage='If using HTTP (insecure), this is the maximum time allowed from the end of reading the request headers until the response is written. If using HTTPS, it is the total time from when the connection is accepted until the response is written.'
- />
- }
- value={this.state.writeTimeout}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableAPIv3'
- label={
- <FormattedMessage
- id='admin.service.enableAPIv3'
- defaultMessage='Allow use of API v3 endpoints:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.enableAPIv3Description'
- defaultMessage='Set to false to disable all version 3 endpoints of the REST API. Integrations that rely on API v3 will fail and can then be identified for migration to API v4. API v3 is deprecated and will be removed in the near future. See <a href="https://api.mattermost.com" target="_blank">https://api.mattermost.com</a> for details.'
- />
- }
- value={this.state.enableAPIv3}
- onChange={this.handleChange}
- />
- <WebserverModeDropdownSetting
- value={this.state.webserverMode}
- onChange={this.handleChange}
- disabled={false}
- />
- {reloadConfigButton}
- <RequestButton
- requestAction={invalidateAllCaches}
- helpText={
- <FormattedMessage
- id='admin.purge.purgeDescription'
- defaultMessage='This will purge all the in-memory caches for things like sessions, accounts, channels, etc. Deployments using High Availability will attempt to purge all the servers in the cluster. Purging the caches may adversely impact performance.'
- />
- }
- buttonText={
- <FormattedMessage
- id='admin.purge.button'
- defaultMessage='Purge All Caches'
- />
- }
- showSuccessMessage={false}
- includeDetailedError={true}
- errorMessage={{
- id: 'admin.purge.purgeFail',
- defaultMessage: 'Purging unsuccessful: {error}'
- }}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/connection_security_dropdown_setting.jsx b/webapp/components/admin_console/connection_security_dropdown_setting.jsx
deleted file mode 100644
index b7b283be1..000000000
--- a/webapp/components/admin_console/connection_security_dropdown_setting.jsx
+++ /dev/null
@@ -1,191 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import * as Utils from 'utils/utils.jsx';
-
-import DropdownSetting from './dropdown_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-
-const SECTION_NONE = (
- <tr>
- <td>
- <FormattedMessage
- id='admin.connectionSecurityNone'
- defaultMessage='None'
- />
- </td>
- <td>
- <FormattedMessage
- id='admin.connectionSecurityNoneDescription'
- defaultMessage='Mattermost will connect over an insecure connection.'
- />
- </td>
- </tr>
-);
-
-const SECTION_TLS = (
- <tr>
- <td>
- <FormattedMessage
- id='admin.connectionSecurityTls'
- defaultMessage='TLS'
- />
- </td>
- <td>
- <FormattedMessage
- id='admin.connectionSecurityTlsDescription'
- defaultMessage='Encrypts the communication between Mattermost and your server.'
- />
- </td>
- </tr>
-);
-
-const SECTION_STARTTLS = (
- <tr>
- <td>
- <FormattedMessage
- id='admin.connectionSecurityStart'
- defaultMessage='STARTTLS'
- />
- </td>
- <td>
- <FormattedMessage
- id='admin.connectionSecurityStartDescription'
- defaultMessage='Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.'
- />
- </td>
- </tr>
-);
-
-const CONNECTION_SECURITY_HELP_TEXT_EMAIL = (
- <table
- className='table table-bordered table-margin--none'
- cellPadding='5'
- >
- <tbody>
- {SECTION_NONE}
- {SECTION_TLS}
- {SECTION_STARTTLS}
- </tbody>
- </table>
-);
-
-const CONNECTION_SECURITY_HELP_TEXT_LDAP = (
- <table
- className='table table-bordered table-margin--none'
- cellPadding='5'
- >
- <tbody>
- {SECTION_NONE}
- {SECTION_TLS}
- {SECTION_STARTTLS}
- </tbody>
- </table>
-);
-
-const CONNECTION_SECURITY_HELP_TEXT_WEBSERVER = (
- <table
- className='table table-bordered table-margin--none'
- cellPadding='5'
- >
- <tbody>
- {SECTION_NONE}
- {SECTION_TLS}
- </tbody>
- </table>
-);
-
-export function ConnectionSecurityDropdownSettingEmail(props) {
- return (
- <DropdownSetting
- id='connectionSecurity'
- values={[
- {value: '', text: Utils.localizeMessage('admin.connectionSecurityNone', 'None')},
- {value: 'TLS', text: Utils.localizeMessage('admin.connectionSecurityTls', 'TLS (Recommended)')},
- {value: 'STARTTLS', text: Utils.localizeMessage('admin.connectionSecurityStart')}
- ]}
- label={
- <FormattedMessage
- id='admin.connectionSecurityTitle'
- defaultMessage='Connection Security:'
- />
- }
- value={props.value}
- onChange={props.onChange}
- disabled={props.disabled}
- helpText={CONNECTION_SECURITY_HELP_TEXT_EMAIL}
- />
- );
-}
-ConnectionSecurityDropdownSettingEmail.defaultProps = {
-};
-
-ConnectionSecurityDropdownSettingEmail.propTypes = {
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired
-};
-
-export function ConnectionSecurityDropdownSettingLdap(props) {
- return (
- <DropdownSetting
- id='connectionSecurity'
- values={[
- {value: '', text: Utils.localizeMessage('admin.connectionSecurityNone', 'None')},
- {value: 'TLS', text: Utils.localizeMessage('admin.connectionSecurityTls', 'TLS (Recommended)')},
- {value: 'STARTTLS', text: Utils.localizeMessage('admin.connectionSecurityStart')}
- ]}
- label={
- <FormattedMessage
- id='admin.connectionSecurityTitle'
- defaultMessage='Connection Security:'
- />
- }
- value={props.value}
- onChange={props.onChange}
- disabled={props.disabled}
- helpText={CONNECTION_SECURITY_HELP_TEXT_LDAP}
- />
- );
-}
-ConnectionSecurityDropdownSettingLdap.defaultProps = {
-};
-
-ConnectionSecurityDropdownSettingLdap.propTypes = {
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired
-};
-
-export function ConnectionSecurityDropdownSettingWebserver(props) {
- return (
- <DropdownSetting
- id='connectionSecurity'
- values={[
- {value: '', text: Utils.localizeMessage('admin.connectionSecurityNone', 'None')},
- {value: 'TLS', text: Utils.localizeMessage('admin.connectionSecurityTls', 'TLS (Recommended)')}
- ]}
- label={
- <FormattedMessage
- id='admin.connectionSecurityTitle'
- defaultMessage='Connection Security:'
- />
- }
- value={props.value}
- onChange={props.onChange}
- disabled={props.disabled}
- helpText={CONNECTION_SECURITY_HELP_TEXT_WEBSERVER}
- />
- );
-}
-ConnectionSecurityDropdownSettingWebserver.defaultProps = {
-};
-
-ConnectionSecurityDropdownSettingWebserver.propTypes = {
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired
-};
diff --git a/webapp/components/admin_console/connection_settings.jsx b/webapp/components/admin_console/connection_settings.jsx
deleted file mode 100644
index 78a0b89ed..000000000
--- a/webapp/components/admin_console/connection_settings.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class ConnectionSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.AllowCorsFrom = this.state.allowCorsFrom;
- config.ServiceSettings.EnableInsecureOutgoingConnections = this.state.enableInsecureOutgoingConnections;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- allowCorsFrom: config.ServiceSettings.AllowCorsFrom,
- enableInsecureOutgoingConnections: config.ServiceSettings.EnableInsecureOutgoingConnections
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.security.connection'
- defaultMessage='Connections'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <TextSetting
- id='allowCorsFrom'
- label={
- <FormattedMessage
- id='admin.service.corsTitle'
- defaultMessage='Enable cross-origin requests from:'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.corsEx', 'http://example.com')}
- helpText={
- <FormattedMessage
- id='admin.service.corsDescription'
- defaultMessage='Enable HTTP Cross origin request from a specific domain. Use "*" if you want to allow CORS from any domain or leave it blank to disable it.'
- />
- }
- value={this.state.allowCorsFrom}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableInsecureOutgoingConnections'
- label={
- <FormattedMessage
- id='admin.service.insecureTlsTitle'
- defaultMessage='Enable Insecure Outgoing Connections: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.insecureTlsDesc'
- defaultMessage='When true, any outgoing HTTPS requests will accept unverified, self-signed certificates. For example, outgoing webhooks to a server with a self-signed TLS certificate, using any domain, will be allowed. Note that this makes these connections susceptible to man-in-the-middle attacks.'
- />
- }
- value={this.state.enableInsecureOutgoingConnections}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/custom_brand_settings.jsx b/webapp/components/admin_console/custom_brand_settings.jsx
deleted file mode 100644
index 4ca3dee0c..000000000
--- a/webapp/components/admin_console/custom_brand_settings.jsx
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import BrandImageSetting from './brand_image_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-import Constants from 'utils/constants.jsx';
-
-export default class CustomBrandSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.TeamSettings.SiteName = this.state.siteName;
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true') {
- config.TeamSettings.customDescriptionText = this.state.customDescriptionText;
- config.TeamSettings.EnableCustomBrand = this.state.enableCustomBrand;
- config.TeamSettings.CustomBrandText = this.state.customBrandText;
- }
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- siteName: config.TeamSettings.SiteName,
- enableCustomBrand: config.TeamSettings.EnableCustomBrand,
- customBrandText: config.TeamSettings.CustomBrandText,
- customDescriptionText: config.TeamSettings.CustomDescriptionText
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.customization.customBrand'
- defaultMessage='Custom Branding'
- />
- );
- }
-
- renderSettings() {
- const enterpriseSettings = [];
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true') {
- enterpriseSettings.push(
- <TextSetting
- key='customDescriptionText'
- id='customDescriptionText'
- label={
- <FormattedMessage
- id='admin.team.brandDescriptionTitle'
- defaultMessage='Site Description: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.team.brandDescriptionHelp'
- defaultMessage='Description of service shown in login screens and UI. When not specified, "All team communication in one place, searchable and accessible anywhere" is displayed.'
- />
- }
- value={this.state.customDescriptionText}
- placeholder={Utils.localizeMessage('web.root.signup_info', 'All team communication in one place, searchable and accessible anywhere')}
- onChange={this.handleChange}
- />
- );
-
- enterpriseSettings.push(
- <BooleanSetting
- key='enableCustomBrand'
- id='enableCustomBrand'
- label={
- <FormattedMessage
- id='admin.team.brandTitle'
- defaultMessage='Enable Custom Branding: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.team.brandDesc'
- defaultMessage='Enable custom branding to show an image of your choice, uploaded below, and some help text, written below, on the login page.'
- />
- }
- value={this.state.enableCustomBrand}
- onChange={this.handleChange}
- />
- );
-
- enterpriseSettings.push(
- <BrandImageSetting
- key='customBrandImage'
- disabled={!this.state.enableCustomBrand}
- />
- );
-
- enterpriseSettings.push(
- <TextSetting
- key='customBrandText'
- id='customBrandText'
- type='textarea'
- label={
- <FormattedMessage
- id='admin.team.brandTextTitle'
- defaultMessage='Custom Brand Text:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.team.brandTextDescription'
- defaultMessage='Text that will appear below your custom brand image on your login screen. Supports Markdown-formatted text. Maximum 500 characters allowed.'
- />
- }
- value={this.state.customBrandText}
- onChange={this.handleChange}
- disabled={!this.state.enableCustomBrand}
- />
- );
- }
-
- return (
- <SettingsGroup>
- <TextSetting
- id='siteName'
- label={
- <FormattedMessage
- id='admin.team.siteNameTitle'
- defaultMessage='Site Name:'
- />
- }
- maxLength={Constants.MAX_SITENAME_LENGTH}
- placeholder={Utils.localizeMessage('admin.team.siteNameExample', 'Ex "Mattermost"')}
- helpText={
- <FormattedMessage
- id='admin.team.siteNameDescription'
- defaultMessage='Name of service shown in login screens and UI.'
- />
- }
- value={this.state.siteName}
- onChange={this.handleChange}
- />
- {enterpriseSettings}
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/custom_emoji_settings.jsx b/webapp/components/admin_console/custom_emoji_settings.jsx
deleted file mode 100644
index 329900888..000000000
--- a/webapp/components/admin_console/custom_emoji_settings.jsx
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-
-export default class CustomEmojiSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.EnableCustomEmoji = this.state.enableCustomEmoji;
- config.ServiceSettings.EnableEmojiPicker = this.state.enableEmojiPicker;
-
- if (global.window.mm_license.IsLicensed === 'true') {
- config.ServiceSettings.RestrictCustomEmojiCreation = this.state.restrictCustomEmojiCreation;
- }
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableCustomEmoji: config.ServiceSettings.EnableCustomEmoji,
- enableEmojiPicker: config.ServiceSettings.EnableEmojiPicker,
- restrictCustomEmojiCreation: config.ServiceSettings.RestrictCustomEmojiCreation
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.customization.emoji'
- defaultMessage='Emoji'
- />
- );
- }
-
- renderSettings() {
- let restrictSetting = null;
- if (global.window.mm_license.IsLicensed === 'true') {
- restrictSetting = (
- <DropdownSetting
- id='restrictCustomEmojiCreation'
- values={[
- {value: 'all', text: Utils.localizeMessage('admin.customization.restrictCustomEmojiCreationAll', 'Allow everyone to create custom emoji')},
- {value: 'admin', text: Utils.localizeMessage('admin.customization.restrictCustomEmojiCreationAdmin', 'Allow System and Team Admins to create custom emoji')},
- {value: 'system_admin', text: Utils.localizeMessage('admin.customization.restrictCustomEmojiCreationSystemAdmin', 'Only allow System Admins to create custom emoji')}
- ]}
- label={
- <FormattedMessage
- id='admin.customization.restrictCustomEmojiCreationTitle'
- defaultMessage='Restrict Custom Emoji Creation:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.customization.restrictCustomEmojiCreationDesc'
- defaultMessage='Restrict the creation of custom emoji to certain users.'
- />
- }
- value={this.state.restrictCustomEmojiCreation}
- onChange={this.handleChange}
- disabled={!this.state.enableCustomEmoji}
- />
- );
- }
-
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableEmojiPicker'
- label={
- <FormattedMessage
- id='admin.customization.enableEmojiPickerTitle'
- defaultMessage='Enable Emoji Picker:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.customization.enableEmojiPickerDesc'
- defaultMessage='The emoji picker allows users to select emoji to add as reactions or use in messages. Enabling the emoji picker with a large number of custom emoji may slow down performance.'
- />
- }
- value={this.state.enableEmojiPicker}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableCustomEmoji'
- label={
- <FormattedMessage
- id='admin.customization.enableCustomEmojiTitle'
- defaultMessage='Enable Custom Emoji:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.customization.enableCustomEmojiDesc'
- defaultMessage='Enable users to create custom emoji for use in messages. When enabled, Custom Emoji settings can be accessed by switching to a team and clicking the three dots above the channel sidebar, and selecting "Custom Emoji".'
- />
- }
- value={this.state.enableCustomEmoji}
- onChange={this.handleChange}
- />
- {restrictSetting}
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/custom_integrations_settings.jsx b/webapp/components/admin_console/custom_integrations_settings.jsx
deleted file mode 100644
index e6bcb4b32..000000000
--- a/webapp/components/admin_console/custom_integrations_settings.jsx
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-
-export default class WebhookSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.EnableIncomingWebhooks = this.state.enableIncomingWebhooks;
- config.ServiceSettings.EnableOutgoingWebhooks = this.state.enableOutgoingWebhooks;
- config.ServiceSettings.EnableCommands = this.state.enableCommands;
- config.ServiceSettings.EnableOnlyAdminIntegrations = this.state.enableOnlyAdminIntegrations;
- config.ServiceSettings.EnablePostUsernameOverride = this.state.enablePostUsernameOverride;
- config.ServiceSettings.EnablePostIconOverride = this.state.enablePostIconOverride;
- config.ServiceSettings.EnableOAuthServiceProvider = this.state.enableOAuthServiceProvider;
- config.ServiceSettings.EnableUserAccessTokens = this.state.enableUserAccessTokens;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableIncomingWebhooks: config.ServiceSettings.EnableIncomingWebhooks,
- enableOutgoingWebhooks: config.ServiceSettings.EnableOutgoingWebhooks,
- enableCommands: config.ServiceSettings.EnableCommands,
- enableOnlyAdminIntegrations: config.ServiceSettings.EnableOnlyAdminIntegrations,
- enablePostUsernameOverride: config.ServiceSettings.EnablePostUsernameOverride,
- enablePostIconOverride: config.ServiceSettings.EnablePostIconOverride,
- enableOAuthServiceProvider: config.ServiceSettings.EnableOAuthServiceProvider,
- enableUserAccessTokens: config.ServiceSettings.EnableUserAccessTokens
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.integrations.custom'
- defaultMessage='Custom Integrations'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableIncomingWebhooks'
- label={
- <FormattedMessage
- id='admin.service.webhooksTitle'
- defaultMessage='Enable Incoming Webhooks: '
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.webhooksDescription'
- defaultMessage='When true, incoming webhooks will be allowed. To help combat phishing attacks, all posts from webhooks will be labelled by a BOT tag. See <a href="http://docs.mattermost.com/developer/webhooks-incoming.html" target="_blank">documentation</a> to learn more.'
- />
- }
- value={this.state.enableIncomingWebhooks}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableOutgoingWebhooks'
- label={
- <FormattedMessage
- id='admin.service.outWebhooksTitle'
- defaultMessage='Enable Outgoing Webhooks: '
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.outWebhooksDesc'
- defaultMessage='When true, outgoing webhooks will be allowed. See <a href="http://docs.mattermost.com/developer/webhooks-outgoing.html" target="_blank">documentation</a> to learn more.'
- />
- }
- value={this.state.enableOutgoingWebhooks}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableCommands'
- label={
- <FormattedMessage
- id='admin.service.cmdsTitle'
- defaultMessage='Enable Custom Slash Commands: '
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.cmdsDesc'
- defaultMessage='When true, custom slash commands will be allowed. See <a href="http://docs.mattermost.com/developer/slash-commands.html" target="_blank">documentation</a> to learn more.'
- />
- }
- value={this.state.enableCommands}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableOAuthServiceProvider'
- label={
- <FormattedMessage
- id='admin.oauth.providerTitle'
- defaultMessage='Enable OAuth 2.0 Service Provider: '
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.oauth.providerDescription'
- defaultMessage='When true, Mattermost can act as an OAuth 2.0 service provider allowing Mattermost to authorize API requests from external applications. See <a href="https://docs.mattermost.com/developer/oauth-2-0-applications.html" target="_blank">documentation</a> to learn more.'
- />
- }
- value={this.state.enableOAuthServiceProvider}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableOnlyAdminIntegrations'
- label={
- <FormattedMessage
- id='admin.service.integrationAdmin'
- defaultMessage='Restrict managing integrations to Admins:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.integrationAdminDesc'
- defaultMessage='When true, webhooks and slash commands can only be created, edited and viewed by Team and System Admins, and OAuth 2.0 applications by System Admins. Integrations are available to all users after they have been created by the Admin.'
- />
- }
- value={this.state.enableOnlyAdminIntegrations}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enablePostUsernameOverride'
- label={
- <FormattedMessage
- id='admin.service.overrideTitle'
- defaultMessage='Enable integrations to override usernames:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.overrideDescription'
- defaultMessage='When true, webhooks, slash commands and other integrations, such as <a href="https://docs.mattermost.com/integrations/zapier.html" target="_blank">Zapier</a>, will be allowed to change the username they are posting as. Note: Combined with allowing integrations to override profile picture icons, users may be able to perform phishing attacks by attempting to impersonate other users.'
- />
- }
- value={this.state.enablePostUsernameOverride}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enablePostIconOverride'
- label={
- <FormattedMessage
- id='admin.service.iconTitle'
- defaultMessage='Enable integrations to override profile picture icons:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.iconDescription'
- defaultMessage='When true, webhooks, slash commands and other integrations, such as <a href="https://docs.mattermost.com/integrations/zapier.html" target="_blank">Zapier</a>, will be allowed to change the profile picture they post with. Note: Combined with allowing integrations to override usernames, users may be able to perform phishing attacks by attempting to impersonate other users.'
- />
- }
- value={this.state.enablePostIconOverride}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableUserAccessTokens'
- label={
- <FormattedMessage
- id='admin.service.userAccessTokensTitle'
- defaultMessage='Enable User Access Tokens: '
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.userAccessTokensDescription'
- defaultMessage='When true, users can create <a href="https://about.mattermost.com/default-user-access-tokens" target="_blank">user access tokens</a> for integrations in <strong>Account Settings > Security</strong>. They can be used to authenticate against the API and give full access to the account.<br/><br/>To manage who can create personal access tokens or to search users by token ID, go to the <strong>System Console > Users</strong> page.'
- />
- }
- value={this.state.enableUserAccessTokens}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/database_settings.jsx b/webapp/components/admin_console/database_settings.jsx
deleted file mode 100644
index 9f008483c..000000000
--- a/webapp/components/admin_console/database_settings.jsx
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {recycleDatabaseConnection} from 'actions/admin_actions.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import GeneratedSetting from './generated_setting.jsx';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-import RequestButton from './request_button/request_button.jsx';
-
-export default class DatabaseSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- // driverName and dataSource are read-only from the UI
-
- config.SqlSettings.MaxIdleConns = this.parseIntNonZero(this.state.maxIdleConns);
- config.SqlSettings.MaxOpenConns = this.parseIntNonZero(this.state.maxOpenConns);
- config.SqlSettings.AtRestEncryptKey = this.state.atRestEncryptKey;
- config.SqlSettings.Trace = this.state.trace;
- config.SqlSettings.QueryTimeout = this.parseIntNonZero(this.state.queryTimeout);
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- driverName: config.SqlSettings.DriverName,
- dataSource: config.SqlSettings.DataSource,
- maxIdleConns: config.SqlSettings.MaxIdleConns,
- maxOpenConns: config.SqlSettings.MaxOpenConns,
- atRestEncryptKey: config.SqlSettings.AtRestEncryptKey,
- trace: config.SqlSettings.Trace,
- queryTimeout: config.SqlSettings.QueryTimeout
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.database.title'
- defaultMessage='Database Settings'
- />
- );
- }
-
- renderSettings() {
- const dataSource = '**********' + this.state.dataSource.substring(this.state.dataSource.indexOf('@'));
-
- let recycleDbButton = <div/>;
- if (global.window.mm_license.IsLicensed === 'true') {
- recycleDbButton = (
- <RequestButton
- requestAction={recycleDatabaseConnection}
- helpText={
- <FormattedMessage
- id='admin.recycle.recycleDescription'
- defaultMessage='Deployments using multiple databases can switch from one master database to another without restarting the Mattermost server by updating "config.json" to the new desired configuration and using the {reloadConfiguration} feature to load the new settings while the server is running. The administrator should then use {featureName} feature to recycle the database connections based on the new settings.'
- values={{
- featureName: (
- <b>
- <FormattedMessage
- id='admin.recycle.recycleDescription.featureName'
- defaultMessage='Recycle Database Connections'
- />
- </b>
- ),
- reloadConfiguration: (
- <a href='../general/configuration'>
- <b>
- <FormattedMessage
- id='admin.recycle.recycleDescription.reloadConfiguration'
- defaultMessage='Configuration > Reload Configuration from Disk'
- />
- </b>
- </a>
- )
- }}
- />
- }
- buttonText={
- <FormattedMessage
- id='admin.recycle.button'
- defaultMessage='Recycle Database Connections'
- />
- }
- showSuccessMessage={false}
- errorMessage={{
- id: 'admin.recycle.reloadFail',
- defaultMessage: 'Recycling unsuccessful: {error}'
- }}
- includeDetailedError={true}
- />
- );
- }
-
- return (
- <SettingsGroup>
- <div className='banner'>
- <FormattedMessage
- id='admin.sql.noteDescription'
- defaultMessage='Changing properties in this section will require a server restart before taking effect.'
- />
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='DriverName'
- >
- <FormattedMessage
- id='admin.sql.driverName'
- defaultMessage='Driver Name:'
- />
- </label>
- <div className='col-sm-8'>
- <p className='help-text'>{this.state.driverName}</p>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='DataSource'
- >
- <FormattedMessage
- id='admin.sql.dataSource'
- defaultMessage='Data Source:'
- />
- </label>
- <div className='col-sm-8'>
- <p className='help-text'>{dataSource}</p>
- </div>
- </div>
- <TextSetting
- id='maxIdleConns'
- label={
- <FormattedMessage
- id='admin.sql.maxConnectionsTitle'
- defaultMessage='Maximum Idle Connections:'
- />
- }
- placeholder={Utils.localizeMessage('admin.sql.maxConnectionsExample', 'Ex "10"')}
- helpText={
- <FormattedMessage
- id='admin.sql.maxConnectionsDescription'
- defaultMessage='Maximum number of idle connections held open to the database.'
- />
- }
- value={this.state.maxIdleConns}
- onChange={this.handleChange}
- />
- <TextSetting
- id='maxOpenConns'
- label={
- <FormattedMessage
- id='admin.sql.maxOpenTitle'
- defaultMessage='Maximum Open Connections:'
- />
- }
- placeholder={Utils.localizeMessage('admin.sql.maxOpenExample', 'Ex "10"')}
- helpText={
- <FormattedMessage
- id='admin.sql.maxOpenDescription'
- defaultMessage='Maximum number of open connections held open to the database.'
- />
- }
- value={this.state.maxOpenConns}
- onChange={this.handleChange}
- />
- <TextSetting
- id='queryTimeout'
- label={
- <FormattedMessage
- id='admin.sql.queryTimeoutTitle'
- defaultMessage='Query Timeout:'
- />
- }
- placeholder={Utils.localizeMessage('admin.sql.queryTimeoutExample', 'Ex "30"')}
- helpText={
- <FormattedMessage
- id='admin.sql.queryTimeoutDescription'
- defaultMessage='The number of seconds to wait for a response from the database after opening a connection and sending the query. Errors that you see in the UI or in the logs as a result of a query timeout can vary depending on the type of query.'
- />
- }
- value={this.state.queryTimeout}
- onChange={this.handleChange}
- />
- <GeneratedSetting
- id='atRestEncryptKey'
- label={
- <FormattedMessage
- id='admin.sql.keyTitle'
- defaultMessage='At Rest Encrypt Key:'
- />
- }
- placeholder={Utils.localizeMessage('admin.sql.keyExample', 'Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"')}
- helpText={
- <FormattedMessage
- id='admin.sql.keyDescription'
- defaultMessage='32-character salt available to encrypt and decrypt sensitive fields in database.'
- />
- }
- value={this.state.atRestEncryptKey}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='trace'
- label={
- <FormattedMessage
- id='admin.sql.traceTitle'
- defaultMessage='Trace: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.sql.traceDescription'
- defaultMessage='(Development Mode) When true, executing SQL statements are written to the log.'
- />
- }
- value={this.state.trace}
- onChange={this.handleChange}
- />
- {recycleDbButton}
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/developer_settings.jsx b/webapp/components/admin_console/developer_settings.jsx
deleted file mode 100644
index 6a8f49dbd..000000000
--- a/webapp/components/admin_console/developer_settings.jsx
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class DeveloperSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.EnableTesting = this.state.enableTesting;
- config.ServiceSettings.EnableDeveloper = this.state.enableDeveloper;
- config.ServiceSettings.AllowedUntrustedInternalConnections = this.state.allowedUntrustedInternalConnections;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableTesting: config.ServiceSettings.EnableTesting,
- enableDeveloper: config.ServiceSettings.EnableDeveloper,
- allowedUntrustedInternalConnections: config.ServiceSettings.AllowedUntrustedInternalConnections
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.developer.title'
- defaultMessage='Developer Settings'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableTesting'
- label={
- <FormattedMessage
- id='admin.service.testingTitle'
- defaultMessage='Enable Testing Commands: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.testingDescription'
- defaultMessage='When true, /test slash command is enabled to load test accounts, data and text formatting. Changing this requires a server restart before taking effect.'
- />
- }
- value={this.state.enableTesting}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableDeveloper'
- label={
- <FormattedMessage
- id='admin.service.developerTitle'
- defaultMessage='Enable Developer Mode: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.developerDesc'
- defaultMessage='When true, JavaScript errors are shown in a purple bar at the top of the user interface. Not recommended for use in production. '
- />
- }
- value={this.state.enableDeveloper}
- onChange={this.handleChange}
- />
- <TextSetting
- id='allowedUntrustedInternalConnections'
- label={
- <FormattedMessage
- id='admin.service.internalConnectionsTitle'
- defaultMessage='Allow untrusted internal connections to: '
- />
- }
- placeholder={Utils.localizeMessage('admin.service.internalConnectionsEx', 'webhooks.internal.example.com 127.0.0.1 10.0.16.0/28')}
- helpText={
- <FormattedHTMLMessage
- id='admin.service.internalConnectionsDesc'
- defaultMessage='In testing environments, such as when developing integrations locally on a development machine, use this setting to specify domains, IP addresses, or CIDR notations to allow internal connections. <b>Not recommended for use in production</b>, since this can allow a user to extract confidential data from your server or internal network.<br /><br />By default, user-supplied URLs such as those used for Open Graph metadata, webhooks, or slash commands will not be allowed to connect to reserved IP addresses including loopback or link-local addresses used for internal networks. Push notification, OAuth 2.0 and WebRTC server URLs are trusted and not affected by this setting.'
- />
- }
- value={this.state.allowedUntrustedInternalConnections}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/dropdown_setting.jsx b/webapp/components/admin_console/dropdown_setting.jsx
deleted file mode 100644
index 05179a4b9..000000000
--- a/webapp/components/admin_console/dropdown_setting.jsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import Setting from './setting.jsx';
-
-export default class DropdownSetting extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- }
-
- handleChange(e) {
- this.props.onChange(this.props.id, e.target.value);
- }
-
- render() {
- const options = [];
- for (const {value, text} of this.props.values) {
- options.push(
- <option
- value={value}
- key={value}
- >
- {text}
- </option>
- );
- }
-
- return (
- <Setting
- label={this.props.label}
- inputId={this.props.id}
- helpText={this.props.helpText}
- >
- <select
- className='form-control'
- id={this.props.id}
- value={this.props.value}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- >
- {options}
- </select>
- </Setting>
- );
- }
-}
-
-DropdownSetting.defaultProps = {
- isDisabled: false
-};
-
-DropdownSetting.propTypes = {
- id: PropTypes.string.isRequired,
- values: PropTypes.array.isRequired,
- label: PropTypes.node.isRequired,
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool,
- helpText: PropTypes.node
-};
diff --git a/webapp/components/admin_console/elasticsearch_settings.jsx b/webapp/components/admin_console/elasticsearch_settings.jsx
deleted file mode 100644
index b739241ef..000000000
--- a/webapp/components/admin_console/elasticsearch_settings.jsx
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import {elasticsearchTest, elasticsearchPurgeIndexes} from 'actions/admin_actions.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-import RequestButton from './request_button/request_button.jsx';
-import ElasticsearchStatus from './elasticsearch_status';
-
-export default class ElasticsearchSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.doTestConfig = this.doTestConfig.bind(this);
- this.handleChange = this.handleChange.bind(this);
- this.handleSaved = this.handleSaved.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ElasticsearchSettings.ConnectionUrl = this.state.connectionUrl;
- config.ElasticsearchSettings.Username = this.state.username;
- config.ElasticsearchSettings.Password = this.state.password;
- config.ElasticsearchSettings.Sniff = this.state.sniff;
- config.ElasticsearchSettings.EnableIndexing = this.state.enableIndexing;
- config.ElasticsearchSettings.EnableSearching = this.state.enableSearching;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- connectionUrl: config.ElasticsearchSettings.ConnectionUrl,
- username: config.ElasticsearchSettings.Username,
- password: config.ElasticsearchSettings.Password,
- sniff: config.ElasticsearchSettings.Sniff,
- enableIndexing: config.ElasticsearchSettings.EnableIndexing,
- enableSearching: config.ElasticsearchSettings.EnableSearching,
- configTested: true,
- canSave: true,
- canPurgeAndIndex: config.ElasticsearchSettings.EnableIndexing
- };
- }
-
- handleChange(id, value) {
- if (id === 'enableIndexing') {
- if (value === false) {
- this.setState({
- enableSearching: false
- });
- } else {
- this.setState({
- canSave: false,
- configTested: false
- });
- }
- }
-
- if (id === 'connectionUrl' || id === 'username' || id === 'password' || id === 'sniff') {
- this.setState({
- configTested: false,
- canSave: false
- });
- }
-
- if (id !== 'enableSearching') {
- this.setState({
- canPurgeAndIndex: false
- });
- }
-
- super.handleChange(id, value);
- }
-
- handleSaved() {
- this.setState({
- canPurgeAndIndex: this.state.enableIndexing
- });
- }
-
- canSave() {
- return this.state.canSave;
- }
-
- doTestConfig(success, error) {
- const config = JSON.parse(JSON.stringify(this.props.config));
- this.getConfigFromState(config);
-
- elasticsearchTest(
- config,
- () => {
- this.setState({
- configTested: true,
- canSave: true
- });
- success();
- this.doSubmit();
- },
- (err) => {
- this.setState({
- configTested: false,
- canSave: false
- });
- error(err);
- }
- );
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.elasticsearch.title'
- defaultMessage='Elasticsearch (Beta)'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <div className='banner'>
- <div className='banner__content'>
- <FormattedMessage
- id='admin.elasticsearch.noteDescription'
- defaultMessage='Changing properties in this section will require a server restart before taking effect.'
- />
- </div>
- </div>
- <BooleanSetting
- id='enableIndexing'
- label={
- <FormattedMessage
- id='admin.elasticsearch.enableIndexingTitle'
- defaultMessage='Enable Elasticsearch Indexing:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.enableIndexingDescription'
- defaultMessage='When true, indexing of new posts occurs automatically. Search queries will use database search until "Enable Elasticsearch for search queries" is enabled. {documentationLink}'
- values={{
- documentationLink: (
- <a
- href='https://about.mattermost.com/default-elasticsearch-documentation/'
- rel='noopener noreferrer'
- target='_blank'
- >
- <FormattedMessage
- id='admin.elasticsearch.enableIndexingDescription.documentationLinkText'
- defaultMessage='Learn more about Elasticsearch in our documentation.'
- />
- </a>
- )
- }}
- />
- }
- value={this.state.enableIndexing}
- onChange={this.handleChange}
- />
- <TextSetting
- id='connectionUrl'
- label={
- <FormattedMessage
- id='admin.elasticsearch.connectionUrlTitle'
- defaultMessage='Server Connection Address:'
- />
- }
- placeholder={Utils.localizeMessage('admin.elasticsearch.connectionUrlExample', 'E.g.: "https://elasticsearch.example.org:9200"')}
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.connectionUrlDescription'
- defaultMessage='The address of the Elasticsearch server. {documentationLink}'
- values={{
- documentationLink: (
- <a
- href='https://about.mattermost.com/default-elasticsearch-server-setup/'
- rel='noopener noreferrer'
- target='_blank'
- >
- <FormattedMessage
- id='admin.elasticsearch.connectionUrlExample.documentationLinkText'
- defaultMessage='Please see documentation with server setup instructions.'
- />
- </a>
- )
- }}
- />
- }
- value={this.state.connectionUrl}
- disabled={!this.state.enableIndexing}
- onChange={this.handleChange}
- />
- <TextSetting
- id='username'
- label={
- <FormattedMessage
- id='admin.elasticsearch.usernameTitle'
- defaultMessage='Server Username:'
- />
- }
- placeholder={Utils.localizeMessage('admin.elasticsearch.usernameExample', 'E.g.: "elastic"')}
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.usernameDescription'
- defaultMessage='(Optional) The username to authenticate to the Elasticsearch server.'
- />
- }
- value={this.state.username}
- disabled={!this.state.enableIndexing}
- onChange={this.handleChange}
- />
- <TextSetting
- id='password'
- label={
- <FormattedMessage
- id='admin.elasticsearch.passwordTitle'
- defaultMessage='Server Password:'
- />
- }
- placeholder={Utils.localizeMessage('admin.elasticsearch.password', 'E.g.: "yourpassword"')}
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.passwordDescription'
- defaultMessage='(Optional) The password to authenticate to the Elasticsearch server.'
- />
- }
- value={this.state.password}
- disabled={!this.state.enableIndexing}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='sniff'
- label={
- <FormattedMessage
- id='admin.elasticsearch.sniffTitle'
- defaultMessage='Enable Cluster Sniffing:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.sniffDescription'
- defaultMessage='When true, sniffing finds and connects to all data nodes in your cluster automatically.'
- />
- }
- value={this.state.sniff}
- disabled={!this.state.enableIndexing}
- onChange={this.handleChange}
- />
- <RequestButton
- requestAction={this.doTestConfig}
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.testHelpText'
- defaultMessage='Tests if the Mattermost server can connect to the Elasticsearch server specified. Testing the connection only saves the configuration if the test is successful. See log file for more detailed error messages.'
- />
- }
- buttonText={
- <FormattedMessage
- id='admin.elasticsearch.elasticsearch_test_button'
- defaultMessage='Test Connection'
- />
- }
- successMessage={{
- id: 'admin.elasticsearch.testConfigSuccess',
- defaultMessage: 'Test successful. Configuration saved.'
- }}
- disabled={!this.state.enableIndexing}
- />
- <ElasticsearchStatus
- isConfigured={this.state.canPurgeAndIndex}
- />
- <RequestButton
- requestAction={elasticsearchPurgeIndexes}
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.purgeIndexesHelpText'
- defaultMessage='Purging will entirely remove the index on the Elasticsearch server. Search results may be incomplete until a bulk index of the existing post database is rebuilt.'
- />
- }
- buttonText={
- <FormattedMessage
- id='admin.elasticsearch.purgeIndexesButton'
- defaultMessage='Purge Index'
- />
- }
- successMessage={{
- id: 'admin.elasticsearch.purgeIndexesButton.success',
- defaultMessage: 'Indexes purged successfully.'
- }}
- errorMessage={{
- id: 'admin.elasticsearch.purgeIndexesButton.error',
- defaultMessage: 'Failed to purge indexes: {error}'
- }}
- disabled={!this.state.canPurgeAndIndex}
- label={(
- <FormattedMessage
- id='admin.elasticsearch.purgeIndexesButton.label'
- defaultMessage='Purge Indexes:'
- />
- )}
- />
- <BooleanSetting
- id='enableSearching'
- label={
- <FormattedMessage
- id='admin.elasticsearch.enableSearchingTitle'
- defaultMessage='Enable Elasticsearch for search queries:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.elasticsearch.enableSearchingDescription'
- defaultMessage='Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all search queries using the latest index. Search results may be incomplete until a bulk index of the existing post database is finished. When false, database search is used.'
- />
- }
- value={this.state.enableSearching}
- disabled={!this.state.enableIndexing || !this.state.configTested}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/elasticsearch_status/index.js b/webapp/components/admin_console/elasticsearch_status/index.js
deleted file mode 100644
index 6446195d2..000000000
--- a/webapp/components/admin_console/elasticsearch_status/index.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {getJobsByType} from 'mattermost-redux/actions/jobs';
-import {JobTypes} from 'utils/constants.jsx';
-
-import * as Selectors from 'mattermost-redux/selectors/entities/jobs';
-
-import Status from './status.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- jobs: Selectors.makeGetJobsByType(JobTypes.ELASTICSEARCH_POST_INDEXING)(state)
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getJobsByType
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(Status);
diff --git a/webapp/components/admin_console/elasticsearch_status/status.jsx b/webapp/components/admin_console/elasticsearch_status/status.jsx
deleted file mode 100644
index 0a32d39c8..000000000
--- a/webapp/components/admin_console/elasticsearch_status/status.jsx
+++ /dev/null
@@ -1,361 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage} from 'react-intl';
-
-import {createJob, cancelJob} from 'actions/job_actions.jsx';
-import {JobTypes, JobStatuses} from 'utils/constants.jsx';
-import RequestButton from '../request_button/request_button.jsx';
-
-export default class Status extends React.PureComponent {
- static propTypes = {
-
- /**
- * Array of jobs
- */
- jobs: PropTypes.arrayOf(PropTypes.object).isRequired,
-
- /**
- * Whether Elasticsearch is properly configured.
- */
- isConfigured: PropTypes.bool.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * Function to fetch jobs
- */
- getJobsByType: PropTypes.func.isRequired
- }).isRequired
- };
-
- constructor(props) {
- super(props);
-
- this.interval = null;
-
- this.state = {
- loading: true,
- cancelInProgress: false
- };
- }
-
- componentWillMount() {
- // reload the cluster status every 15 seconds
- this.interval = setInterval(this.reload, 15000);
- }
-
- componentDidMount() {
- this.props.actions.getJobsByType(JobTypes.ELASTICSEARCH_POST_INDEXING).then(
- () => this.setState({loading: false})
- );
- }
-
- componentWillUnmount() {
- if (this.interval) {
- clearInterval(this.interval);
- }
- }
-
- reload = () => {
- this.props.actions.getJobsByType(JobTypes.ELASTICSEARCH_POST_INDEXING).then(
- () => {
- this.setState({
- loading: false,
- cancelInProgress: false
- });
- }
- );
- };
-
- createIndexJob = (success, error) => {
- const job = {
- type: JobTypes.ELASTICSEARCH_POST_INDEXING
- };
-
- createJob(
- job,
- () => {
- this.reload();
- success();
- },
- error
- );
- };
-
- cancelIndexJob = (e) => {
- e.preventDefault();
-
- const chosenJob = this.getChosenJob();
- if (!chosenJob) {
- return;
- }
-
- this.setState({
- cancelInProgress: true
- });
-
- cancelJob(
- chosenJob.id,
- () => {
- this.reload();
- },
- () => {
- this.reload();
- }
- );
- };
-
- getChosenJob = () => {
- let chosenJob = null;
-
- if (this.props.jobs.length > 0) {
- for (let i = 0; i < this.props.jobs.length; i++) {
- const job = this.props.jobs[i];
- if (job.status === JobStatuses.CANCEL_REQUESTED || job.status === JobStatuses.IN_PROGRESS) {
- chosenJob = job;
- } else {
- break;
- }
- }
-
- if (!chosenJob) {
- for (let i = 0; i < this.props.jobs.length; i++) {
- const job = this.props.jobs[i];
- if (job.status !== JobStatuses.PENDING && chosenJob) {
- continue;
- } else {
- chosenJob = job;
- break;
- }
- }
- }
- }
-
- return chosenJob;
- };
-
- render() {
- const chosenJob = this.getChosenJob();
-
- let indexButtonDisabled = !this.props.isConfigured;
- let buttonText = (
- <FormattedMessage
- id='admin.elasticsearch.indexButton.ready'
- defaultMessage='Build Index'
- />
- );
- let cancelButton = null;
- let indexButtonHelp = (
- <FormattedMessage
- id='admin.elasticsearch.indexHelpText.buildIndex'
- defaultMessage='All posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete.'
- />
- );
-
- if (this.state.loading) {
- indexButtonDisabled = true;
- } else if (chosenJob) {
- if (chosenJob.status === JobStatuses.PENDING || chosenJob.status === JobStatuses.IN_PROGRESS || chosenJob.status === JobStatuses.CANCEL_REQUESTED) {
- indexButtonDisabled = true;
- buttonText = (
- <span>
- <span className='fa fa-refresh icon--rotate'/>
- <FormattedMessage
- id='admin.elasticsearch.indexButton.inProgress'
- defaultMessage='Indexing in progress'
- />
- </span>
- );
- }
-
- if (chosenJob.status === JobStatuses.PENDING || chosenJob.status === JobStatuses.IN_PROGRESS || chosenJob.status === JobStatuses.CANCEL_REQUESTED) {
- indexButtonHelp = (
- <FormattedMessage
- id='admin.elasticsearch.indexHelpText.cancelIndexing'
- defaultMessage='Cancelling stops the indexing job and removes it from the queue. Posts that have already been indexed will not be deleted.'
- />
- );
- }
-
- if (!this.state.cancelInProgress && (chosenJob.status === JobStatuses.PENDING || chosenJob.status === JobStatuses.IN_PROGRESS)) {
- cancelButton = (
- <a
- href='#'
- className='btn btn-link'
- onClick={this.cancelIndexJob}
- >
- <FormattedMessage
- id='admin.elasticsearchStatus.cancelButton'
- defaultMessage='Cancel'
- />
- </a>
- );
- }
- }
-
- const indexButton = (
- <RequestButton
- requestAction={this.createIndexJob}
- helpText={indexButtonHelp}
- buttonText={buttonText}
- disabled={indexButtonDisabled}
- showSuccessMessage={false}
- errorMessage={{
- id: 'admin.elasticsearch.bulkIndexButton.error',
- defaultMessage: 'Failed to schedule Bulk Index Job: {error}'
- }}
- alternativeActionElement={cancelButton}
- label={(
- <FormattedMessage
- id='admin.elasticsearchStatus.bulkIndexLabel'
- defaultMessage='Bulk Indexing:'
- />
- )}
- />
- );
-
- let status = null;
- let statusHelp = null;
- let statusClass = null;
- if (!this.props.isConfigured) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusIndexingDisabled'
- defaultMessage='Indexing disabled.'
- />
- );
- } else if (this.state.loading) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusLoading'
- defaultMessage='Loading...'
- />
- );
- statusClass = 'status-icon-unknown';
- } else if (chosenJob) {
- if (chosenJob.status === JobStatuses.PENDING) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusPending'
- defaultMessage='Job pending.'
- />
- );
- statusHelp = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusPending.help'
- defaultMessage='Elasticsearch index job is queued on the job server. If Elasticsearch is enabled, search results may be incomplete until the job is finished.'
- />
- );
- statusClass = 'status-icon-warning';
- } else if (chosenJob.status === JobStatuses.IN_PROGRESS) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusInProgress'
- defaultMessage='Job in progress. {percent}% complete.'
- values={{
- percent: chosenJob.progress
- }}
- />
- );
- statusHelp = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusInProgress.help'
- defaultMessage='Indexing is in progress on the job server. If Elasticsearch is enabled, search results may be incomplete until the job is finished.'
- />
- );
- statusClass = 'status-icon-warning';
- } else if (chosenJob.status === JobStatuses.SUCCESS) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusSuccess'
- defaultMessage='Indexing complete.'
- />
- );
- statusHelp = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusSuccess.help'
- defaultMessage='Indexing is complete and new posts are being automatically indexed.'
- />
- );
- statusClass = 'status-icon-success';
- } else if (chosenJob.status === JobStatuses.ERROR) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusError'
- defaultMessage='Indexing error.'
- />
- );
- statusHelp = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusError.help'
- defaultMessage='Mattermost encountered an error building the Elasticsearch index: {error}'
- values={{
- error: chosenJob.data ? (chosenJob.data.error || '') : ''
- }}
- />
- );
- statusClass = 'status-icon-error';
- } else if (chosenJob.status === JobStatuses.CANCEL_REQUESTED) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusRequestCancel'
- defaultMessage='Canceling Job...'
- />
- );
- statusClass = 'status-icon-warning';
- } else if (chosenJob.status === JobStatuses.CANCELED) {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusCancelled'
- defaultMessage='Indexing job cancelled.'
- />
- );
- statusClass = 'status-icon-error';
- }
- } else {
- status = (
- <FormattedMessage
- id='admin.elasticsearchStatus.statusNoJobs'
- defaultMessage='No indexing jobs queued.'
- />
- );
- statusClass = 'status-icon-unknown';
- }
-
- if (statusHelp !== null) {
- statusHelp = (
- <div className='col-sm-offset-4 col-sm-8'>
- <div className='help-text'>
- {statusHelp}
- </div>
- </div>
- );
- }
-
- statusClass = 'fa fa-circle margin--right ' + statusClass;
-
- return (
- <div>
- {indexButton}
- <div className='form-group'>
- <div className='col-sm-offset-4 col-sm-8'>
- <div className='help-text no-margin'>
- <FormattedMessage
- id='admin.elasticsearchStatus.status'
- defaultMessage='Status: '
- />
- <i
- className={statusClass}
- />
- {status}
- </div>
- </div>
- {statusHelp}
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/email_authentication_settings.jsx b/webapp/components/admin_console/email_authentication_settings.jsx
deleted file mode 100644
index 9cc3ab3d7..000000000
--- a/webapp/components/admin_console/email_authentication_settings.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-
-export default class EmailAuthenticationSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.EmailSettings.EnableSignUpWithEmail = this.state.enableSignUpWithEmail;
- config.EmailSettings.EnableSignInWithEmail = this.state.enableSignInWithEmail;
- config.EmailSettings.EnableSignInWithUsername = this.state.enableSignInWithUsername;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableSignUpWithEmail: config.EmailSettings.EnableSignUpWithEmail,
- enableSignInWithEmail: config.EmailSettings.EnableSignInWithEmail,
- enableSignInWithUsername: config.EmailSettings.EnableSignInWithUsername
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.authentication.email'
- defaultMessage='Email Authentication'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableSignUpWithEmail'
- label={
- <FormattedMessage
- id='admin.email.allowSignupTitle'
- defaultMessage='Enable account creation with email: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.email.allowSignupDescription'
- defaultMessage='When true, Mattermost allows account creation using email and password. This value should be false only when you want to limit sign up to a single sign-on service like AD/LDAP, SAML or GitLab.'
- />
- }
- value={this.state.enableSignUpWithEmail}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableSignInWithEmail'
- label={
- <FormattedMessage
- id='admin.email.allowEmailSignInTitle'
- defaultMessage='Enable sign-in with email: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.email.allowEmailSignInDescription'
- defaultMessage='When true, Mattermost allows users to sign in using their email and password.'
- />
- }
- value={this.state.enableSignInWithEmail}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableSignInWithUsername'
- label={
- <FormattedMessage
- id='admin.email.allowUsernameSignInTitle'
- defaultMessage='Enable sign-in with username: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.email.allowUsernameSignInDescription'
- defaultMessage='When true, users with email login can sign in using their username and password. This setting does not affect AD/LDAP login.'
- />
- }
- value={this.state.enableSignInWithUsername}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/email_connection_test.jsx b/webapp/components/admin_console/email_connection_test.jsx
deleted file mode 100644
index 17edbf23e..000000000
--- a/webapp/components/admin_console/email_connection_test.jsx
+++ /dev/null
@@ -1,130 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import {FormattedMessage} from 'react-intl';
-
-import {testEmail} from 'actions/admin_actions.jsx';
-
-export default class EmailConnectionTestButton extends React.Component {
- static get propTypes() {
- return {
- config: PropTypes.object.isRequired,
- getConfigFromState: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleTestConnection = this.handleTestConnection.bind(this);
-
- this.state = {
- testing: false,
- success: false,
- fail: null
- };
- }
-
- handleTestConnection(e) {
- e.preventDefault();
-
- this.setState({
- testing: true,
- success: false,
- fail: null
- });
-
- const config = JSON.parse(JSON.stringify(this.props.config));
- this.props.getConfigFromState(config);
-
- testEmail(
- config,
- () => {
- this.setState({
- testing: false,
- success: true
- });
- },
- (err) => {
- let fail = err.message;
- if (err.detailed_error) {
- fail += ' - ' + err.detailed_error;
- }
-
- this.setState({
- testing: false,
- fail
- });
- }
- );
- }
-
- render() {
- let testMessage = null;
- if (this.state.success) {
- testMessage = (
- <div className='alert alert-success'>
- <i className='fa fa-check'/>
- <FormattedMessage
- id='admin.email.emailSuccess'
- defaultMessage='No errors were reported while sending an email. Please check your inbox to make sure.'
- />
- </div>
- );
- } else if (this.state.fail) {
- testMessage = (
- <div className='alert alert-warning'>
- <i className='fa fa-warning'/>
- <FormattedMessage
- id='admin.email.emailFail'
- defaultMessage='Connection unsuccessful: {error}'
- values={{
- error: this.state.fail
- }}
- />
- </div>
- );
- }
-
- let contents = null;
- if (this.state.testing) {
- contents = (
- <span>
- <span className='fa fa-refresh icon--rotate'/>
- {Utils.localizeMessage('admin.email.testing', 'Testing...')}
- </span>
- );
- } else {
- contents = (
- <FormattedMessage
- id='admin.email.connectionSecurityTest'
- defaultMessage='Test Connection'
- />
- );
- }
-
- return (
- <div className='form-group email-connection-test'>
- <div className='col-sm-offset-4 col-sm-8'>
- <div className='help-text'>
- <button
- className='btn btn-default'
- onClick={this.handleTestConnection}
- disabled={this.props.disabled}
- >
- {contents}
- </button>
- {testMessage}
- </div>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/email_settings.jsx b/webapp/components/admin_console/email_settings.jsx
deleted file mode 100644
index e630402bc..000000000
--- a/webapp/components/admin_console/email_settings.jsx
+++ /dev/null
@@ -1,395 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import ErrorStore from 'stores/error_store.jsx';
-
-import {ErrorBarTypes} from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {ConnectionSecurityDropdownSettingEmail} from './connection_security_dropdown_setting.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import EmailConnectionTest from './email_connection_test.jsx';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-const EMAIL_NOTIFICATION_CONTENTS_FULL = 'full';
-const EMAIL_NOTIFICATION_CONTENTS_GENERIC = 'generic';
-
-export default class EmailSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
- this.handleSaved = this.handleSaved.bind(this);
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.EmailSettings.SendEmailNotifications = this.state.sendEmailNotifications;
- config.EmailSettings.FeedbackName = this.state.feedbackName;
- config.EmailSettings.FeedbackEmail = this.state.feedbackEmail;
- config.EmailSettings.FeedbackOrganization = this.state.feedbackOrganization;
- config.EmailSettings.EnableSMTPAuth = this.state.enableSMTPAuth;
- config.EmailSettings.SMTPUsername = this.state.smtpUsername;
- config.EmailSettings.SMTPPassword = this.state.smtpPassword;
- config.EmailSettings.SMTPServer = this.state.smtpServer;
- config.EmailSettings.SMTPPort = this.state.smtpPort;
- config.EmailSettings.ConnectionSecurity = this.state.connectionSecurity;
- config.EmailSettings.EnableEmailBatching = this.state.enableEmailBatching;
- config.ServiceSettings.EnableSecurityFixAlert = this.state.enableSecurityFixAlert;
- config.EmailSettings.SkipServerCertificateVerification = this.state.skipServerCertificateVerification;
- config.EmailSettings.EmailNotificationContentsType = this.state.emailNotificationContentsType;
-
- return config;
- }
-
- handleSaved(newConfig) {
- if (newConfig.EmailSettings.SendEmailNotifications) {
- ErrorStore.clearError(ErrorBarTypes.PREVIEW_MODE);
- }
- }
-
- getStateFromConfig(config) {
- return {
- sendEmailNotifications: config.EmailSettings.SendEmailNotifications,
- feedbackName: config.EmailSettings.FeedbackName,
- feedbackEmail: config.EmailSettings.FeedbackEmail,
- feedbackOrganization: config.EmailSettings.FeedbackOrganization,
- enableSMTPAuth: config.EmailSettings.EnableSMTPAuth,
- smtpUsername: config.EmailSettings.SMTPUsername,
- smtpPassword: config.EmailSettings.SMTPPassword,
- smtpServer: config.EmailSettings.SMTPServer,
- smtpPort: config.EmailSettings.SMTPPort,
- connectionSecurity: config.EmailSettings.ConnectionSecurity,
- enableEmailBatching: config.EmailSettings.EnableEmailBatching,
- skipServerCertificateVerification: config.EmailSettings.SkipServerCertificateVerification,
- enableSecurityFixAlert: config.ServiceSettings.EnableSecurityFixAlert,
- emailNotificationContentsType: config.EmailSettings.EmailNotificationContentsType
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.notifications.email'
- defaultMessage='Email'
- />
- );
- }
-
- renderSettings() {
- let enableEmailBatchingDisabledText = null;
-
- if (this.props.config.ClusterSettings.Enable) {
- enableEmailBatchingDisabledText = (
- <span
- key='admin.email.enableEmailBatching.clusterEnabled'
- className='help-text'
- >
- <FormattedHTMLMessage
- id='admin.email.enableEmailBatching.clusterEnabled'
- defaultMessage='Email batching cannot be enabled unless the SiteURL is configured in <b>Configuration > SiteURL</b>.'
- />
- </span>
- );
- } else if (!this.props.config.ServiceSettings.SiteURL) {
- enableEmailBatchingDisabledText = (
- <span
- key='admin.email.enableEmailBatching.siteURL'
- className='help-text'
- >
- <FormattedHTMLMessage
- id='admin.email.enableEmailBatching.siteURL'
- defaultMessage='Email batching cannot be enabled unless the SiteURL is configured in <b>Configuration > SiteURL</b>.'
- />
- </span>
- );
- }
-
- let emailNotificationContentsTypeDropdown = null;
- let emailNotificationContentsHelpText = null;
- if (window.mm_license.EmailNotificationContents === 'true') {
- const emailNotificationContentsTypes = [];
- emailNotificationContentsTypes.push({value: EMAIL_NOTIFICATION_CONTENTS_FULL, text: Utils.localizeMessage('admin.email.notification.contents.full', 'Send full message contents')});
- emailNotificationContentsTypes.push({value: EMAIL_NOTIFICATION_CONTENTS_GENERIC, text: Utils.localizeMessage('admin.email.notification.contents.generic', 'Send generic description with only sender name')});
-
- if (this.state.emailNotificationContentsType === EMAIL_NOTIFICATION_CONTENTS_FULL) {
- emailNotificationContentsHelpText = (
- <FormattedHTMLMessage
- key='admin.email.notification.contents.full.description'
- id='admin.email.notification.contents.full.description'
- defaultMessage='Sender name and channel are included in email notifications.</br>Typically used for compliance reasons if Mattermost contains confidential information and policy dictates it cannot be stored in email.'
- />
- );
- } else if (this.state.emailNotificationContentsType === EMAIL_NOTIFICATION_CONTENTS_GENERIC) {
- emailNotificationContentsHelpText = (
- <FormattedHTMLMessage
- key='admin.email.notification.contents.generic.description'
- id='admin.email.notification.contents.generic.description'
- defaultMessage='Only the name of the person who sent the message, with no information about channel name or message contents are included in email notifications.</br>Typically used for compliance reasons if Mattermost contains confidential information and policy dictates it cannot be stored in email.'
- />
- );
- }
-
- emailNotificationContentsTypeDropdown = (
- <DropdownSetting
- id='emailNotificationContentsType'
- values={emailNotificationContentsTypes}
- label={
- <FormattedMessage
- id='admin.email.notification.contents.title'
- defaultMessage='Email Notification Contents: '
- />
- }
- value={this.state.emailNotificationContentsType}
- onChange={this.handleChange}
- helpText={emailNotificationContentsHelpText}
- />
- );
- }
-
- return (
- <SettingsGroup>
- <BooleanSetting
- id='sendEmailNotifications'
- label={
- <FormattedMessage
- id='admin.email.notificationsTitle'
- defaultMessage='Enable Email Notifications: '
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.email.notificationsDescription'
- defaultMessage='Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.<br />Setting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).'
- />
- }
- value={this.state.sendEmailNotifications}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableEmailBatching'
- label={
- <FormattedMessage
- id='admin.email.enableEmailBatchingTitle'
- defaultMessage='Enable Email Batching: '
- />
- }
- helpText={[
- <FormattedHTMLMessage
- key='admin.email.enableEmailBatchingDesc'
- id='admin.email.enableEmailBatchingDesc'
- defaultMessage='When true, users will have email notifications for multiple direct messages and mentions combined into a single email. Batching will occur at a default interval of 15 minutes, configurable in Account Settings > Notifications.'
- />,
- enableEmailBatchingDisabledText
- ]}
- value={this.state.enableEmailBatching && !this.props.config.ClusterSettings.Enable && Boolean(this.props.config.ServiceSettings.SiteURL)}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications || this.props.config.ClusterSettings.Enable || !this.props.config.ServiceSettings.SiteURL}
- />
- {emailNotificationContentsTypeDropdown}
- <TextSetting
- id='feedbackName'
- label={
- <FormattedMessage
- id='admin.email.notificationDisplayTitle'
- defaultMessage='Notification Display Name:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.notificationDisplayExample', 'Ex: "Mattermost Notification", "System", "No-Reply"')}
- helpText={
- <FormattedMessage
- id='admin.email.notificationDisplayDescription'
- defaultMessage='Display name on email account used when sending notification emails from Mattermost.'
- />
- }
- value={this.state.feedbackName}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications}
- />
- <TextSetting
- id='feedbackEmail'
- label={
- <FormattedMessage
- id='admin.email.notificationEmailTitle'
- defaultMessage='Notification From Address:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.notificationEmailExample', 'Ex: "mattermost@yourcompany.com", "admin@yourcompany.com"')}
- helpText={
- <FormattedMessage
- id='admin.email.notificationEmailDescription'
- defaultMessage='Email address displayed on email account used when sending notification emails from Mattermost.'
- />
- }
- value={this.state.feedbackEmail}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications}
- />
- <TextSetting
- id='feedbackOrganization'
- label={
- <FormattedMessage
- id='admin.email.notificationOrganization'
- defaultMessage='Notification Footer Mailing Address:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.notificationOrganizationExample', 'Ex: "© ABC Corporation, 565 Knight Way, Palo Alto, California, 94305, USA"')}
- helpText={
- <FormattedMessage
- id='admin.email.notificationOrganizationDescription'
- defaultMessage='Organization name and address displayed on email notifications from Mattermost, such as "© ABC Corporation, 565 Knight Way, Palo Alto, California, 94305, USA". If the field is left empty, the organization name and address will not be displayed.'
- />
- }
- value={this.state.feedbackOrganization}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications}
- />
- <TextSetting
- id='smtpServer'
- label={
- <FormattedMessage
- id='admin.email.smtpServerTitle'
- defaultMessage='SMTP Server:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.smtpServerExample', 'Ex: "smtp.yourcompany.com", "email-smtp.us-east-1.amazonaws.com"')}
- helpText={
- <FormattedMessage
- id='admin.email.smtpServerDescription'
- defaultMessage='Location of SMTP email server.'
- />
- }
- value={this.state.smtpServer}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications}
- />
- <TextSetting
- id='smtpPort'
- label={
- <FormattedMessage
- id='admin.email.smtpPortTitle'
- defaultMessage='SMTP Server Port:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.smtpPortExample', 'Ex: "25", "465", "587"')}
- helpText={
- <FormattedMessage
- id='admin.email.smtpPortDescription'
- defaultMessage='Port of SMTP email server.'
- />
- }
- value={this.state.smtpPort}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications}
- />
- <BooleanSetting
- id='enableSMTPAuth'
- label={
- <FormattedMessage
- id='admin.email.enableSMTPAuthTitle'
- defaultMessage='Enable SMTP Authentication: '
- />
- }
- helpText={[
- <FormattedHTMLMessage
- key='admin.email.enableSMTPAuthDesc'
- id='admin.email.enableSMTPAuthDesc'
- defaultMessage='When true, SMTP Authentication is enabled.'
- />
- ]}
- value={this.state.enableSMTPAuth}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications}
- />
- <TextSetting
- id='smtpUsername'
- label={
- <FormattedMessage
- id='admin.email.smtpUsernameTitle'
- defaultMessage='SMTP Server Username:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.smtpUsernameExample', 'Ex: "admin@yourcompany.com", "AKIADTOVBGERKLCBV"')}
- helpText={
- <FormattedMessage
- id='admin.email.smtpUsernameDescription'
- defaultMessage=' Obtain this credential from administrator setting up your email server.'
- />
- }
- value={this.state.smtpUsername}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications || !this.state.enableSMTPAuth}
- />
- <TextSetting
- id='smtpPassword'
- label={
- <FormattedMessage
- id='admin.email.smtpPasswordTitle'
- defaultMessage='SMTP Server Password:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.smtpPasswordExample', 'Ex: "yourpassword", "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
- helpText={
- <FormattedMessage
- id='admin.email.smtpPasswordDescription'
- defaultMessage=' Obtain this credential from administrator setting up your email server.'
- />
- }
- value={this.state.smtpPassword}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications || !this.state.enableSMTPAuth}
- />
- <ConnectionSecurityDropdownSettingEmail
- value={this.state.connectionSecurity}
- onChange={this.handleChange}
- disabled={!this.state.sendEmailNotifications}
- />
- <EmailConnectionTest
- config={this.props.config}
- getConfigFromState={this.getConfigFromState}
- disabled={!this.state.sendEmailNotifications}
- />
- <BooleanSetting
- id='skipServerCertificateVerification'
- label={
- <FormattedMessage
- id='admin.email.skipServerCertificateVerification.title'
- defaultMessage='Skip Server Certificate Verification: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.email.skipServerCertificateVerification.description'
- defaultMessage='When true, Mattermost will not verify the email server certificate.'
- />
- }
- value={this.state.skipServerCertificateVerification}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableSecurityFixAlert'
- label={
- <FormattedMessage
- id='admin.service.securityTitle'
- defaultMessage='Enable Security Alerts: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.securityDesc'
- defaultMessage='When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.'
- />
- }
- value={this.state.enableSecurityFixAlert}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/external_service_settings.jsx b/webapp/components/admin_console/external_service_settings.jsx
deleted file mode 100644
index 6359470a8..000000000
--- a/webapp/components/admin_console/external_service_settings.jsx
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class ExternalServiceSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.GoogleDeveloperKey = this.state.googleDeveloperKey;
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- googleDeveloperKey: config.ServiceSettings.GoogleDeveloperKey
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.integrations.external'
- defaultMessage='External Services'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <TextSetting
- id='googleDeveloperKey'
- label={
- <FormattedMessage
- id='admin.service.googleTitle'
- defaultMessage='Google API Key:'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.googleExample', 'Ex "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"')}
- helpText={
- <FormattedHTMLMessage
- id='admin.service.googleDescription'
- defaultMessage='Set this key to enable the display of titles for embedded YouTube video previews. Without the key, YouTube previews will still be created based on hyperlinks appearing in messages or comments but they will not show the video title. View a <a href="https://www.youtube.com/watch?v=Im69kzhpR3I" target="_blank">Google Developers Tutorial</a> for instructions on how to obtain a key.'
- />
- }
- value={this.state.googleDeveloperKey}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/file_upload_setting.jsx b/webapp/components/admin_console/file_upload_setting.jsx
deleted file mode 100644
index c2bc9869e..000000000
--- a/webapp/components/admin_console/file_upload_setting.jsx
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import PropTypes from 'prop-types';
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-import Setting from './setting.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-export default class FileUploadSetting extends Setting {
- static get propTypes() {
- return {
- id: PropTypes.string.isRequired,
- label: PropTypes.node.isRequired,
- helpText: PropTypes.node,
- uploadingText: PropTypes.node,
- onSubmit: PropTypes.func.isRequired,
- disabled: PropTypes.bool,
- fileType: PropTypes.string.isRequired,
- error: PropTypes.string
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
-
- this.state = {
- fileName: null,
- serverError: props.error
- };
- }
-
- handleChange() {
- const files = this.refs.fileInput.files;
- if (files && files.length > 0) {
- this.setState({fileSelected: true, fileName: files[0].name});
- }
- }
-
- handleSubmit(e) {
- e.preventDefault();
-
- $(this.refs.upload_button).button('loading');
- this.props.onSubmit(this.props.id, this.refs.fileInput.files[0], (error) => {
- $(this.refs.upload_button).button('reset');
- if (error) {
- Utils.clearFileInput(this.refs.fileInput);
- }
- });
- }
-
- render() {
- let serverError;
- if (this.state.serverError) {
- serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
- }
-
- let btnClass = 'btn';
- if (this.state.fileSelected) {
- btnClass = 'btn btn-primary';
- }
-
- let fileName;
- if (this.state.fileName) {
- fileName = this.state.fileName;
- } else {
- fileName = (
- <FormattedMessage
- id='admin.file_upload.noFile'
- defaultMessage='No file uploaded'
- />
- );
- }
-
- return (
- <Setting
- label={this.props.label}
- helpText={this.props.helpText}
- inputId={this.props.id}
- >
- <div>
- <div className='file__upload'>
- <button
- className='btn btn-default'
- disabled={this.props.disabled}
- >
- <FormattedMessage
- id='admin.file_upload.chooseFile'
- defaultMessage='Choose File'
- />
- </button>
- <input
- ref='fileInput'
- type='file'
- disabled={this.props.disabled}
- accept={this.props.fileType}
- onChange={this.handleChange}
- />
- </div>
- <button
- className={btnClass}
- disabled={!this.state.fileSelected}
- onClick={this.handleSubmit}
- ref='upload_button'
- data-loading-text={`<span class='glyphicon glyphicon-refresh glyphicon-refresh-animate'></span> ${this.props.uploadingText}`}
- >
- <FormattedMessage
- id='admin.file_upload.uploadFile'
- defaultMessage='Upload'
- />
- </button>
- <div className='help-text no-margin'>
- {fileName}
- </div>
- {serverError}
- </div>
- </Setting>
- );
- }
-}
diff --git a/webapp/components/admin_console/generated_setting.jsx b/webapp/components/admin_console/generated_setting.jsx
deleted file mode 100644
index 2fed2f42f..000000000
--- a/webapp/components/admin_console/generated_setting.jsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import crypto from 'crypto';
-
-import {FormattedMessage} from 'react-intl';
-
-export default class GeneratedSetting extends React.Component {
- static get propTypes() {
- return {
- id: PropTypes.string.isRequired,
- label: PropTypes.node.isRequired,
- placeholder: PropTypes.string,
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired,
- disabledText: PropTypes.node,
- helpText: PropTypes.node.isRequired,
- regenerateText: PropTypes.node,
- regenerateHelpText: PropTypes.node
- };
- }
-
- static get defaultProps() {
- return {
- disabled: false,
- regenerateText: (
- <FormattedMessage
- id='admin.regenerate'
- defaultMessage='Regenerate'
- />
- )
- };
- }
-
- constructor(props) {
- super(props);
-
- this.regenerate = this.regenerate.bind(this);
- }
-
- regenerate(e) {
- e.preventDefault();
-
- this.props.onChange(this.props.id, crypto.randomBytes(256).toString('base64').substring(0, 32));
- }
-
- render() {
- let disabledText = null;
- if (this.props.disabled && this.props.disabledText) {
- disabledText = (
- <div className='admin-console__disabled-text'>
- {this.props.disabledText}
- </div>
- );
- }
-
- let regenerateHelpText = null;
- if (this.props.regenerateHelpText) {
- regenerateHelpText = (
- <div className='help-text'>
- {this.props.regenerateHelpText}
- </div>
- );
- }
-
- return (
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor={this.props.id}
- >
- {this.props.label}
- </label>
- <div className='col-sm-8'>
- <input
- type='text'
- className='form-control'
- id={this.props.id}
- placeholder={this.props.placeholder}
- value={this.props.value}
- disabled={true}
- />
- {disabledText}
- <div className='help-text'>
- {this.props.helpText}
- </div>
- <div className='help-text'>
- <button
- className='btn btn-default'
- onClick={this.regenerate}
- disabled={this.props.disabled}
- >
- {this.props.regenerateText}
- </button>
- </div>
- {regenerateHelpText}
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/gitlab_settings.jsx b/webapp/components/admin_console/gitlab_settings.jsx
deleted file mode 100644
index d08597b7d..000000000
--- a/webapp/components/admin_console/gitlab_settings.jsx
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class GitLabSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.GitLabSettings.Enable = this.state.enable;
- config.GitLabSettings.Id = this.state.id;
- config.GitLabSettings.Secret = this.state.secret;
- config.GitLabSettings.UserApiEndpoint = this.state.userApiEndpoint;
- config.GitLabSettings.AuthEndpoint = this.state.authEndpoint;
- config.GitLabSettings.TokenEndpoint = this.state.tokenEndpoint;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enable: config.GitLabSettings.Enable,
- id: config.GitLabSettings.Id,
- secret: config.GitLabSettings.Secret,
- userApiEndpoint: config.GitLabSettings.UserApiEndpoint,
- authEndpoint: config.GitLabSettings.AuthEndpoint,
- tokenEndpoint: config.GitLabSettings.TokenEndpoint
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.authentication.gitlab'
- defaultMessage='GitLab'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enable'
- label={
- <FormattedMessage
- id='admin.gitlab.enableTitle'
- defaultMessage='Enable authentication with GitLab: '
- />
- }
- helpText={
- <div>
- <FormattedMessage
- id='admin.gitlab.enableDescription'
- defaultMessage='When true, Mattermost allows team creation and account signup using GitLab OAuth.'
- />
- <br/>
- <FormattedHTMLMessage
- id='admin.gitlab.EnableHtmlDesc'
- defaultMessage='<ol><li>Log in to your GitLab account and go to Profile Settings -> Applications.</li><li>Enter Redirect URIs "<your-mattermost-url>/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "<your-mattermost-url>/signup/gitlab/complete". </li><li>Then use "Application Secret Key" and "Application ID" fields from GitLab to complete the options below.</li><li>Complete the Endpoint URLs below. </li></ol>'
- />
- </div>
- }
- value={this.state.enable}
- onChange={this.handleChange}
- />
- <TextSetting
- id='id'
- label={
- <FormattedMessage
- id='admin.gitlab.clientIdTitle'
- defaultMessage='Application ID:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.clientIdExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.clientIdDescription'
- defaultMessage='Obtain this value via the instructions above for logging into GitLab'
- />
- }
- value={this.state.id}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='secret'
- label={
- <FormattedMessage
- id='admin.gitlab.clientSecretTitle'
- defaultMessage='Application Secret Key:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.clientSecretExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
- helpText={
- <FormattedMessage
- id='admin.gitab.clientSecretDescription'
- defaultMessage='Obtain this value via the instructions above for logging into GitLab.'
- />
- }
- value={this.state.secret}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='userApiEndpoint'
- label={
- <FormattedMessage
- id='admin.gitlab.userTitle'
- defaultMessage='User API Endpoint:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.userExample', 'Ex "https://<your-gitlab-url>/api/v3/user"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.userDescription'
- defaultMessage='Enter https://<your-gitlab-url>/api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- }
- value={this.state.userApiEndpoint}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='authEndpoint'
- label={
- <FormattedMessage
- id='admin.gitlab.authTitle'
- defaultMessage='Auth Endpoint:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.authExample', 'Ex "https://<your-gitlab-url>/oauth/authorize"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.authDescription'
- defaultMessage='Enter https://<your-gitlab-url>/oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- }
- value={this.state.authEndpoint}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='tokenEndpoint'
- label={
- <FormattedMessage
- id='admin.gitlab.tokenTitle'
- defaultMessage='Token Endpoint:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.tokenExample', 'Ex "https://<your-gitlab-url>/oauth/token"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.tokenDescription'
- defaultMessage='Enter https://<your-gitlab-url>/oauth/token. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- }
- value={this.state.tokenEndpoint}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/index.js b/webapp/components/admin_console/index.js
deleted file mode 100644
index 4b333e65c..000000000
--- a/webapp/components/admin_console/index.js
+++ /dev/null
@@ -1,27 +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 {getConfig} from 'mattermost-redux/actions/admin';
-
-import * as Selectors from 'mattermost-redux/selectors/entities/admin';
-
-import AdminConsole from './admin_console.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- config: Selectors.getConfig(state)
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getConfig
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(AdminConsole);
diff --git a/webapp/components/admin_console/ldap_settings.jsx b/webapp/components/admin_console/ldap_settings.jsx
deleted file mode 100644
index 9ffbe3b0e..000000000
--- a/webapp/components/admin_console/ldap_settings.jsx
+++ /dev/null
@@ -1,504 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {ConnectionSecurityDropdownSettingLdap} from './connection_security_dropdown_setting.jsx';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-import {ldapSyncNow, ldapTest} from 'actions/admin_actions.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-import RequestButton from './request_button/request_button.jsx';
-
-export default class LdapSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.LdapSettings.Enable = this.state.enable;
- config.LdapSettings.LdapServer = this.state.ldapServer;
- config.LdapSettings.LdapPort = this.parseIntNonZero(this.state.ldapPort);
- config.LdapSettings.ConnectionSecurity = this.state.connectionSecurity;
- config.LdapSettings.BaseDN = this.state.baseDN;
- config.LdapSettings.BindUsername = this.state.bindUsername;
- config.LdapSettings.BindPassword = this.state.bindPassword;
- config.LdapSettings.UserFilter = this.state.userFilter;
- config.LdapSettings.FirstNameAttribute = this.state.firstNameAttribute;
- config.LdapSettings.LastNameAttribute = this.state.lastNameAttribute;
- config.LdapSettings.NicknameAttribute = this.state.nicknameAttribute;
- config.LdapSettings.EmailAttribute = this.state.emailAttribute;
- config.LdapSettings.UsernameAttribute = this.state.usernameAttribute;
- config.LdapSettings.PositionAttribute = this.state.positionAttribute;
- config.LdapSettings.IdAttribute = this.state.idAttribute;
- config.LdapSettings.SyncIntervalMinutes = this.parseIntNonZero(this.state.syncIntervalMinutes);
- config.LdapSettings.SkipCertificateVerification = this.state.skipCertificateVerification;
- config.LdapSettings.QueryTimeout = this.parseIntNonZero(this.state.queryTimeout);
- config.LdapSettings.MaxPageSize = this.parseInt(this.state.maxPageSize);
- config.LdapSettings.LoginFieldName = this.state.loginFieldName;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enable: config.LdapSettings.Enable,
- ldapServer: config.LdapSettings.LdapServer,
- ldapPort: config.LdapSettings.LdapPort,
- connectionSecurity: config.LdapSettings.ConnectionSecurity,
- baseDN: config.LdapSettings.BaseDN,
- bindUsername: config.LdapSettings.BindUsername,
- bindPassword: config.LdapSettings.BindPassword,
- userFilter: config.LdapSettings.UserFilter,
- firstNameAttribute: config.LdapSettings.FirstNameAttribute,
- lastNameAttribute: config.LdapSettings.LastNameAttribute,
- nicknameAttribute: config.LdapSettings.NicknameAttribute,
- emailAttribute: config.LdapSettings.EmailAttribute,
- usernameAttribute: config.LdapSettings.UsernameAttribute,
- positionAttribute: config.LdapSettings.PositionAttribute,
- idAttribute: config.LdapSettings.IdAttribute,
- syncIntervalMinutes: config.LdapSettings.SyncIntervalMinutes,
- skipCertificateVerification: config.LdapSettings.SkipCertificateVerification,
- queryTimeout: config.LdapSettings.QueryTimeout,
- maxPageSize: config.LdapSettings.MaxPageSize,
- loginFieldName: config.LdapSettings.LoginFieldName
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.authentication.ldap'
- defaultMessage='AD/LDAP'
- />
- );
- }
-
- renderSettings() {
- const licenseEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.LDAP === 'true';
- if (!licenseEnabled) {
- return null;
- }
-
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enable'
- label={
- <FormattedMessage
- id='admin.ldap.enableTitle'
- defaultMessage='Enable sign-in with AD/LDAP:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.ldap.enableDesc'
- defaultMessage='When true, Mattermost allows login using AD/LDAP'
- />
- }
- value={this.state.enable}
- onChange={this.handleChange}
- />
- <TextSetting
- id='ldapServer'
- label={
- <FormattedMessage
- id='admin.ldap.serverTitle'
- defaultMessage='AD/LDAP Server:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.serverEx', 'Ex "10.0.0.23"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.serverDesc'
- defaultMessage='The domain or IP address of AD/LDAP server.'
- />
- }
- value={this.state.ldapServer}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='ldapPort'
- label={
- <FormattedMessage
- id='admin.ldap.portTitle'
- defaultMessage='AD/LDAP Port:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.portEx', 'Ex "389"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.portDesc'
- defaultMessage='The port Mattermost will use to connect to the AD/LDAP server. Default is 389.'
- />
- }
- value={this.state.ldapPort}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <ConnectionSecurityDropdownSettingLdap
- value={this.state.connectionSecurity}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <BooleanSetting
- id='skipCertificateVerification'
- label={
- <FormattedMessage
- id='admin.ldap.skipCertificateVerification'
- defaultMessage='Skip Certificate Verification:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.ldap.skipCertificateVerificationDesc'
- defaultMessage='Skips the certificate verification step for TLS or STARTTLS connections. Not recommended for production environments where TLS is required. For testing only.'
- />
- }
- value={this.state.skipCertificateVerification}
- onChange={this.handleChange}
- />
- <TextSetting
- id='baseDN'
- label={
- <FormattedMessage
- id='admin.ldap.baseTitle'
- defaultMessage='BaseDN:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.baseEx', 'Ex "ou=Unit Name,dc=corp,dc=example,dc=com"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.baseDesc'
- defaultMessage='The Base DN is the Distinguished Name of the location where Mattermost should start its search for users in the AD/LDAP tree.'
- />
- }
- value={this.state.baseDN}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='bindUsername'
- label={
- <FormattedMessage
- id='admin.ldap.bindUserTitle'
- defaultMessage='Bind Username:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.ldap.bindUserDesc'
- defaultMessage='The username used to perform the AD/LDAP search. This should typically be an account created specifically for use with Mattermost. It should have access limited to read the portion of the AD/LDAP tree specified in the BaseDN field.'
- />
- }
- value={this.state.bindUsername}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='bindPassword'
- label={
- <FormattedMessage
- id='admin.ldap.bindPwdTitle'
- defaultMessage='Bind Password:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.ldap.bindPwdDesc'
- defaultMessage='Password of the user given in "Bind Username".'
- />
- }
- value={this.state.bindPassword}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='userFilter'
- label={
- <FormattedMessage
- id='admin.ldap.userFilterTitle'
- defaultMessage='User Filter:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.userFilterEx', 'Ex. "(objectClass=user)"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.userFilterDisc'
- defaultMessage='(Optional) Enter an AD/LDAP Filter to use when searching for user objects. Only the users selected by the query will be able to access Mattermost. For Active Directory, the query to filter out disabled users is (&(objectCategory=Person)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))).'
- />
- }
- value={this.state.userFilter}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='firstNameAttribute'
- label={
- <FormattedMessage
- id='admin.ldap.firstnameAttrTitle'
- defaultMessage='First Name Attribute'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.firstnameAttrEx', 'Ex "givenName"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.firstnameAttrDesc'
- defaultMessage='(Optional) The attribute in the AD/LDAP server that will be used to populate the first name of users in Mattermost. When set, users will not be able to edit their first name, since it is synchronized with the LDAP server. When left blank, users can set their own first name in Account Settings.'
- />
- }
- value={this.state.firstNameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='lastNameAttribute'
- label={
- <FormattedMessage
- id='admin.ldap.lastnameAttrTitle'
- defaultMessage='Last Name Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.lastnameAttrEx', 'Ex "sn"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.lastnameAttrDesc'
- defaultMessage='(Optional) The attribute in the AD/LDAP server that will be used to populate the last name of users in Mattermost. When set, users will not be able to edit their last name, since it is synchronized with the LDAP server. When left blank, users can set their own last name in Account Settings.'
- />
- }
- value={this.state.lastNameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='nicknameAttribute'
- label={
- <FormattedMessage
- id='admin.ldap.nicknameAttrTitle'
- defaultMessage='Nickname Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.nicknameAttrEx', 'Ex "nickname"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.nicknameAttrDesc'
- defaultMessage='(Optional) The attribute in the AD/LDAP server that will be used to populate the nickname of users in Mattermost. When set, users will not be able to edit their nickname, since it is synchronized with the LDAP server. When left blank, users can set their own nickname in Account Settings.'
- />
- }
- value={this.state.nicknameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='positionAttribute'
- label={
- <FormattedMessage
- id='admin.ldap.positionAttrTitle'
- defaultMessage='Position Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.positionAttrEx', 'E.g.: "title"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.positionAttrDesc'
- defaultMessage='(Optional) The attribute in the AD/LDAP server that will be used to populate the position field in Mattermost.'
- />
- }
- value={this.state.positionAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='emailAttribute'
- label={
- <FormattedMessage
- id='admin.ldap.emailAttrTitle'
- defaultMessage='Email Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.emailAttrEx', 'Ex "mail" or "userPrincipalName"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.emailAttrDesc'
- defaultMessage='The attribute in the AD/LDAP server that will be used to populate the email addresses of users in Mattermost.'
- />
- }
- value={this.state.emailAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='usernameAttribute'
- label={
- <FormattedMessage
- id='admin.ldap.usernameAttrTitle'
- defaultMessage='Username Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.usernameAttrEx', 'Ex "sAMAccountName"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.uernameAttrDesc'
- defaultMessage='The attribute in the AD/LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.'
- />
- }
- value={this.state.usernameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='idAttribute'
- label={
- <FormattedMessage
- id='admin.ldap.idAttrTitle'
- defaultMessage='ID Attribute: '
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.idAttrEx', 'Ex "sAMAccountName"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.idAttrDesc'
- defaultMessage='The attribute in the AD/LDAP server that will be used as a unique identifier in Mattermost. It should be an AD/LDAP attribute with a value that does not change, such as username or uid. If a user’s ID Attribute changes, it will create a new Mattermost account unassociated with their old one. This is the value used to log in to Mattermost in the "AD/LDAP Username" field on the sign in page. Normally this attribute is the same as the "Username Attribute" field above. If your team typically uses domain\\username to sign in to other services with AD/LDAP, you may choose to put domain\\username in this field to maintain consistency between sites.'
- />
- }
- value={this.state.idAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='loginFieldName'
- label={
- <FormattedMessage
- id='admin.ldap.loginNameTitle'
- defaultMessage='Sign-in Field Default Text:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.loginNameEx', 'Ex "AD/LDAP Username"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.loginNameDesc'
- defaultMessage='The placeholder text that appears in the login field on the login page. Defaults to "AD/LDAP Username".'
- />
- }
- value={this.state.loginFieldName}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='syncIntervalMinutes'
- label={
- <FormattedMessage
- id='admin.ldap.syncIntervalTitle'
- defaultMessage='Synchronization Interval (minutes):'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.ldap.syncIntervalHelpText'
- defaultMessage='AD/LDAP Synchronization updates Mattermost user information to reflect updates on the AD/LDAP server. For example, when a user’s name changes on the AD/LDAP server, the change updates in Mattermost when synchronization is performed. Accounts removed from or disabled in the AD/LDAP server have their Mattermost accounts set to "Inactive" and have their account sessions revoked. Mattermost performs synchronization on the interval entered. For example, if 60 is entered, Mattermost synchronizes every 60 minutes.'
- />
- }
- value={this.state.syncIntervalMinutes}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='maxPageSize'
- label={
- <FormattedMessage
- id='admin.ldap.maxPageSizeTitle'
- defaultMessage='Maximum Page Size:'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.maxPageSizeEx', 'Ex "2000"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.maxPageSizeHelpText'
- defaultMessage='The maximum number of users the Mattermost server will request from the AD/LDAP server at one time. 0 is unlimited.'
- />
- }
- value={this.state.maxPageSize}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='queryTimeout'
- label={
- <FormattedMessage
- id='admin.ldap.queryTitle'
- defaultMessage='Query Timeout (seconds):'
- />
- }
- placeholder={Utils.localizeMessage('admin.ldap.queryEx', 'Ex "60"')}
- helpText={
- <FormattedMessage
- id='admin.ldap.queryDesc'
- defaultMessage='The timeout value for queries to the AD/LDAP server. Increase if you are getting timeout errors caused by a slow AD/LDAP server.'
- />
- }
- value={this.state.queryTimeout}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <RequestButton
- requestAction={ldapSyncNow}
- helpText={
- <FormattedMessage
- id='admin.ldap.syncNowHelpText'
- defaultMessage='Initiates an AD/LDAP synchronization immediately.'
- />
- }
- buttonText={
- <FormattedMessage
- id='admin.ldap.sync_button'
- defaultMessage='AD/LDAP Synchronize Now'
- />
- }
- disabled={!this.state.enable}
- showSuccessMessage={false}
- errorMessage={{
- id: 'admin.ldap.syncFailure',
- defaultMessage: 'Sync Failure: {error}'
- }}
- includeDetailedError={true}
- />
- <RequestButton
- requestAction={ldapTest}
- helpText={
- <FormattedMessage
- id='admin.ldap.testHelpText'
- defaultMessage='Tests if the Mattermost server can connect to the AD/LDAP server specified. See log file for more detailed error messages.'
- />
- }
- buttonText={
- <FormattedMessage
- id='admin.ldap.ldap_test_button'
- defaultMessage='AD/LDAP Test'
- />
- }
- disabled={!this.state.enable}
- saveNeeded={this.state.saveNeeded}
- saveConfigAction={this.doSubmit}
- errorMessage={{
- id: 'admin.ldap.testFailure',
- defaultMessage: 'AD/LDAP Test Failure: {error}'
- }}
- successMessage={{
- id: 'admin.ldap.testSuccess',
- defaultMessage: 'AD/LDAP Test Successful'
- }}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/legal_and_support_settings.jsx b/webapp/components/admin_console/legal_and_support_settings.jsx
deleted file mode 100644
index 6b64e0c07..000000000
--- a/webapp/components/admin_console/legal_and_support_settings.jsx
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class LegalAndSupportSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.SupportSettings.TermsOfServiceLink = this.state.termsOfServiceLink;
- config.SupportSettings.PrivacyPolicyLink = this.state.privacyPolicyLink;
- config.SupportSettings.AboutLink = this.state.aboutLink;
- config.SupportSettings.HelpLink = this.state.helpLink;
- config.SupportSettings.ReportAProblemLink = this.state.reportAProblemLink;
- config.SupportSettings.SupportEmail = this.state.supportEmail;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- termsOfServiceLink: config.SupportSettings.TermsOfServiceLink,
- privacyPolicyLink: config.SupportSettings.PrivacyPolicyLink,
- aboutLink: config.SupportSettings.AboutLink,
- helpLink: config.SupportSettings.HelpLink,
- reportAProblemLink: config.SupportSettings.ReportAProblemLink,
- supportEmail: config.SupportSettings.SupportEmail
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.customization.support'
- defaultMessage='Legal and Support'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <TextSetting
- id='termsOfServiceLink'
- label={
- <FormattedMessage
- id='admin.support.termsTitle'
- defaultMessage='Terms of Service link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.support.termsDesc'
- defaultMessage='Link to the terms under which users may use your online service. By default, this includes the "Mattermost Conditions of Use (End Users)" explaining the terms under which Mattermost software is provided to end users. If you change the default link to add your own terms for using the service you provide, your new terms must include a link to the default terms so end users are aware of the Mattermost Conditions of Use (End User) for Mattermost software.'
- />
- }
- value={this.state.termsOfServiceLink}
- onChange={this.handleChange}
- />
- <TextSetting
- id='privacyPolicyLink'
- label={
- <FormattedMessage
- id='admin.support.privacyTitle'
- defaultMessage='Privacy Policy link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.support.privacyDesc'
- defaultMessage='The URL for the Privacy link on the login and sign-up pages. If this field is empty, the Privacy link is hidden from users.'
- />
- }
- value={this.state.privacyPolicyLink}
- onChange={this.handleChange}
- />
- <TextSetting
- id='aboutLink'
- label={
- <FormattedMessage
- id='admin.support.aboutTitle'
- defaultMessage='About link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.support.aboutDesc'
- defaultMessage='The URL for the About link on the Mattermost login and sign-up pages. If this field is empty, the About link is hidden from users.'
- />
- }
- value={this.state.aboutLink}
- onChange={this.handleChange}
- />
- <TextSetting
- id='helpLink'
- label={
- <FormattedMessage
- id='admin.support.helpTitle'
- defaultMessage='Help link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.support.helpDesc'
- defaultMessage='The URL for the Help link on the Mattermost login page, sign-up pages, and Main Menu. If this field is empty, the Help link is hidden from users.'
- />
- }
- value={this.state.helpLink}
- onChange={this.handleChange}
- />
- <TextSetting
- id='reportAProblemLink'
- label={
- <FormattedMessage
- id='admin.support.problemTitle'
- defaultMessage='Report a Problem link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.support.problemDesc'
- defaultMessage='The URL for the Report a Problem link in the Main Menu. If this field is empty, the link is removed from the Main Menu.'
- />
- }
- value={this.state.reportAProblemLink}
- onChange={this.handleChange}
- />
- <TextSetting
- id='supportEmail'
- label={
- <FormattedMessage
- id='admin.support.emailTitle'
- defaultMessage='Support Email:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.support.emailHelp'
- defaultMessage='Email address displayed on email notifications and during tutorial for end users to ask support questions.'
- />
- }
- value={this.state.supportEmail}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/license_settings.jsx b/webapp/components/admin_console/license_settings.jsx
deleted file mode 100644
index f04a0c351..000000000
--- a/webapp/components/admin_console/license_settings.jsx
+++ /dev/null
@@ -1,286 +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 * as Utils from 'utils/utils.jsx';
-
-import ErrorStore from 'stores/error_store.jsx';
-import {uploadLicenseFile, removeLicenseFile} from 'actions/admin_actions.jsx';
-
-import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-const holders = defineMessages({
- removing: {
- id: 'admin.license.removing',
- defaultMessage: 'Removing License...'
- },
- uploading: {
- id: 'admin.license.uploading',
- defaultMessage: 'Uploading License...'
- }
-});
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-class LicenseSettings extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- this.handleRemove = this.handleRemove.bind(this);
-
- this.state = {
- fileSelected: false,
- fileName: null,
- serverError: null
- };
- }
-
- handleChange() {
- const element = $(ReactDOM.findDOMNode(this.refs.fileInput));
- if (element.prop('files').length > 0) {
- this.setState({fileSelected: true, fileName: element.prop('files')[0].name});
- }
- }
-
- handleSubmit(e) {
- e.preventDefault();
-
- const element = $(ReactDOM.findDOMNode(this.refs.fileInput));
- if (element.prop('files').length === 0) {
- return;
- }
- const file = element.prop('files')[0];
-
- $('#upload-button').button('loading');
-
- uploadLicenseFile(
- file,
- () => {
- Utils.clearFileInput(element[0]);
- $('#upload-button').button('reset');
- this.setState({fileSelected: false, fileName: null, serverError: null});
- window.location.reload(true);
- },
- (error) => {
- Utils.clearFileInput(element[0]);
- $('#upload-button').button('reset');
- this.setState({fileSelected: false, fileName: null, serverError: error.message});
- }
- );
- }
-
- handleRemove(e) {
- e.preventDefault();
-
- $('#remove-button').button('loading');
-
- removeLicenseFile(
- () => {
- $('#remove-button').button('reset');
- this.setState({fileSelected: false, fileName: null, serverError: null});
- ErrorStore.clearLastError(true);
- window.location.reload(true);
- },
- (error) => {
- $('#remove-button').button('reset');
- this.setState({fileSelected: false, fileName: null, serverError: error.message});
- }
- );
- }
-
- render() {
- var serverError = '';
- if (this.state.serverError) {
- serverError = <div className='col-sm-12'><div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div></div>;
- }
-
- var btnClass = 'btn';
- if (this.state.fileSelected) {
- btnClass = 'btn btn-primary';
- }
-
- let edition;
- let licenseType;
- let licenseKey;
-
- const issued = Utils.displayDate(parseInt(global.window.mm_license.IssuedAt, 10)) + ' ' + Utils.displayTime(parseInt(global.window.mm_license.IssuedAt, 10), true);
- const startsAt = Utils.displayDate(parseInt(global.window.mm_license.StartsAt, 10));
- const expiresAt = Utils.displayDate(parseInt(global.window.mm_license.ExpiresAt, 10));
-
- if (global.window.mm_license.IsLicensed === 'true') {
- // Note: DO NOT LOCALISE THESE STRINGS. Legally we can not since the license is in English.
- edition = 'Mattermost Enterprise Edition. Enterprise features on this server have been unlocked with a license key and a valid subscription.';
- licenseType = (
- <div>
- <p>
- {'This software is offered under a commercial license.\n\nSee ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. See NOTICE.txt for information about open source software used in this system.\n\nYour subscription details are as follows:'}
- </p>
- {`Name: ${global.window.mm_license.Name}`}<br/>
- {`Company or organization name: ${global.window.mm_license.Company}`}<br/>
- {`Number of users: ${global.window.mm_license.Users}`}<br/>
- {`License issued: ${issued}`}<br/>
- {`Start date of license: ${startsAt}`}<br/>
- {`Expiry date of license: ${expiresAt}`}<br/>
- <br/>
- {'See also '}<a href='https://about.mattermost.com/enterprise-edition-terms/'>{'Enterprise Edition Terms of Service'}</a>{' and '}<a href='https://about.mattermost.com/privacy/'>{'Privacy Policy.'}</a>
- </div>
- );
-
- licenseKey = (
- <div className='col-sm-8'>
- <button
- className='btn btn-danger'
- onClick={this.handleRemove}
- id='remove-button'
- data-loading-text={'<span class=\'fa fa-refresh icon--rotate\'></span> ' + this.props.intl.formatMessage(holders.removing)}
- >
- <FormattedMessage
- id='admin.license.keyRemove'
- defaultMessage='Remove Enterprise License and Downgrade Server'
- />
- </button>
- <br/>
- <br/>
- <p className='help-text'>
- {'If you migrate servers you may need to remove your license key to install it elsewhere. You can remove the key here, which will revert functionality to that of Team Edition.'}
- </p>
- </div>
- );
- } else {
- // Note: DO NOT LOCALISE THESE STRINGS. Legally we can not since the license is in English.
- edition = (
- <p>
- {'Mattermost Enterprise Edition. Unlock enterprise features in this software through the purchase of a subscription from '}
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='https://mattermost.com/'
- >
- {'https://mattermost.com/'}
- </a>
- </p>
- );
-
- licenseType = 'This software is offered under a commercial license.\n\nSee ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. See NOTICE.txt for information about open source software used in this system.';
-
- let fileName;
- if (this.state.fileName) {
- fileName = this.state.fileName;
- } else {
- fileName = (
- <FormattedMessage
- id='admin.license.noFile'
- defaultMessage='No file uploaded'
- />
- );
- }
-
- licenseKey = (
- <div className='col-sm-8'>
- <div className='file__upload'>
- <button className='btn btn-primary'>
- <FormattedMessage
- id='admin.license.choose'
- defaultMessage='Choose File'
- />
- </button>
- <input
- ref='fileInput'
- type='file'
- accept='.mattermost-license'
- onChange={this.handleChange}
- />
- </div>
- <button
- className={btnClass}
- disabled={!this.state.fileSelected}
- onClick={this.handleSubmit}
- id='upload-button'
- data-loading-text={'<span class=\'fa fa-refresh icon--rotate\'></span> ' + this.props.intl.formatMessage(holders.uploading)}
- >
- <FormattedMessage
- id='admin.license.upload'
- defaultMessage='Upload'
- />
- </button>
- <div className='help-text no-margin'>
- {fileName}
- </div>
- <br/>
- {serverError}
- <p className='help-text no-margin'>
- <FormattedHTMLMessage
- id='admin.license.uploadDesc'
- defaultMessage='Upload a license key for Mattermost Enterprise Edition to upgrade this server. <a href="http://mattermost.com" target="_blank">Visit us online</a> to learn more about the benefits of Enterprise Edition or to purchase a key.'
- />
- </p>
- </div>
- );
- }
-
- return (
- <div className='wrapper--fixed'>
- <h3 className='admin-console-header'>
- <FormattedMessage
- id='admin.license.title'
- defaultMessage='Edition and License'
- />
- </h3>
- <form
- className='form-horizontal'
- role='form'
- >
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- >
- <FormattedMessage
- id='admin.license.edition'
- defaultMessage='Edition: '
- />
- </label>
- <div className='col-sm-8'>
- {edition}
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- >
- <FormattedMessage
- id='admin.license.type'
- defaultMessage='License: '
- />
- </label>
- <div className='col-sm-8'>
- {licenseType}
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- >
- <FormattedMessage
- id='admin.license.key'
- defaultMessage='License Key: '
- />
- </label>
- {licenseKey}
- </div>
- </form>
- </div>
- );
- }
-}
-
-LicenseSettings.propTypes = {
- intl: intlShape.isRequired,
- config: PropTypes.object
-};
-
-export default injectIntl(LicenseSettings);
diff --git a/webapp/components/admin_console/link_previews_settings.jsx b/webapp/components/admin_console/link_previews_settings.jsx
deleted file mode 100644
index b120d75d2..000000000
--- a/webapp/components/admin_console/link_previews_settings.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-
-export default class LinkPreviewsSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.EnableLinkPreviews = this.state.enableLinkPreviews;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableLinkPreviews: config.ServiceSettings.EnableLinkPreviews
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.customization.linkPreviews'
- defaultMessage='Link Previews'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableLinkPreviews'
- label={
- <FormattedMessage
- id='admin.customization.enableLinkPreviewsTitle'
- defaultMessage='Enable Link Previews:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.customization.enableLinkPreviewsDesc'
- defaultMessage='Enable users to display a preview of website content below the message, if available. When true, website previews can be enabled from Account Settings > Advanced > Preview pre-release features.'
- />
- }
- value={this.state.enableLinkPreviews}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/localization_settings.jsx b/webapp/components/admin_console/localization_settings.jsx
deleted file mode 100644
index 78b63b163..000000000
--- a/webapp/components/admin_console/localization_settings.jsx
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as I18n from 'i18n/i18n.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import MultiSelectSetting from './multiselect_settings.jsx';
-
-export default class LocalizationSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- this.canSave = this.canSave.bind(this);
-
- const locales = I18n.getAllLanguages();
-
- this.state = Object.assign(this.state, {
- hasErrors: false,
- languages: Object.keys(locales).map((l) => {
- return {value: locales[l].value, text: locales[l].name, order: locales[l].order};
- }).sort((a, b) => a.order - b.order)
- });
- }
-
- canSave() {
- return this.state.availableLocales.join(',').indexOf(this.state.defaultClientLocale) !== -1 || this.state.availableLocales.length === 0;
- }
-
- getConfigFromState(config) {
- config.LocalizationSettings.DefaultServerLocale = this.state.defaultServerLocale;
- config.LocalizationSettings.DefaultClientLocale = this.state.defaultClientLocale;
- config.LocalizationSettings.AvailableLocales = this.state.availableLocales.join(',');
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- defaultServerLocale: config.LocalizationSettings.DefaultServerLocale,
- defaultClientLocale: config.LocalizationSettings.DefaultClientLocale,
- availableLocales: config.LocalizationSettings.AvailableLocales ? config.LocalizationSettings.AvailableLocales.split(',') : []
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.general.localization'
- defaultMessage='Localization'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <DropdownSetting
- id='defaultServerLocale'
- values={this.state.languages}
- label={
- <FormattedMessage
- id='admin.general.localization.serverLocaleTitle'
- defaultMessage='Default Server Language:'
- />
- }
- value={this.state.defaultServerLocale}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.localization.serverLocaleDescription'
- defaultMessage='Default language for system messages and logs. Changing this will require a server restart before taking effect.'
- />
- }
- />
- <DropdownSetting
- id='defaultClientLocale'
- values={this.state.languages}
- label={
- <FormattedMessage
- id='admin.general.localization.clientLocaleTitle'
- defaultMessage='Default Client Language:'
- />
- }
- value={this.state.defaultClientLocale}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.localization.clientLocaleDescription'
- defaultMessage="Default language for newly created users and pages where the user hasn't logged in."
- />
- }
- />
- <MultiSelectSetting
- id='availableLocales'
- values={this.state.languages}
- label={
- <FormattedMessage
- id='admin.general.localization.availableLocalesTitle'
- defaultMessage='Available Languages:'
- />
- }
- selected={this.state.availableLocales}
- onChange={this.handleChange}
- helpText={
- <FormattedHTMLMessage
- id='admin.general.localization.availableLocalesDescription'
- defaultMessage='Set which languages are available for users in Account Settings (leave this field blank to have all supported languages available). If you’re manually adding new languages, the <strong>Default Client Language</strong> must be added before saving this setting.<br /><br />Would like to help with translations? Join the <a href="http://translate.mattermost.com/" target="_blank">Mattermost Translation Server</a> to contribute.'
- />
- }
- noResultText={
- <FormattedMessage
- id='admin.general.localization.availableLocalesNoResults'
- defaultMessage='No results found'
- />
- }
- notPresent={
- <FormattedMessage
- id='admin.general.localization.availableLocalesNotPresent'
- defaultMessage='The default client language must be included in the available list'
- />
- }
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/log_settings.jsx b/webapp/components/admin_console/log_settings.jsx
deleted file mode 100644
index 8e1e4891e..000000000
--- a/webapp/components/admin_console/log_settings.jsx
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class LogSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.LogSettings.EnableConsole = this.state.enableConsole;
- config.LogSettings.ConsoleLevel = this.state.consoleLevel;
- config.LogSettings.EnableFile = this.state.enableFile;
- config.LogSettings.FileLevel = this.state.fileLevel;
- config.LogSettings.FileLocation = this.state.fileLocation;
- config.LogSettings.FileFormat = this.state.fileFormat;
- config.LogSettings.EnableWebhookDebugging = this.state.enableWebhookDebugging;
- config.LogSettings.EnableDiagnostics = this.state.enableDiagnostics;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableConsole: config.LogSettings.EnableConsole,
- consoleLevel: config.LogSettings.ConsoleLevel,
- enableFile: config.LogSettings.EnableFile,
- fileLevel: config.LogSettings.FileLevel,
- fileLocation: config.LogSettings.FileLocation,
- fileFormat: config.LogSettings.FileFormat,
- enableWebhookDebugging: config.LogSettings.EnableWebhookDebugging,
- enableDiagnostics: config.LogSettings.EnableDiagnostics
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.general.log'
- defaultMessage='Logging'
- />
- );
- }
-
- renderSettings() {
- const logLevels = [
- {value: 'DEBUG', text: 'DEBUG'},
- {value: 'INFO', text: 'INFO'},
- {value: 'ERROR', text: 'ERROR'}
- ];
-
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableConsole'
- label={
- <FormattedMessage
- id='admin.log.consoleTitle'
- defaultMessage='Output logs to console: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.log.consoleDescription'
- defaultMessage='Typically set to false in production. Developers may set this field to true to output log messages to console based on the console level option. If true, server writes messages to the standard output stream (stdout).'
- />
- }
- value={this.state.enableConsole}
- onChange={this.handleChange}
- />
- <DropdownSetting
- id='consoleLevel'
- values={logLevels}
- label={
- <FormattedMessage
- id='admin.log.levelTitle'
- defaultMessage='Console Log Level:'
- />
- }
- value={this.state.consoleLevel}
- onChange={this.handleChange}
- disabled={!this.state.enableConsole}
- helpText={
- <FormattedMessage
- id='admin.log.levelDescription'
- defaultMessage='This setting determines the level of detail at which log events are written to the console. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'
- />
- }
- />
- <BooleanSetting
- id='enableFile'
- label={
- <FormattedMessage
- id='admin.log.fileTitle'
- defaultMessage='Output logs to file: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.log.fileDescription'
- defaultMessage='Typically set to true in production. When true, logged events are written to the mattermost.log file in the directory specified in the File Log Directory field. The logs are rotated at 10,000 lines and archived to a file in the same directory, and given a name with a datestamp and serial number. For example, mattermost.2017-03-31.001.'
- />
- }
- value={this.state.enableFile}
- onChange={this.handleChange}
- />
- <DropdownSetting
- id='fileLevel'
- values={logLevels}
- label={
- <FormattedMessage
- id='admin.log.fileLevelTitle'
- defaultMessage='File Log Level:'
- />
- }
- value={this.state.fileLevel}
- onChange={this.handleChange}
- disabled={!this.state.enableFile}
- helpText={
- <FormattedMessage
- id='admin.log.fileLevelDescription'
- defaultMessage='This setting determines the level of detail at which log events are written to the log file. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'
- />
- }
- />
- <TextSetting
- id='fileLocation'
- label={
- <FormattedMessage
- id='admin.log.locationTitle'
- defaultMessage='File Log Directory:'
- />
- }
- placeholder={Utils.localizeMessage('admin.log.locationPlaceholder', 'Enter your file location')}
- helpText={
- <FormattedMessage
- id='admin.log.locationDescription'
- defaultMessage='The location of the log files. If blank, they are stored in the ./logs directory. The path that you set must exist and Mattermost must have write permissions in it.'
- />
- }
- value={this.state.fileLocation}
- onChange={this.handleChange}
- disabled={!this.state.enableFile}
- />
- <TextSetting
- id='fileFormat'
- label={
- <FormattedMessage
- id='admin.log.formatTitle'
- defaultMessage='File Log Format:'
- />
- }
- placeholder={Utils.localizeMessage('admin.log.formatPlaceholder', 'Enter your file format')}
- helpText={this.renderFileFormatHelpText()}
- value={this.state.fileFormat}
- onChange={this.handleChange}
- disabled={!this.state.enableFile}
- />
- <BooleanSetting
- id='enableWebhookDebugging'
- label={
- <FormattedMessage
- id='admin.log.enableWebhookDebugging'
- defaultMessage='Enable Webhook Debugging:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.log.enableWebhookDebuggingDescription'
- defaultMessage='You can set this to false to disable the debug logging of all incoming webhook request bodies.'
- />
- }
- value={this.state.enableWebhookDebugging}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableDiagnostics'
- label={
- <FormattedMessage
- id='admin.log.enableDiagnostics'
- defaultMessage='Enable Diagnostics and Error Reporting:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.log.enableDiagnosticsDescription'
- defaultMessage='Enable this feature to improve the quality and performance of Mattermost by sending error reporting and diagnostic information to Mattermost, Inc. Read our <a href="https://about.mattermost.com/default-privacy-policy/" target="_blank">privacy policy</a> to learn more.'
- />
- }
- value={this.state.enableDiagnostics}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-
- renderFileFormatHelpText() {
- return (
- <div>
- <FormattedMessage
- id='admin.log.formatDescription'
- defaultMessage='Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'
- />
- <table
- className='table table-bordered'
- cellPadding='5'
- >
- <tbody>
- <tr>
- <td>{'%T'}</td>
- <td>
- <FormattedMessage
- id='admin.log.formatTime'
- defaultMessage='Time (15:04:05 MST)'
- />
- </td>
- </tr>
- <tr>
- <td>{'%D'}</td>
- <td>
- <FormattedMessage
- id='admin.log.formatDateLong'
- defaultMessage='Date (2006/01/02)'
- />
- </td>
- </tr>
- <tr>
- <td>{'%d'}</td>
- <td>
- <FormattedMessage
- id='admin.log.formatDateShort'
- defaultMessage='Date (01/02/06)'
- />
- </td>
- </tr>
- <tr>
- <td>{'%L'}</td>
- <td>
- <FormattedMessage
- id='admin.log.formatLevel'
- defaultMessage='Level (DEBG, INFO, EROR)'
- />
- </td>
- </tr>
- <tr>
- <td>{'%S'}</td>
- <td>
- <FormattedMessage
- id='admin.log.formatSource'
- defaultMessage='Source'
- />
- </td>
- </tr>
- <tr>
- <td>{'%M'}</td>
- <td>
- <FormattedMessage
- id='admin.log.formatMessage'
- defaultMessage='Message'
- />
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/manage_roles_modal/index.js b/webapp/components/admin_console/manage_roles_modal/index.js
deleted file mode 100644
index 1ca243621..000000000
--- a/webapp/components/admin_console/manage_roles_modal/index.js
+++ /dev/null
@@ -1,25 +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 {updateUserRoles} from 'mattermost-redux/actions/users';
-
-import ManageRolesModal from './manage_roles_modal.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- userAccessTokensEnabled: state.entities.admin.config.ServiceSettings.EnableUserAccessTokens
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- updateUserRoles
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ManageRolesModal);
diff --git a/webapp/components/admin_console/manage_roles_modal/manage_roles_modal.jsx b/webapp/components/admin_console/manage_roles_modal/manage_roles_modal.jsx
deleted file mode 100644
index 2358f0241..000000000
--- a/webapp/components/admin_console/manage_roles_modal/manage_roles_modal.jsx
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import * as UserUtils from 'mattermost-redux/utils/user_utils';
-import {Client4} from 'mattermost-redux/client';
-import {General} from 'mattermost-redux/constants';
-
-import {trackEvent} from 'actions/diagnostics_actions.jsx';
-
-import React from 'react';
-import {Modal} from 'react-bootstrap';
-import PropTypes from 'prop-types';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-function getStateFromProps(props) {
- const roles = props.user && props.user.roles ? props.user.roles : '';
-
- return {
- error: null,
- hasPostAllRole: UserUtils.hasPostAllRole(roles),
- hasPostAllPublicRole: UserUtils.hasPostAllPublicRole(roles),
- hasUserAccessTokenRole: UserUtils.hasUserAccessTokenRole(roles),
- isSystemAdmin: UserUtils.isSystemAdmin(roles)
- };
-}
-
-export default class ManageRolesModal extends React.PureComponent {
- static propTypes = {
-
- /**
- * Set to render the modal
- */
- show: PropTypes.bool.isRequired,
-
- /**
- * The user the roles are being managed for
- */
- user: PropTypes.object,
-
- /**
- * Set if user access tokens are enabled
- */
- userAccessTokensEnabled: PropTypes.bool.isRequired,
-
- /**
- * Function called when modal is dismissed
- */
- onModalDismissed: PropTypes.func.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * Function to update a user's roles
- */
- updateUserRoles: PropTypes.func.isRequired
- }).isRequired
- };
-
- constructor(props) {
- super(props);
- this.state = getStateFromProps(props);
- }
-
- componentWillReceiveProps(nextProps) {
- const user = this.props.user || {};
- const nextUser = nextProps.user || {};
- if (user.id !== nextUser.id) {
- this.setState(getStateFromProps(nextProps));
- }
- }
-
- handleError = (error) => {
- this.setState({
- error
- });
- }
-
- handleSystemAdminChange = (e) => {
- if (e.target.name === 'systemadmin') {
- this.setState({isSystemAdmin: true});
- } else if (e.target.name === 'systemmember') {
- this.setState({isSystemAdmin: false});
- }
- };
-
- handleUserAccessTokenChange = (e) => {
- this.setState({
- hasUserAccessTokenRole: e.target.checked
- });
- };
-
- handlePostAllChange = (e) => {
- this.setState({
- hasPostAllRole: e.target.checked
- });
- };
-
- handlePostAllPublicChange = (e) => {
- this.setState({
- hasPostAllPublicRole: e.target.checked
- });
- };
-
- trackRoleChanges = (roles, oldRoles) => {
- if (UserUtils.hasUserAccessTokenRole(roles) && !UserUtils.hasUserAccessTokenRole(oldRoles)) {
- trackEvent('actions', 'add_roles', {role: General.SYSTEM_USER_ACCESS_TOKEN_ROLE});
- } else if (!UserUtils.hasUserAccessTokenRole(roles) && UserUtils.hasUserAccessTokenRole(oldRoles)) {
- trackEvent('actions', 'remove_roles', {role: General.SYSTEM_USER_ACCESS_TOKEN_ROLE});
- }
-
- if (UserUtils.hasPostAllRole(roles) && !UserUtils.hasPostAllRole(oldRoles)) {
- trackEvent('actions', 'add_roles', {role: General.SYSTEM_POST_ALL_ROLE});
- } else if (!UserUtils.hasPostAllRole(roles) && UserUtils.hasPostAllRole(oldRoles)) {
- trackEvent('actions', 'remove_roles', {role: General.SYSTEM_POST_ALL_ROLE});
- }
-
- if (UserUtils.hasPostAllPublicRole(roles) && !UserUtils.hasPostAllPublicRole(oldRoles)) {
- trackEvent('actions', 'add_roles', {role: General.SYSTEM_POST_ALL_PUBLIC_ROLE});
- } else if (!UserUtils.hasPostAllPublicRole(roles) && UserUtils.hasPostAllPublicRole(oldRoles)) {
- trackEvent('actions', 'remove_roles', {role: General.SYSTEM_POST_ALL_PUBLIC_ROLE});
- }
- }
-
- handleSave = async () => {
- this.setState({error: null});
-
- let roles = General.SYSTEM_USER_ROLE;
-
- if (this.state.isSystemAdmin) {
- roles += ' ' + General.SYSTEM_ADMIN_ROLE;
- } else if (this.state.hasUserAccessTokenRole) {
- roles += ' ' + General.SYSTEM_USER_ACCESS_TOKEN_ROLE;
- if (this.state.hasPostAllRole) {
- roles += ' ' + General.SYSTEM_POST_ALL_ROLE;
- } else if (this.state.hasPostAllPublicRole) {
- roles += ' ' + General.SYSTEM_POST_ALL_PUBLIC_ROLE;
- }
- }
-
- const data = await this.props.actions.updateUserRoles(this.props.user.id, roles);
-
- this.trackRoleChanges(roles, this.props.user.roles);
-
- if (data) {
- this.props.onModalDismissed();
- } else {
- this.handleError(
- <FormattedMessage
- id='admin.manage_roles.saveError'
- defaultMessage='Unable to save roles.'
- />
- );
- }
- }
-
- renderContents = () => {
- const {user} = this.props;
-
- if (user == null) {
- return <div/>;
- }
-
- let name = UserUtils.getFullName(user);
- if (name) {
- name += ` (@${user.username})`;
- } else {
- name = `@${user.username}`;
- }
-
- let additionalRoles;
- if (this.state.hasUserAccessTokenRole || this.state.isSystemAdmin) {
- additionalRoles = (
- <div>
- <p>
- <FormattedHTMLMessage
- id='admin.manage_roles.additionalRoles'
- defaultMessage='Select additional permissions for the account. <a href="https://about.mattermost.com/default-permissions" target="_blank">Read more about roles and permissions</a>.'
- />
- </p>
- <div className='checkbox'>
- <label>
- <input
- type='checkbox'
- ref='postall'
- checked={this.state.hasPostAllRole || this.state.isSystemAdmin}
- disabled={this.state.isSystemAdmin}
- onChange={this.handlePostAllChange}
- />
- <strong>
- <FormattedMessage
- id='admin.manage_roles.postAllRoleTitle'
- defaultMessage='post:all'
- />
- </strong>
- <FormattedMessage
- id='admin.manage_roles.postAllRole'
- defaultMessage='Access to post to all Mattermost channels including direct messages.'
- />
- </label>
- </div>
- <div className='checkbox'>
- <label>
- <input
- type='checkbox'
- ref='postallpublic'
- checked={this.state.hasPostAllPublicRole || this.state.hasPostAllRole || this.state.isSystemAdmin}
- disabled={this.state.hasPostAllRole || this.state.isSystemAdmin}
- onChange={this.handlePostAllPublicChange}
- />
- <strong>
- <FormattedMessage
- id='admin.manage_roles.postAllPublicRoleTitle'
- defaultMessage='post:channels'
- />
- </strong>
- <FormattedMessage
- id='admin.manage_roles.postAllPublicRole'
- defaultMessage='Access to post to all Mattermost public channels.'
- />
- </label>
- </div>
- </div>
- );
- }
-
- let userAccessTokenContent;
- if (this.props.userAccessTokensEnabled) {
- userAccessTokenContent = (
- <div>
- <div className='checkbox'>
- <label>
- <input
- type='checkbox'
- ref='postall'
- checked={this.state.hasUserAccessTokenRole || this.state.isSystemAdmin}
- disabled={this.state.isSystemAdmin}
- onChange={this.handleUserAccessTokenChange}
- />
- <FormattedHTMLMessage
- id='admin.manage_roles.allowUserAccessTokens'
- defaultMessage='Allow this account to generate <a href="https://about.mattermost.com/default-user-access-tokens" target="_blank">user access tokens</a>.'
- />
- </label>
- </div>
- <div className='member-row--padded'>
- {additionalRoles}
- </div>
- </div>
- );
- }
-
- return (
- <div>
- <div className='manage-teams__user'>
- <img
- className='manage-teams__profile-picture'
- src={Client4.getProfilePictureUrl(user.id, user.last_picture_update)}
- />
- <div className='manage-teams__info'>
- <div className='manage-teams__name'>
- {name}
- </div>
- <div className='manage-teams__email'>
- {user.email}
- </div>
- </div>
- </div>
- <div>
- <div className='manage-row--inner'>
- <div className='radio-inline'>
- <label>
- <input
- name='systemadmin'
- type='radio'
- checked={this.state.isSystemAdmin}
- onChange={this.handleSystemAdminChange}
- />
- <FormattedMessage
- id='admin.manage_roles.systemAdmin'
- defaultMessage='System Admin'
- />
- </label>
- </div>
- <div className='radio-inline'>
- <label>
- <input
- name='systemmember'
- type='radio'
- checked={!this.state.isSystemAdmin}
- onChange={this.handleSystemAdminChange}
- />
- <FormattedMessage
- id='admin.manage_roles.systemMember'
- defaultMessage='Member'
- />
- </label>
- </div>
- </div>
- {userAccessTokenContent}
- </div>
- </div>
- );
- }
-
- render() {
- return (
- <Modal
- show={this.props.show}
- onHide={this.props.onModalDismissed}
- dialogClassName='manage-teams'
- >
- <Modal.Header closeButton={true}>
- <Modal.Title>
- <FormattedMessage
- id='admin.manage_roles.manageRolesTitle'
- defaultMessage='Manage Roles'
- />
- </Modal.Title>
- </Modal.Header>
- <Modal.Body>
- {this.renderContents()}
- {this.state.error}
- </Modal.Body>
- <Modal.Footer>
- <button
- type='button'
- className='btn btn-link'
- onClick={this.props.onModalDismissed}
- >
- <FormattedMessage
- id='admin.manage_roles.cancel'
- defaultMessage='Cancel'
- />
- </button>
- <button
- type='button'
- className='btn btn-primary'
- onClick={this.handleSave}
- >
- <FormattedMessage
- id='admin.manage_roles.save'
- defaultMessage='Save'
- />
- </button>
- </Modal.Footer>
- </Modal>
- );
- }
-}
diff --git a/webapp/components/admin_console/manage_teams_modal/manage_teams_dropdown.jsx b/webapp/components/admin_console/manage_teams_modal/manage_teams_dropdown.jsx
deleted file mode 100644
index 4ee3c11cd..000000000
--- a/webapp/components/admin_console/manage_teams_modal/manage_teams_dropdown.jsx
+++ /dev/null
@@ -1,148 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import {Dropdown, MenuItem} from 'react-bootstrap';
-import {FormattedMessage} from 'react-intl';
-
-import {updateTeamMemberRoles, removeUserFromTeam} from 'actions/team_actions.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-export default class ManageTeamsDropdown extends React.Component {
- static propTypes = {
- user: PropTypes.object.isRequired,
- teamMember: PropTypes.object.isRequired,
- onError: PropTypes.func.isRequired,
- onMemberChange: PropTypes.func.isRequired,
- onMemberRemove: PropTypes.func.isRequired
- };
-
- constructor(props) {
- super(props);
-
- this.toggleDropdown = this.toggleDropdown.bind(this);
-
- this.makeTeamAdmin = this.makeTeamAdmin.bind(this);
- this.makeMember = this.makeMember.bind(this);
- this.removeFromTeam = this.removeFromTeam.bind(this);
-
- this.handleMemberChange = this.handleMemberChange.bind(this);
- this.handleMemberRemove = this.handleMemberRemove.bind(this);
-
- this.state = {
- show: false
- };
- }
-
- toggleDropdown() {
- this.setState((prevState) => {
- return {show: !prevState.show};
- });
- }
-
- makeTeamAdmin() {
- updateTeamMemberRoles(
- this.props.teamMember.team_id,
- this.props.user.id,
- 'team_user team_admin',
- this.handleMemberChange,
- this.props.onError
- );
- }
-
- makeMember() {
- updateTeamMemberRoles(
- this.props.teamMember.team_id,
- this.props.user.id,
- 'team_user',
- this.handleMemberChange,
- this.props.onError
- );
- }
-
- removeFromTeam() {
- removeUserFromTeam(
- this.props.teamMember.team_id,
- this.props.user.id,
- this.handleMemberRemove,
- this.props.onError
- );
- }
-
- handleMemberChange() {
- this.props.onMemberChange(this.props.teamMember.team_id);
- }
-
- handleMemberRemove() {
- this.props.onMemberRemove(this.props.teamMember.team_id);
- }
-
- render() {
- const isTeamAdmin = Utils.isAdmin(this.props.teamMember.roles);
-
- let title;
- if (isTeamAdmin) {
- title = Utils.localizeMessage('admin.user_item.teamAdmin', 'Team Admin');
- } else {
- title = Utils.localizeMessage('admin.user_item.teamMember', 'Team Member');
- }
-
- let makeTeamAdmin = null;
- if (!isTeamAdmin) {
- makeTeamAdmin = (
- <MenuItem
- id='makeTeamAdmin'
- onSelect={this.makeTeamAdmin}
- >
- <FormattedMessage
- id='admin.user_item.makeTeamAdmin'
- defaultMessage='Make Team Admin'
- />
- </MenuItem>
- );
- }
-
- let makeMember = null;
- if (isTeamAdmin) {
- makeMember = (
- <MenuItem
- id='makeMember'
- onSelect={this.makeMember}
- >
- <FormattedMessage
- id='admin.user_item.makeMember'
- defaultMessage='Make Member'
- />
- </MenuItem>
- );
- }
-
- return (
- <Dropdown
- id={`manage-teams-${this.props.user.id}-${this.props.teamMember.team_id}`}
- open={this.state.show}
- onToggle={this.toggleDropdown}
- >
- <Dropdown.Toggle useAnchor={true}>
- {title}
- </Dropdown.Toggle>
- <Dropdown.Menu>
- {makeTeamAdmin}
- {makeMember}
- <MenuItem
- id='removeFromTeam'
- onSelect={this.removeFromTeam}
- >
- <FormattedMessage
- id='team_members_dropdown.leave_team'
- defaultMessage='Remove from Team'
- />
- </MenuItem>
- </Dropdown.Menu>
- </Dropdown>
- );
- }
-}
diff --git a/webapp/components/admin_console/manage_teams_modal/manage_teams_modal.jsx b/webapp/components/admin_console/manage_teams_modal/manage_teams_modal.jsx
deleted file mode 100644
index 21f9d762d..000000000
--- a/webapp/components/admin_console/manage_teams_modal/manage_teams_modal.jsx
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import {Modal} from 'react-bootstrap';
-import {FormattedMessage} from 'react-intl';
-import PropTypes from 'prop-types';
-
-import * as TeamActions from 'actions/team_actions.jsx';
-
-import {Client4} from 'mattermost-redux/client';
-
-import LoadingScreen from 'components/loading_screen.jsx';
-
-import {sortTeamsByDisplayName} from 'utils/team_utils.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import ManageTeamsDropdown from './manage_teams_dropdown.jsx';
-import RemoveFromTeamButton from './remove_from_team_button.jsx';
-
-export default class ManageTeamsModal extends React.Component {
- static propTypes = {
- onModalDismissed: PropTypes.func.isRequired,
- show: PropTypes.bool.isRequired,
- user: PropTypes.object
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- error: null,
- teams: null,
- teamMembers: null
- };
- }
-
- componentDidMount() {
- if (this.props.user) {
- this.loadTeamsAndTeamMembers();
- }
- }
-
- componentWillReceiveProps(nextProps) {
- const userId = this.props.user ? this.props.user.id : '';
- const nextUserId = nextProps.user ? nextProps.user.id : '';
-
- if (userId !== nextUserId) {
- this.setState({
- teams: null,
- teamMembers: null
- });
-
- if (nextProps.user) {
- this.loadTeamsAndTeamMembers(nextProps.user);
- }
- }
- }
-
- loadTeamsAndTeamMembers = (user = this.props.user) => {
- TeamActions.getTeamsForUser(user.id, (teams) => {
- this.setState({
- teams: teams.sort(sortTeamsByDisplayName)
- });
- });
-
- TeamActions.getTeamMembersForUser(user.id, (teamMembers) => {
- this.setState({
- teamMembers
- });
- });
- }
-
- handleError = (error) => {
- this.setState({
- error
- });
- }
-
- handleMemberChange = () => {
- TeamActions.getTeamMembersForUser(this.props.user.id, (teamMembers) => {
- this.setState({
- teamMembers
- });
- });
- }
-
- handleMemberRemove = (teamId) => {
- this.setState({
- teams: this.state.teams.filter((team) => team.id !== teamId),
- teamMembers: this.state.teamMembers.filter((teamMember) => teamMember.team_id !== teamId)
- });
- }
-
- renderContents = () => {
- const {user} = this.props;
- const {teams, teamMembers} = this.state;
-
- if (!user) {
- return <LoadingScreen/>;
- }
-
- const isSystemAdmin = Utils.isAdmin(user.roles);
-
- let name = Utils.getFullName(user);
- if (name) {
- name += ` (@${user.username})`;
- } else {
- name = `@${user.username}`;
- }
-
- let teamList;
- if (teams && teamMembers) {
- teamList = teams.map((team) => {
- const teamMember = teamMembers.find((member) => member.team_id === team.id);
- if (!teamMember) {
- return null;
- }
-
- let action;
- if (isSystemAdmin) {
- action = (
- <RemoveFromTeamButton
- user={user}
- team={team}
- onError={this.handleError}
- onMemberRemove={this.handleMemberRemove}
- />
- );
- } else {
- action = (
- <ManageTeamsDropdown
- user={user}
- team={team}
- teamMember={teamMember}
- onError={this.handleError}
- onMemberChange={this.handleMemberChange}
- onMemberRemove={this.handleMemberRemove}
- />
- );
- }
-
- return (
- <div
- key={team.id}
- className='manage-teams__team'
- >
- <div className='manage-teams__team-name'>
- {team.display_name}
- </div>
- <div className='manage-teams__team-actions'>
- {action}
- </div>
- </div>
- );
- });
- } else {
- teamList = <LoadingScreen/>;
- }
-
- let systemAdminIndicator = null;
- if (isSystemAdmin) {
- systemAdminIndicator = (
- <div className='manage-teams__system-admin'>
- <FormattedMessage
- id='admin.user_item.sysAdmin'
- defaultMessage='System Admin'
- />
- </div>
- );
- }
-
- return (
- <div>
- <div className='manage-teams__user'>
- <img
- className='manage-teams__profile-picture'
- src={Client4.getProfilePictureUrl(user.id, user.last_picture_update)}
- />
- <div className='manage-teams__info'>
- <div className='manage-teams__name'>
- {name}
- </div>
- <div className='manage-teams__email'>
- {user.email}
- </div>
- </div>
- {systemAdminIndicator}
- </div>
- <div className='manage-teams__teams'>
- {teamList}
- </div>
- </div>
- );
- }
-
- render() {
- return (
- <Modal
- show={this.props.show}
- onHide={this.props.onModalDismissed}
- dialogClassName='manage-teams'
- >
- <Modal.Header closeButton={true}>
- <Modal.Title>
- <FormattedMessage
- id='admin.user_item.manageTeams'
- defaultMessage='Manage Teams'
- />
- </Modal.Title>
- </Modal.Header>
- <Modal.Body>
- {this.renderContents()}
- </Modal.Body>
- </Modal>
- );
- }
-}
diff --git a/webapp/components/admin_console/manage_teams_modal/remove_from_team_button.jsx b/webapp/components/admin_console/manage_teams_modal/remove_from_team_button.jsx
deleted file mode 100644
index 69579d46f..000000000
--- a/webapp/components/admin_console/manage_teams_modal/remove_from_team_button.jsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-import {removeUserFromTeam} from 'actions/team_actions.jsx';
-
-export default class RemoveFromTeamButton extends React.PureComponent {
- static propTypes = {
- onError: PropTypes.func.isRequired,
- onMemberRemove: PropTypes.func.isRequired,
- team: PropTypes.object.isRequired,
- user: PropTypes.object.isRequired
- };
-
- constructor(props) {
- super(props);
-
- this.handleClick = this.handleClick.bind(this);
- this.handleMemberRemove = this.handleMemberRemove.bind(this);
- }
-
- handleClick(e) {
- e.preventDefault();
-
- removeUserFromTeam(
- this.props.team.id,
- this.props.user.id,
- this.handleMemberRemove,
- this.props.onError
- );
- }
-
- handleMemberRemove() {
- this.props.onMemberRemove(this.props.team.id);
- }
-
- render() {
- return (
- <button
- className='btn btn-danger'
- onClick={this.handleClick}
- >
- <FormattedMessage
- id='team_members_dropdown.leave_team'
- defaultMessage='Remove from Team'
- />
- </button>
- );
- }
-}
diff --git a/webapp/components/admin_console/manage_tokens_modal/index.js b/webapp/components/admin_console/manage_tokens_modal/index.js
deleted file mode 100644
index 9f7a31141..000000000
--- a/webapp/components/admin_console/manage_tokens_modal/index.js
+++ /dev/null
@@ -1,27 +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 {getUserAccessTokensForUser} from 'mattermost-redux/actions/users';
-
-import ManageTokensModal from './manage_tokens_modal.jsx';
-
-function mapStateToProps(state, ownProps) {
- const userId = ownProps.user ? ownProps.user.id : '';
-
- return {
- ...ownProps,
- userAccessTokens: state.entities.admin.userAccessTokens[userId]
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getUserAccessTokensForUser
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ManageTokensModal);
diff --git a/webapp/components/admin_console/manage_tokens_modal/manage_tokens_modal.jsx b/webapp/components/admin_console/manage_tokens_modal/manage_tokens_modal.jsx
deleted file mode 100644
index fdef870e5..000000000
--- a/webapp/components/admin_console/manage_tokens_modal/manage_tokens_modal.jsx
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import LoadingScreen from 'components/loading_screen.jsx';
-import RevokeTokenButton from 'components/admin_console/revoke_token_button';
-
-import {Client4} from 'mattermost-redux/client';
-import * as UserUtils from 'mattermost-redux/utils/user_utils';
-
-import React from 'react';
-import {Modal} from 'react-bootstrap';
-import PropTypes from 'prop-types';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-export default class ManageTokensModal extends React.PureComponent {
- static propTypes = {
-
- /**
- * Set to render the modal
- */
- show: PropTypes.bool.isRequired,
-
- /**
- * The user the roles are being managed for
- */
- user: PropTypes.object,
-
- /**
- * The personal access tokens for a user, object with token ids as keys
- */
- userAccessTokens: PropTypes.object,
-
- /**
- * Function called when modal is dismissed
- */
- onModalDismissed: PropTypes.func.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * Function to get a user's access tokens
- */
- getUserAccessTokensForUser: PropTypes.func.isRequired
- }).isRequired
- };
-
- constructor(props) {
- super(props);
- this.state = {error: null};
- }
-
- componentWillReceiveProps(nextProps) {
- const userId = this.props.user ? this.props.user.id : null;
- const nextUserId = nextProps.user ? nextProps.user.id : null;
- if (nextUserId && nextUserId !== userId) {
- this.props.actions.getUserAccessTokensForUser(nextUserId, 0, 200);
- }
- }
-
- handleError = (error) => {
- this.setState({
- error
- });
- }
-
- renderContents = () => {
- const {user, userAccessTokens} = this.props;
-
- if (!user) {
- return <LoadingScreen/>;
- }
-
- let name = UserUtils.getFullName(user);
- if (name) {
- name += ` (@${user.username})`;
- } else {
- name = `@${user.username}`;
- }
-
- let tokenList;
- if (userAccessTokens) {
- const userAccessTokensList = Object.values(userAccessTokens);
-
- if (userAccessTokensList.length === 0) {
- tokenList = (
- <div className='manage-row__empty'>
- <FormattedMessage
- id='admin.manage_tokens.userAccessTokensNone'
- defaultMessage='No personal access tokens.'
- />
- </div>
- );
- } else {
- tokenList = userAccessTokensList.map((token) => {
- return (
- <div
- key={token.id}
- className='manage-teams__team'
- >
- <div className='manage-teams__team-name'>
- <div className='whitespace--nowrap overflow--ellipsis'>
- <FormattedMessage
- id='admin.manage_tokens.userAccessTokensNameLabel'
- defaultMessage='Token Description: '
- />
- {token.description}
- </div>
- <div className='whitespace--nowrap overflow--ellipsis'>
- <FormattedMessage
- id='admin.manage_tokens.userAccessTokensIdLabel'
- defaultMessage='Token ID: '
- />
- {token.id}
- </div>
- </div>
- <div className='manage-teams__team-actions'>
- <RevokeTokenButton
- tokenId={token.id}
- onError={this.handleError}
- />
- </div>
- </div>
- );
- });
- }
- } else {
- tokenList = <LoadingScreen/>;
- }
-
- return (
- <div>
- <div className='manage-teams__user'>
- <img
- className='manage-teams__profile-picture'
- src={Client4.getProfilePictureUrl(user.id, user.last_picture_update)}
- />
- <div className='manage-teams__info'>
- <div className='manage-teams__name'>
- {name}
- </div>
- <div className='manage-teams__email'>
- {user.email}
- </div>
- </div>
- </div>
- <div className='padding-top x2'>
- <FormattedHTMLMessage
- id='admin.manage_tokens.userAccessTokensDescription'
- defaultMessage='Personal access tokens function similar to session tokens and can be used by integrations to <a href="https://about.mattermost.com/default-api-authentication" target="_blank">interact with this Mattermost server</a>. Learn more about <a href="https://about.mattermost.com/default-user-access-tokens" target="_blank">personal access tokens</a>.'
- />
- </div>
- <div className='manage-teams__teams'>
- {tokenList}
- </div>
- </div>
- );
- }
-
- render() {
- return (
- <Modal
- show={this.props.show}
- onHide={this.props.onModalDismissed}
- dialogClassName='manage-teams'
- >
- <Modal.Header closeButton={true}>
- <Modal.Title>
- <FormattedMessage
- id='admin.manage_tokens.manageTokensTitle'
- defaultMessage='Manage Personal Access Tokens'
- />
- </Modal.Title>
- </Modal.Header>
- <Modal.Body>
- {this.renderContents()}
- {this.state.error}
- </Modal.Body>
- </Modal>
- );
- }
-}
diff --git a/webapp/components/admin_console/metrics_settings.jsx b/webapp/components/admin_console/metrics_settings.jsx
deleted file mode 100644
index 9eab4073b..000000000
--- a/webapp/components/admin_console/metrics_settings.jsx
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import TextSetting from './text_setting.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-export default class MetricsSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.MetricsSettings.Enable = this.state.enable;
- config.MetricsSettings.ListenAddress = this.state.listenAddress;
-
- return config;
- }
-
- getStateFromConfig(config) {
- const settings = config.MetricsSettings;
-
- return {
- enable: settings.Enable,
- listenAddress: settings.ListenAddress
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.advance.metrics'
- defaultMessage='Performance Monitoring'
- />
- );
- }
-
- renderSettings() {
- const licenseEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.Metrics === 'true';
- if (!licenseEnabled) {
- return null;
- }
-
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enable'
- label={
- <FormattedMessage
- id='admin.metrics.enableTitle'
- defaultMessage='Enable Performance Monitoring:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.metrics.enableDescription'
- defaultMessage='When true, Mattermost will enable performance monitoring collection and profiling. Please see <a href="http://docs.mattermost.com/deployment/metrics.html" target="_blank">documentation</a> to learn more about configuring performance monitoring for Mattermost.'
- />
- }
- value={this.state.enable}
- onChange={this.handleChange}
- />
- <TextSetting
- id='listenAddress'
- label={
- <FormattedMessage
- id='admin.metrics.listenAddressTitle'
- defaultMessage='Listen Address:'
- />
- }
- placeholder={Utils.localizeMessage('admin.metrics.listenAddressEx', 'Ex ":8067"')}
- helpText={
- <FormattedMessage
- id='admin.metrics.listenAddressDesc'
- defaultMessage='The address the server will listen on to expose performance metrics.'
- />
- }
- value={this.state.listenAddress}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/mfa_settings.jsx b/webapp/components/admin_console/mfa_settings.jsx
deleted file mode 100644
index 9d7a64d05..000000000
--- a/webapp/components/admin_console/mfa_settings.jsx
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import AdminSettings from './admin_settings.jsx';
-import SettingsGroup from './settings_group.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-
-import React from 'react';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-export default class MfaSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
-
- this.state = Object.assign(this.state, {
- enableMultifactorAuthentication: props.config.ServiceSettings.EnableMultifactorAuthentication,
- enforceMultifactorAuthentication: props.config.ServiceSettings.EnforceMultifactorAuthentication
- });
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.EnableMultifactorAuthentication = this.state.enableMultifactorAuthentication;
- config.ServiceSettings.EnforceMultifactorAuthentication = this.state.enableMultifactorAuthentication && this.state.enforceMultifactorAuthentication;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableMultifactorAuthentication: config.ServiceSettings.EnableMultifactorAuthentication,
- enforceMultifactorAuthentication: config.ServiceSettings.EnableMultifactorAuthentication && config.ServiceSettings.EnforceMultifactorAuthentication
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.mfa.title'
- defaultMessage='Multi-factor Authentication'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <div className='banner'>
- <div className='banner__content'>
- <FormattedHTMLMessage
- id='admin.mfa.bannerDesc'
- defaultMessage="<a href='https://docs.mattermost.com/deployment/auth.html' target='_blank'>Multi-factor authentication</a> is available for accounts with AD/LDAP or email login. If other login methods are used, MFA should be configured with the authentication provider."
- />
- </div>
- </div>
- <BooleanSetting
- id='enableMultifactorAuthentication'
- label={
- <FormattedMessage
- id='admin.service.mfaTitle'
- defaultMessage='Enable Multi-factor Authentication:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.service.mfaDesc'
- defaultMessage='When true, users with AD/LDAP or email login can add multi-factor authentication to their account using Google Authenticator.'
- />
- }
- value={this.state.enableMultifactorAuthentication}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enforceMultifactorAuthentication'
- label={
- <FormattedMessage
- id='admin.service.enforceMfaTitle'
- defaultMessage='Enforce Multi-factor Authentication:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.service.enforceMfaDesc'
- defaultMessage="When true, <a href='https://docs.mattermost.com/deployment/auth.html' target='_blank'>multi-factor authentication</a> is required for login. New users will be required to configure MFA on signup. Logged in users without MFA configured are redirected to the MFA setup page until configuration is complete.<br/><br/>If your system has users with login methods other than AD/LDAP and email, MFA must be enforced with the authentication provider outside of Mattermost."
- />
- }
- disabled={!this.state.enableMultifactorAuthentication}
- value={this.state.enforceMultifactorAuthentication}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/multiselect_settings.jsx b/webapp/components/admin_console/multiselect_settings.jsx
deleted file mode 100644
index 8ae8e1349..000000000
--- a/webapp/components/admin_console/multiselect_settings.jsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-import React from 'react';
-import ReactSelect from 'react-select';
-
-import Setting from './setting.jsx';
-import FormError from 'components/form_error.jsx';
-
-export default class MultiSelectSetting extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- this.state = {error: false};
- }
-
- handleChange(newValue) {
- const values = newValue.map((n) => {
- return n.value;
- });
-
- if (this.props.selected.length > 0 && this.props.mustBePresent && values.join(',').indexOf(this.props.mustBePresent) === -1) {
- this.setState({error: this.props.notPresent});
- } else {
- this.props.onChange(this.props.id, values);
- this.setState({error: false});
- }
- }
-
- componentWillReceiveProps(newProps) {
- if (newProps.selected.length > 0 && newProps.mustBePresent && newProps.selected.join(',').indexOf(newProps.mustBePresent) === -1) {
- this.setState({error: this.props.notPresent});
- } else {
- this.setState({error: false});
- }
- }
-
- render() {
- return (
- <Setting
- label={this.props.label}
- inputId={this.props.id}
- helpText={this.props.helpText}
- >
- <ReactSelect
- id={this.props.id}
- multi={true}
- labelKey='text'
- options={this.props.values}
- joinValues={true}
- clearable={false}
- disabled={this.props.disabled}
- noResultsText={this.props.noResultText}
- onChange={this.handleChange}
- value={this.props.selected}
- />
- <FormError error={this.state.error}/>
- </Setting>
- );
- }
-}
-
-MultiSelectSetting.defaultProps = {
- disabled: false
-};
-
-MultiSelectSetting.propTypes = {
- id: PropTypes.string.isRequired,
- values: PropTypes.array.isRequired,
- label: PropTypes.node.isRequired,
- selected: PropTypes.array.isRequired,
- mustBePresent: PropTypes.string,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool,
- helpText: PropTypes.node,
- noResultText: PropTypes.node,
- errorText: PropTypes.node,
- notPresent: PropTypes.node
-};
diff --git a/webapp/components/admin_console/native_app_link_settings.jsx b/webapp/components/admin_console/native_app_link_settings.jsx
deleted file mode 100644
index 88c078476..000000000
--- a/webapp/components/admin_console/native_app_link_settings.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class NativeAppLinkSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.NativeAppSettings.AppDownloadLink = this.state.appDownloadLink;
- config.NativeAppSettings.AndroidAppDownloadLink = this.state.androidAppDownloadLink;
- config.NativeAppSettings.IosAppDownloadLink = this.state.iosAppDownloadLink;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- appDownloadLink: config.NativeAppSettings.AppDownloadLink,
- androidAppDownloadLink: config.NativeAppSettings.AndroidAppDownloadLink,
- iosAppDownloadLink: config.NativeAppSettings.IosAppDownloadLink
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.customization.nativeAppLinks'
- defaultMessage='Mattermost App Links'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <TextSetting
- id='appDownloadLink'
- label={
- <FormattedMessage
- id='admin.customization.appDownloadLinkTitle'
- defaultMessage='Mattermost Apps Download Page Link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.customization.appDownloadLinkDesc'
- defaultMessage='Add a link to a download page for the Mattermost apps. When a link is present, an option to "Download Mattermost Apps" will be added in the Main Menu so users can find the download page. Leave this field blank to hide the option from the Main Menu.'
- />
- }
- value={this.state.appDownloadLink}
- onChange={this.handleChange}
- />
- <TextSetting
- id='androidAppDownloadLink'
- label={
- <FormattedMessage
- id='admin.customization.androidAppDownloadLinkTitle'
- defaultMessage='Android App Download Link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.customization.androidAppDownloadLinkDesc'
- defaultMessage='Add a link to download the Android app. Users who access the site on a mobile web browser will be prompted with a page giving them the option to download the app. Leave this field blank to prevent the page from appearing.'
- />
- }
- value={this.state.androidAppDownloadLink}
- onChange={this.handleChange}
- />
- <TextSetting
- id='iosAppDownloadLink'
- label={
- <FormattedMessage
- id='admin.customization.iosAppDownloadLinkTitle'
- defaultMessage='iOS App Download Link:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.customization.iosAppDownloadLinkDesc'
- defaultMessage='Add a link to download the iOS app. Users who access the site on a mobile web browser will be prompted with a page giving them the option to download the app. Leave this field blank to prevent the page from appearing.'
- />
- }
- value={this.state.iosAppDownloadLink}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/oauth_settings.jsx b/webapp/components/admin_console/oauth_settings.jsx
deleted file mode 100644
index abb4dc762..000000000
--- a/webapp/components/admin_console/oauth_settings.jsx
+++ /dev/null
@@ -1,430 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-import React from 'react';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-
-export default class OAuthSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
- this.getStateFromConfig = this.getStateFromConfig.bind(this);
- this.renderSettings = this.renderSettings.bind(this);
- this.renderOffice365 = this.renderOffice365.bind(this);
- this.renderGoogle = this.renderGoogle.bind(this);
- this.renderGitLab = this.renderGitLab.bind(this);
- this.changeType = this.changeType.bind(this);
- }
-
- getConfigFromState(config) {
- config.GitLabSettings.Enable = false;
- config.GoogleSettings.Enable = false;
- config.Office365Settings.Enable = false;
-
- if (this.state.oauthType === Constants.GITLAB_SERVICE) {
- config.GitLabSettings.Enable = true;
- config.GitLabSettings.Id = this.state.id;
- config.GitLabSettings.Secret = this.state.secret;
- config.GitLabSettings.UserApiEndpoint = this.state.userApiEndpoint;
- config.GitLabSettings.AuthEndpoint = this.state.authEndpoint;
- config.GitLabSettings.TokenEndpoint = this.state.tokenEndpoint;
- }
-
- if (this.state.oauthType === Constants.GOOGLE_SERVICE) {
- config.GoogleSettings.Enable = true;
- config.GoogleSettings.Id = this.state.id;
- config.GoogleSettings.Secret = this.state.secret;
- config.GoogleSettings.UserApiEndpoint = 'https://www.googleapis.com/plus/v1/people/me';
- config.GoogleSettings.AuthEndpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
- config.GoogleSettings.TokenEndpoint = 'https://www.googleapis.com/oauth2/v4/token';
- config.GoogleSettings.Scope = 'profile email';
- }
-
- if (this.state.oauthType === Constants.OFFICE365_SERVICE) {
- config.Office365Settings.Enable = true;
- config.Office365Settings.Id = this.state.id;
- config.Office365Settings.Secret = this.state.secret;
- config.Office365Settings.UserApiEndpoint = 'https://graph.microsoft.com/v1.0/me';
- config.Office365Settings.AuthEndpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
- config.Office365Settings.TokenEndpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
- config.Office365Settings.Scope = 'User.Read';
- }
-
- return config;
- }
-
- getStateFromConfig(config) {
- this.config = config;
-
- let oauthType = 'off';
- let settings = {};
- if (config.GitLabSettings.Enable) {
- oauthType = Constants.GITLAB_SERVICE;
- settings = config.GitLabSettings;
- } else if (config.GoogleSettings.Enable) {
- oauthType = Constants.GOOGLE_SERVICE;
- settings = config.GoogleSettings;
- } else if (config.Office365Settings.Enable) {
- oauthType = Constants.OFFICE365_SERVICE;
- settings = config.Office365Settings;
- }
-
- return {
- oauthType,
- id: settings.Id,
- secret: settings.Secret,
- userApiEndpoint: settings.UserApiEndpoint,
- authEndpoint: settings.AuthEndpoint,
- tokenEndpoint: settings.TokenEndpoint
- };
- }
-
- changeType(id, value) {
- let settings = {};
- if (value === Constants.GITLAB_SERVICE) {
- settings = this.config.GitLabSettings;
- } else if (value === Constants.GOOGLE_SERVICE) {
- settings = this.config.GoogleSettings;
- } else if (value === Constants.OFFICE365_SERVICE) {
- settings = this.config.Office365Settings;
- }
-
- this.setState({
- id: settings.Id,
- secret: settings.Secret,
- userApiEndpoint: settings.UserApiEndpoint,
- authEndpoint: settings.AuthEndpoint,
- tokenEndpoint: settings.TokenEndpoint
- });
-
- this.handleChange(id, value);
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.authentication.oauth'
- defaultMessage='OAuth 2.0'
- />
- );
- }
-
- renderGoogle() {
- return (
- <div>
- <TextSetting
- id='id'
- label={
- <FormattedMessage
- id='admin.google.clientIdTitle'
- defaultMessage='Client ID:'
- />
- }
- placeholder={Utils.localizeMessage('admin.google.clientIdExample', 'Ex "7602141235235-url0fhs1mayfasbmop5qlfns8dh4.apps.googleusercontent.com"')}
- helpText={
- <FormattedMessage
- id='admin.google.clientIdDescription'
- defaultMessage='The Client ID you received when registering your application with Google.'
- />
- }
- value={this.state.id}
- onChange={this.handleChange}
- />
- <TextSetting
- id='secret'
- label={
- <FormattedMessage
- id='admin.google.clientSecretTitle'
- defaultMessage='Client Secret:'
- />
- }
- placeholder={Utils.localizeMessage('admin.google.clientSecretExample', 'Ex "H8sz0Az-dDs2p15-7QzD231"')}
- helpText={
- <FormattedMessage
- id='admin.google.clientSecretDescription'
- defaultMessage='The Client Secret you received when registering your application with Google.'
- />
- }
- value={this.state.secret}
- onChange={this.handleChange}
- />
- <TextSetting
- id='userApiEndpoint'
- label={
- <FormattedMessage
- id='admin.google.userTitle'
- defaultMessage='User API Endpoint:'
- />
- }
- value='https://www.googleapis.com/plus/v1/people/me'
- disabled={true}
- />
- <TextSetting
- id='authEndpoint'
- label={
- <FormattedMessage
- id='admin.google.authTitle'
- defaultMessage='Auth Endpoint:'
- />
- }
- value='https://accounts.google.com/o/oauth2/v2/auth'
- disabled={true}
- />
- <TextSetting
- id='tokenEndpoint'
- label={
- <FormattedMessage
- id='admin.google.tokenTitle'
- defaultMessage='Token Endpoint:'
- />
- }
- value='https://www.googleapis.com/oauth2/v4/token'
- disabled={true}
- />
- </div>
- );
- }
-
- renderOffice365() {
- return (
- <div>
- <TextSetting
- id='id'
- label={
- <FormattedMessage
- id='admin.office365.clientIdTitle'
- defaultMessage='Application ID:'
- />
- }
- placeholder={Utils.localizeMessage('admin.office365.clientIdExample', 'Ex "adf3sfa2-ag3f-sn4n-ids0-sh1hdax192qq"')}
- helpText={
- <FormattedMessage
- id='admin.office365.clientIdDescription'
- defaultMessage='The Application/Client ID you received when registering your application with Microsoft.'
- />
- }
- value={this.state.id}
- onChange={this.handleChange}
- />
- <TextSetting
- id='secret'
- label={
- <FormattedMessage
- id='admin.office365.clientSecretTitle'
- defaultMessage='Application Secret Password:'
- />
- }
- placeholder={Utils.localizeMessage('admin.office365.clientSecretExample', 'Ex "shAieM47sNBfgl20f8ci294"')}
- helpText={
- <FormattedMessage
- id='admin.office365.clientSecretDescription'
- defaultMessage='The Application Secret Password you generated when registering your application with Microsoft.'
- />
- }
- value={this.state.secret}
- onChange={this.handleChange}
- />
- <TextSetting
- id='userApiEndpoint'
- label={
- <FormattedMessage
- id='admin.office365.userTitle'
- defaultMessage='User API Endpoint:'
- />
- }
- value='https://graph.microsoft.com/v1.0/me'
- disabled={true}
- />
- <TextSetting
- id='authEndpoint'
- label={
- <FormattedMessage
- id='admin.office365.authTitle'
- defaultMessage='Auth Endpoint:'
- />
- }
- value='https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
- disabled={true}
- />
- <TextSetting
- id='tokenEndpoint'
- label={
- <FormattedMessage
- id='admin.office365.tokenTitle'
- defaultMessage='Token Endpoint:'
- />
- }
- value='https://login.microsoftonline.com/common/oauth2/v2.0/token'
- disabled={true}
- />
- </div>
- );
- }
-
- renderGitLab() {
- return (
- <div>
- <TextSetting
- id='id'
- label={
- <FormattedMessage
- id='admin.gitlab.clientIdTitle'
- defaultMessage='Application ID:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.clientIdExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.clientIdDescription'
- defaultMessage='Obtain this value via the instructions above for logging into GitLab'
- />
- }
- value={this.state.id}
- onChange={this.handleChange}
- />
- <TextSetting
- id='secret'
- label={
- <FormattedMessage
- id='admin.gitlab.clientSecretTitle'
- defaultMessage='Application Secret Key:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.clientSecretExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
- helpText={
- <FormattedMessage
- id='admin.gitab.clientSecretDescription'
- defaultMessage='Obtain this value via the instructions above for logging into GitLab.'
- />
- }
- value={this.state.secret}
- onChange={this.handleChange}
- />
- <TextSetting
- id='userApiEndpoint'
- label={
- <FormattedMessage
- id='admin.gitlab.userTitle'
- defaultMessage='User API Endpoint:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.userExample', 'Ex "https://<your-gitlab-url>/api/v3/user"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.userDescription'
- defaultMessage='Enter https://<your-gitlab-url>/api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- }
- value={this.state.userApiEndpoint}
- onChange={this.handleChange}
- />
- <TextSetting
- id='authEndpoint'
- label={
- <FormattedMessage
- id='admin.gitlab.authTitle'
- defaultMessage='Auth Endpoint:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.authExample', 'Ex "https://<your-gitlab-url>/oauth/authorize"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.authDescription'
- defaultMessage='Enter https://<your-gitlab-url>/oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- }
- value={this.state.authEndpoint}
- onChange={this.handleChange}
- />
- <TextSetting
- id='tokenEndpoint'
- label={
- <FormattedMessage
- id='admin.gitlab.tokenTitle'
- defaultMessage='Token Endpoint:'
- />
- }
- placeholder={Utils.localizeMessage('admin.gitlab.tokenExample', 'Ex "https://<your-gitlab-url>/oauth/token"')}
- helpText={
- <FormattedMessage
- id='admin.gitlab.tokenDescription'
- defaultMessage='Enter https://<your-gitlab-url>/oauth/token. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- }
- value={this.state.tokenEndpoint}
- onChange={this.handleChange}
- />
- </div>
- );
- }
-
- renderSettings() {
- let contents;
- let helpText;
- if (this.state.oauthType === Constants.GITLAB_SERVICE) {
- contents = this.renderGitLab();
- helpText = (
- <FormattedHTMLMessage
- id='admin.gitlab.EnableHtmlDesc'
- defaultMessage='<ol><li>Log in to your GitLab account and go to Profile Settings -> Applications.</li><li>Enter Redirect URIs "<your-mattermost-url>/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "<your-mattermost-url>/signup/gitlab/complete". </li><li>Then use "Application Secret Key" and "Application ID" fields from GitLab to complete the options below.</li><li>Complete the Endpoint URLs below. </li></ol>'
- />
- );
- } else if (this.state.oauthType === Constants.GOOGLE_SERVICE) {
- contents = this.renderGoogle();
- helpText = (
- <FormattedHTMLMessage
- id='admin.google.EnableHtmlDesc'
- defaultMessage='<ol><li><a target="_blank" href="https://accounts.google.com/login">Log in</a> to your Google account.</li><li>Go to <a target="_blank" href="https://console.developers.google.com">https://console.developers.google.com</a>, click <strong>Credentials</strong> in the left hand sidebar and enter "Mattermost - your-company-name" as the <strong>Project Name</strong>, then click <strong>Create</strong>.</li><li>Click the <strong>OAuth consent screen</strong> header and enter "Mattermost" as the <strong>Product name shown to users</strong>, then click <strong>Save</strong>.</li><li>Under the <strong>Credentials</strong> header, click <strong>Create credentials</strong>, choose <strong>OAuth client ID</strong> and select <strong>Web Application</strong>.</li><li>Under <strong>Restrictions</strong> and <strong>Authorized redirect URIs</strong> enter <strong>your-mattermost-url/signup/google/complete</strong> (example: http://localhost:8065/signup/google/complete). Click <strong>Create</strong>.</li><li>Paste the <strong>Client ID</strong> and <strong>Client Secret</strong> to the fields below, then click <strong>Save</strong>.</li><li>Finally, go to <a target="_blank" href="https://console.developers.google.com/apis/api/plus/overview">Google+ API</a> and click <strong>Enable</strong>. This might take a few minutes to propagate through Google`s systems.</li></ol>'
- />
- );
- } else if (this.state.oauthType === Constants.OFFICE365_SERVICE) {
- contents = this.renderOffice365();
- helpText = (
- <FormattedHTMLMessage
- id='admin.office365.EnableHtmlDesc'
- defaultMessage='<ol><li><a target="_blank" href="https://login.microsoftonline.com/">Log in</a> to your Microsoft or Office 365 account. Make sure it`s the account on the same <a target="_blank" href="https://msdn.microsoft.com/en-us/library/azure/jj573650.aspx#Anchor_0">tenant</a> that you would like users to log in with.</li><li>Go to <a target="_blank" href="https://apps.dev.microsoft.com">https://apps.dev.microsoft.com</a>, click <strong>Go to app list</strong> > <strong>Add an app</strong> and use "Mattermost - your-company-name" as the <strong>Application Name</strong>.</li><li>Under <strong>Application Secrets</strong>, click <strong>Generate New Password</strong> and paste it to the <strong>Application Secret Password</strong> field below.</li><li>Under <strong>Platforms</strong>, click <strong>Add Platform</strong>, choose <strong>Web</strong> and enter <strong>your-mattermost-url/signup/office365/complete</strong> (example: http://localhost:8065/signup/office365/complete) under <strong>Redirect URIs</strong>. Also uncheck <strong>Allow Implicit Flow</strong>.</li><li>Finally, click <strong>Save</strong> and then paste the <strong>Application ID</strong> below.</li></ol>'
- />
- );
- }
-
- const oauthTypes = [];
- oauthTypes.push({value: 'off', text: Utils.localizeMessage('admin.oauth.off', 'Do not allow sign-in via an OAuth 2.0 provider.')});
- oauthTypes.push({value: Constants.GITLAB_SERVICE, text: Utils.localizeMessage('admin.oauth.gitlab', 'GitLab')});
- if (global.window.mm_license.IsLicensed === 'true') {
- if (global.window.mm_license.GoogleOAuth === 'true') {
- oauthTypes.push({value: Constants.GOOGLE_SERVICE, text: Utils.localizeMessage('admin.oauth.google', 'Google Apps')});
- }
- if (global.window.mm_license.Office365OAuth === 'true') {
- oauthTypes.push({value: Constants.OFFICE365_SERVICE, text: Utils.localizeMessage('admin.oauth.office365', 'Office 365 (Beta)')});
- }
- }
-
- return (
- <SettingsGroup>
- <DropdownSetting
- id='oauthType'
- values={oauthTypes}
- label={
- <FormattedMessage
- id='admin.oauth.select'
- defaultMessage='Select OAuth 2.0 Service Provider:'
- />
- }
- helpText={helpText}
- value={this.state.oauthType}
- onChange={this.changeType}
- />
- {contents}
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/password_settings.jsx b/webapp/components/admin_console/password_settings.jsx
deleted file mode 100644
index 6f39269c0..000000000
--- a/webapp/components/admin_console/password_settings.jsx
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import AdminSettings from './admin_settings.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-import Setting from './setting.jsx';
-import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-
-export default class PasswordSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
-
- this.getSampleErrorMsg = this.getSampleErrorMsg.bind(this);
-
- this.handlePasswordLengthChange = this.handlePasswordLengthChange.bind(this);
- this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
-
- this.state = Object.assign(this.state, {
- passwordMinimumLength: props.config.PasswordSettings.MinimumLength,
- passwordLowercase: props.config.PasswordSettings.Lowercase,
- passwordNumber: props.config.PasswordSettings.Number,
- passwordUppercase: props.config.PasswordSettings.Uppercase,
- passwordSymbol: props.config.PasswordSettings.Symbol,
- maximumLoginAttempts: props.config.ServiceSettings.MaximumLoginAttempts
- });
-
- // Update sample message from config settings
- this.sampleErrorMsg = null;
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
- let sampleErrorMsgId = 'user.settings.security.passwordError';
- if (props.config.PasswordSettings.Lowercase) {
- sampleErrorMsgId += 'Lowercase';
- }
- if (props.config.PasswordSettings.Uppercase) {
- sampleErrorMsgId += 'Uppercase';
- }
- if (props.config.PasswordSettings.Number) {
- sampleErrorMsgId += 'Number';
- }
- if (props.config.PasswordSettings.Symbol) {
- sampleErrorMsgId += 'Symbol';
- }
- this.sampleErrorMsg = (
- <FormattedMessage
- id={sampleErrorMsgId}
- default='Your password must contain between {min} and {max} characters.'
- values={{
- min: (this.state.passwordMinimumLength || Constants.MIN_PASSWORD_LENGTH),
- max: Constants.MAX_PASSWORD_LENGTH
- }}
- />
- );
- }
- }
-
- getConfigFromState(config) {
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
- config.PasswordSettings.MinimumLength = this.parseIntNonZero(this.state.passwordMinimumLength, Constants.MIN_PASSWORD_LENGTH);
- config.PasswordSettings.Lowercase = this.refs.lowercase.checked;
- config.PasswordSettings.Uppercase = this.refs.uppercase.checked;
- config.PasswordSettings.Number = this.refs.number.checked;
- config.PasswordSettings.Symbol = this.refs.symbol.checked;
- }
-
- config.ServiceSettings.MaximumLoginAttempts = this.parseIntNonZero(this.state.maximumLoginAttempts);
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- passwordMinimumLength: config.PasswordSettings.MinimumLength,
- passwordLowercase: config.PasswordSettings.Lowercase,
- passwordNumber: config.PasswordSettings.Number,
- passwordUppercase: config.PasswordSettings.Uppercase,
- passwordSymbol: config.PasswordSettings.Symbol,
- maximumLoginAttempts: config.ServiceSettings.MaximumLoginAttempts
- };
- }
-
- getSampleErrorMsg(minLength) {
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
- if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) {
- return (
- <FormattedMessage
- id='user.settings.security.passwordMinLength'
- default='Invalid minimum length, cannot show preview.'
- />
- );
- }
- let sampleErrorMsgId = 'user.settings.security.passwordError';
- if (this.refs.lowercase.checked) {
- sampleErrorMsgId += 'Lowercase';
- }
- if (this.refs.uppercase.checked) {
- sampleErrorMsgId += 'Uppercase';
- }
- if (this.refs.number.checked) {
- sampleErrorMsgId += 'Number';
- }
- if (this.refs.symbol.checked) {
- sampleErrorMsgId += 'Symbol';
- }
- return (
- <FormattedMessage
- id={sampleErrorMsgId}
- default='Your password must contain between {min} and {max} characters.'
- values={{
- min: (minLength || Constants.MIN_PASSWORD_LENGTH),
- max: Constants.MAX_PASSWORD_LENGTH
- }}
- />
- );
- }
-
- return null;
- }
-
- handlePasswordLengthChange(id, value) {
- this.sampleErrorMsg = this.getSampleErrorMsg(value);
- this.handleChange(id, value);
- }
-
- handleCheckboxChange(id, value) {
- this.sampleErrorMsg = this.getSampleErrorMsg(this.state.passwordMinimumLength);
- this.handleChange(id, value);
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.security.password'
- defaultMessage='Password'
- />
- );
- }
-
- renderSettings() {
- let passwordSettings = null;
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
- passwordSettings = (
- <div>
- <TextSetting
- id='passwordMinimumLength'
- label={
- <FormattedMessage
- id='admin.password.minimumLength'
- defaultMessage='Minimum Password Length:'
- />
- }
- placeholder={Utils.localizeMessage('admin.password.minimumLengthExample', 'Ex "5"')}
- helpText={
- <FormattedMessage
- id='admin.password.minimumLengthDescription'
- defaultMessage='Minimum number of characters required for a valid password. Must be a whole number greater than or equal to {min} and less than or equal to {max}.'
- values={{
- min: Constants.MIN_PASSWORD_LENGTH,
- max: Constants.MAX_PASSWORD_LENGTH
- }}
- />
- }
- value={this.state.passwordMinimumLength}
- onChange={this.handlePasswordLengthChange}
- />
- <Setting
- label={
- <FormattedMessage
- id='passwordRequirements'
- defaultMessage='Password Requirements:'
- />
- }
- >
- <div>
- <label className='checkbox-inline'>
- <input
- type='checkbox'
- ref='lowercase'
- defaultChecked={this.state.passwordLowercase}
- name='admin.password.lowercase'
- onChange={this.handleCheckboxChange}
- />
- <FormattedMessage
- id='admin.password.lowercase'
- defaultMessage='At least one lowercase letter'
- />
- </label>
- </div>
- <div>
- <label className='checkbox-inline'>
- <input
- type='checkbox'
- ref='uppercase'
- defaultChecked={this.state.passwordUppercase}
- name='admin.password.uppercase'
- onChange={this.handleCheckboxChange}
- />
- <FormattedMessage
- id='admin.password.uppercase'
- defaultMessage='At least one uppercase letter'
- />
- </label>
- </div>
- <div>
- <label className='checkbox-inline'>
- <input
- type='checkbox'
- ref='number'
- defaultChecked={this.state.passwordNumber}
- name='admin.password.number'
- onChange={this.handleCheckboxChange}
- />
- <FormattedMessage
- id='admin.password.number'
- defaultMessage='At least one number'
- />
- </label>
- </div>
- <div>
- <label className='checkbox-inline'>
- <input
- type='checkbox'
- ref='symbol'
- defaultChecked={this.state.passwordSymbol}
- name='admin.password.symbol'
- onChange={this.handleCheckboxChange}
- />
- <FormattedMessage
- id='admin.password.symbol'
- defaultMessage='At least one symbol (e.g. "~!@#$%^&*()")'
- />
- </label>
- </div>
- <div>
- <br/>
- <label>
- <FormattedMessage
- id='admin.password.preview'
- defaultMessage='Error message preview:'
- />
- </label>
- <br/>
- {this.sampleErrorMsg}
- </div>
- </Setting>
- </div>
- );
- }
-
- return (
- <SettingsGroup>
- {passwordSettings}
- <TextSetting
- id='maximumLoginAttempts'
- label={
- <FormattedMessage
- id='admin.service.attemptTitle'
- defaultMessage='Maximum Login Attempts:'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.attemptExample', 'Ex "10"')}
- helpText={
- <FormattedMessage
- id='admin.service.attemptDescription'
- defaultMessage='Login attempts allowed before user is locked out and required to reset password via email.'
- />
- }
- value={this.state.maximumLoginAttempts}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/plugin_settings/index.js b/webapp/components/admin_console/plugin_settings/index.js
deleted file mode 100644
index 469d4ee2e..000000000
--- a/webapp/components/admin_console/plugin_settings/index.js
+++ /dev/null
@@ -1,27 +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 {uploadPlugin, removePlugin, getPlugins} from 'mattermost-redux/actions/admin';
-
-import PluginSettings from './plugin_settings.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- plugins: state.entities.admin.plugins
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- uploadPlugin,
- removePlugin,
- getPlugins
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(PluginSettings);
diff --git a/webapp/components/admin_console/plugin_settings/plugin_settings.jsx b/webapp/components/admin_console/plugin_settings/plugin_settings.jsx
deleted file mode 100644
index 286e05c06..000000000
--- a/webapp/components/admin_console/plugin_settings/plugin_settings.jsx
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import LoadingScreen from 'components/loading_screen.jsx';
-import Banner from 'components/admin_console/banner.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-export default class PluginSettings extends React.Component {
- static propTypes = {
-
- /*
- * The config
- */
- config: PropTypes.object.isRequired,
-
- /*
- * Plugins object with ids as keys and manifests as values
- */
- plugins: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /*
- * Function to upload a plugin
- */
- uploadPlugin: PropTypes.func.isRequired,
-
- /*
- * Function to remove a plugin
- */
- removePlugin: PropTypes.func.isRequired,
-
- /*
- * Function to get installed plugins
- */
- getPlugins: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- loading: true,
- fileSelected: false,
- fileName: null,
- serverError: null
- };
- }
-
- componentDidMount() {
- this.props.actions.getPlugins().then(
- () => this.setState({loading: false})
- );
- }
-
- handleChange = () => {
- const element = this.refs.fileInput;
- if (element.files.length > 0) {
- this.setState({fileSelected: true, fileName: element.files[0].name});
- }
- }
-
- handleSubmit = async (e) => {
- e.preventDefault();
-
- const element = this.refs.fileInput;
- if (element.files.length === 0) {
- return;
- }
- const file = element.files[0];
-
- this.setState({uploading: true});
-
- const {error} = await this.props.actions.uploadPlugin(file);
- this.setState({fileSelected: false, fileName: null, uploading: false});
- Utils.clearFileInput(element);
-
- if (error) {
- if (error.server_error_id === 'app.plugin.activate.app_error') {
- this.setState({serverError: Utils.localizeMessage('admin.plugin.error.activate', 'Unable to upload the plugin. It may conflict with another plugin on your server.')});
- } else if (error.server_error_id === 'app.plugin.extract.app_error') {
- this.setState({serverError: Utils.localizeMessage('admin.plugin.error.extract', 'Encountered an error when extracting the plugin. Review your plugin file content and try again.')});
- } else {
- this.setState({serverError: error.message});
- }
- }
- }
-
- handleRemove = async (pluginId) => {
- this.setState({removing: pluginId});
-
- const {error} = await this.props.actions.removePlugin(pluginId);
- this.setState({removing: null});
-
- if (error) {
- this.setState({serverError: error.message});
- }
- }
-
- render() {
- let serverError = '';
- if (this.state.serverError) {
- serverError = <div className='col-sm-12'><div className='form-group has-error half'><label className='control-label'>{this.state.serverError}</label></div></div>;
- }
-
- let btnClass = 'btn';
- if (this.state.fileSelected) {
- btnClass = 'btn btn-primary';
- }
-
- let fileName;
- if (this.state.fileName) {
- fileName = this.state.fileName;
- }
-
- let uploadButtonText;
- if (this.state.uploading) {
- uploadButtonText = (
- <FormattedMessage
- id='admin.plugin.uploading'
- defaultMessage='Uploading...'
- />
- );
- } else {
- uploadButtonText = (
- <FormattedMessage
- id='admin.plugin.upload'
- defaultMessage='Upload'
- />
- );
- }
-
- let activePluginsList;
- let activePluginsContainer;
- const plugins = Object.values(this.props.plugins);
- if (this.state.loading) {
- activePluginsList = <LoadingScreen/>;
- } else if (plugins.length === 0) {
- activePluginsContainer = (
- <FormattedMessage
- id='admin.plugin.no_plugins'
- defaultMessage='No active plugins.'
- />
- );
- } else {
- activePluginsList = plugins.map(
- (p) => {
- let removeButtonText;
- if (this.state.removing === p.id) {
- removeButtonText = (
- <FormattedMessage
- id='admin.plugin.removing'
- defaultMessage='Removing...'
- />
- );
- } else {
- removeButtonText = (
- <FormattedMessage
- id='admin.plugin.remove'
- defaultMessage='Remove'
- />
- );
- }
-
- return (
- <div key={p.id}>
- <div>
- <strong>
- <FormattedMessage
- id='admin.plugin.id'
- defaultMessage='ID:'
- />
- </strong>
- {' ' + p.id}
- </div>
- <div className='padding-top'>
- <strong>
- <FormattedMessage
- id='admin.plugin.desc'
- defaultMessage='Description:'
- />
- </strong>
- {' ' + p.description}
- </div>
- <div className='padding-top'>
- <a
- disabled={this.state.removing === p.id}
- onClick={() => this.handleRemove(p.id)}
- >
- {removeButtonText}
- </a>
- </div>
- <hr/>
- </div>
- );
- }
- );
-
- activePluginsContainer = (
- <div className='alert alert-transparent'>
- {activePluginsList}
- </div>
- );
- }
-
- return (
- <div className='wrapper--fixed'>
- <h3 className='admin-console-header'>
- <FormattedMessage
- id='admin.plugin.title'
- defaultMessage='Plugins (experimental)'
- />
- </h3>
- <Banner
- title={<div/>}
- description={
- <FormattedHTMLMessage
- id='admin.plugin.banner'
- defaultMessage='Plugins are experimental stage and are not yet recommended for use in production environments. <br/><br/> Webapp plugins will require users to refresh their browsers or desktop apps before the plugin will take effect. Similarly when a plugin is removed, users will continue to see the plugin until they refresh their browser or app.'
- />
- }
- />
- <form
- className='form-horizontal'
- role='form'
- >
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- >
- <FormattedMessage
- id='admin.plugin.uploadTitle'
- defaultMessage='Upload Plugin: '
- />
- </label>
- <div className='col-sm-8'>
- <div className='file__upload'>
- <button className='btn btn-primary'>
- <FormattedMessage
- id='admin.plugin.choose'
- defaultMessage='Choose File'
- />
- </button>
- <input
- ref='fileInput'
- type='file'
- accept='.gz'
- onChange={this.handleChange}
- />
- </div>
- <button
- className={btnClass}
- disabled={!this.state.fileSelected}
- onClick={this.handleSubmit}
- >
- {uploadButtonText}
- </button>
- <div className='help-text no-margin'>
- {fileName}
- </div>
- {serverError}
- <p className='help-text'>
- <FormattedHTMLMessage
- id='admin.plugin.uploadDesc'
- defaultMessage='Upload a plugin for your Mattermost server. Adding or removing a webapp plugin requires users to refresh their browser or Desktop App before taking effect. See <a href="https://about.mattermost.com/default-plugins">documentation</a> to learn more.'
- />
- </p>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- >
- <FormattedMessage
- id='admin.plugin.activeTitle'
- defaultMessage='Active Plugins: '
- />
- </label>
- <div className='col-sm-8 padding-top'>
- {activePluginsContainer}
- </div>
- </div>
- </form>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/policy_settings.jsx b/webapp/components/admin_console/policy_settings.jsx
deleted file mode 100644
index f689efd82..000000000
--- a/webapp/components/admin_console/policy_settings.jsx
+++ /dev/null
@@ -1,413 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import SettingsGroup from './settings_group.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import RadioSetting from './radio_setting.jsx';
-import PostEditSetting from './post_edit_setting.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import TextSetting from './text_setting.jsx';
-import ColorSetting from './color_setting.jsx';
-
-import Constants from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-export default class PolicySettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.RestrictPostDelete = this.state.restrictPostDelete;
- config.ServiceSettings.AllowEditPost = this.state.allowEditPost;
- config.ServiceSettings.PostEditTimeLimit = this.parseIntNonZero(this.state.postEditTimeLimit, Constants.DEFAULT_POST_EDIT_TIME_LIMIT);
- config.TeamSettings.RestrictTeamInvite = this.state.restrictTeamInvite;
- config.TeamSettings.RestrictPublicChannelCreation = this.state.restrictPublicChannelCreation;
- config.TeamSettings.RestrictPrivateChannelCreation = this.state.restrictPrivateChannelCreation;
- config.TeamSettings.RestrictPublicChannelManagement = this.state.restrictPublicChannelManagement;
- config.TeamSettings.RestrictPrivateChannelManagement = this.state.restrictPrivateChannelManagement;
- config.TeamSettings.RestrictPublicChannelDeletion = this.state.restrictPublicChannelDeletion;
- config.TeamSettings.RestrictPrivateChannelDeletion = this.state.restrictPrivateChannelDeletion;
- config.TeamSettings.RestrictPrivateChannelManageMembers = this.state.restrictPrivateChannelManageMembers;
- config.AnnouncementSettings.EnableBanner = this.state.enableBanner;
- config.AnnouncementSettings.BannerText = this.state.bannerText;
- config.AnnouncementSettings.BannerColor = this.state.bannerColor;
- config.AnnouncementSettings.BannerTextColor = this.state.bannerTextColor;
- config.AnnouncementSettings.AllowBannerDismissal = this.state.allowBannerDismissal;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- restrictPostDelete: config.ServiceSettings.RestrictPostDelete,
- allowEditPost: config.ServiceSettings.AllowEditPost,
- postEditTimeLimit: config.ServiceSettings.PostEditTimeLimit,
- restrictTeamInvite: config.TeamSettings.RestrictTeamInvite,
- restrictPublicChannelCreation: config.TeamSettings.RestrictPublicChannelCreation,
- restrictPrivateChannelCreation: config.TeamSettings.RestrictPrivateChannelCreation,
- restrictPublicChannelManagement: config.TeamSettings.RestrictPublicChannelManagement,
- restrictPrivateChannelManagement: config.TeamSettings.RestrictPrivateChannelManagement,
- restrictPublicChannelDeletion: config.TeamSettings.RestrictPublicChannelDeletion,
- restrictPrivateChannelDeletion: config.TeamSettings.RestrictPrivateChannelDeletion,
- restrictPrivateChannelManageMembers: config.TeamSettings.RestrictPrivateChannelManageMembers,
- enableBanner: config.AnnouncementSettings.EnableBanner,
- bannerText: config.AnnouncementSettings.BannerText,
- bannerColor: config.AnnouncementSettings.BannerColor,
- bannerTextColor: config.AnnouncementSettings.BannerTextColor,
- allowBannerDismissal: config.AnnouncementSettings.AllowBannerDismissal
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.general.policy'
- defaultMessage='Policy'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <DropdownSetting
- id='restrictTeamInvite'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAll', 'All team members')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.teamInviteTitle'
- defaultMessage='Enable sending team invites from:'
- />
- }
- value={this.state.restrictTeamInvite}
- onChange={this.handleChange}
- helpText={
- <FormattedHTMLMessage
- id='admin.general.policy.teamInviteDescription'
- defaultMessage='Set policy on who can invite others to a team using <b>Send Email Invite</b> to invite new users by email, or the <b>Get Team Invite Link</b> and <b>Add Members to Team</b> options from the Main Menu. If <b>Get Team Invite Link</b> is used to share a link, you can expire the invite code from <b>Team Settings</b> > <b>Invite Code</b> after the desired users join the team.'
- />
- }
- />
- <DropdownSetting
- id='restrictPublicChannelCreation'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAll', 'All team members')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPublicChannelCreationTitle'
- defaultMessage='Enable public channel creation for:'
- />
- }
- value={this.state.restrictPublicChannelCreation}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.policy.restrictPublicChannelCreationDescription'
- defaultMessage='Set policy on who can create public channels.'
- />
- }
- />
- <DropdownSetting
- id='restrictPublicChannelManagement'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAllChannel', 'All channel members')},
- {value: Constants.PERMISSIONS_CHANNEL_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsChannelAdmin', 'Channel, Team and System Admins')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPublicChannelManagementTitle'
- defaultMessage='Enable public channel renaming for:'
- />
- }
- value={this.state.restrictPublicChannelManagement}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.policy.restrictPublicChannelManagementDescription'
- defaultMessage='Set policy on who can rename and set the header or purpose for public channels.'
- />
- }
- />
- <DropdownSetting
- id='restrictPublicChannelDeletion'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAllChannel', 'All channel members')},
- {value: Constants.PERMISSIONS_CHANNEL_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsChannelAdmin', 'Channel, Team and System Admins')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPublicChannelDeletionTitle'
- defaultMessage='Enable public channel deletion for:'
- />
- }
- value={this.state.restrictPublicChannelDeletion}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.policy.restrictPublicChannelDeletionDescription'
- defaultMessage='Set policy on who can delete public channels. Deleted channels can be recovered from the database using a {commandLineToolLink}.'
- values={{
- commandLineToolLink: (
- <a
- href='https://docs.mattermost.com/administration/command-line-tools.html'
- target='_blank'
- rel='noopener noreferrer'
- >
- <FormattedMessage
- id='admin.general.policy.restrictPublicChannelDeletionCommandLineToolLink'
- defaultMessage='command line tool'
- />
- </a>
- )
- }}
- />
- }
- />
- <DropdownSetting
- id='restrictPrivateChannelCreation'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAll', 'All team members')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelCreationTitle'
- defaultMessage='Enable private channel creation for:'
- />
- }
- value={this.state.restrictPrivateChannelCreation}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelCreationDescription'
- defaultMessage='Set policy on who can create private channels.'
- />
- }
- />
- <DropdownSetting
- id='restrictPrivateChannelManagement'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAllChannel', 'All channel members')},
- {value: Constants.PERMISSIONS_CHANNEL_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsChannelAdmin', 'Channel, Team and System Admins')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelManagementTitle'
- defaultMessage='Enable private channel renaming for:'
- />
- }
- value={this.state.restrictPrivateChannelManagement}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelManagementDescription'
- defaultMessage='Set policy on who can rename and set the header or purpose for private channels.'
- />
- }
- />
- <DropdownSetting
- id='restrictPrivateChannelManageMembers'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAllChannel', 'All channel members')},
- {value: Constants.PERMISSIONS_CHANNEL_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsChannelAdmin', 'Channel, Team and System Admins')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelManageMembersTitle'
- defaultMessage='Enable managing of private group members for:'
- />
- }
- value={this.state.restrictPrivateChannelManageMembers}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelManageMembersDescription'
- defaultMessage='Set policy on who can add and remove members from private groups.'
- />
- }
- />
- <DropdownSetting
- id='restrictPrivateChannelDeletion'
- values={[
- {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAllChannel', 'All channel members')},
- {value: Constants.PERMISSIONS_CHANNEL_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsChannelAdmin', 'Channel, Team and System Admins')},
- {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
- {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelDeletionTitle'
- defaultMessage='Enable private channel deletion for:'
- />
- }
- value={this.state.restrictPrivateChannelDeletion}
- onChange={this.handleChange}
- helpText={
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelDeletionDescription'
- defaultMessage='Set policy on who can delete private channels. Deleted channels can be recovered from the database using a {commandLineToolLink}.'
- values={{
- commandLineToolLink: (
- <a
- href='https://docs.mattermost.com/administration/command-line-tools.html'
- target='_blank'
- rel='noopener noreferrer'
- >
- <FormattedMessage
- id='admin.general.policy.restrictPrivateChannelDeletionCommandLineToolLink'
- defaultMessage='command line tool'
- />
- </a>
- )
- }}
- />
- }
- />
- <RadioSetting
- id='restrictPostDelete'
- values={[
- {value: Constants.PERMISSIONS_DELETE_POST_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsDeletePostAll', 'Message authors can delete their own messages, and Administrators can delete any message')},
- {value: Constants.PERMISSIONS_DELETE_POST_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsDeletePostAdmin', 'Team Admins and System Admins')},
- {value: Constants.PERMISSIONS_DELETE_POST_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsDeletePostSystemAdmin', 'System Admins')}
- ]}
- label={
- <FormattedMessage
- id='admin.general.policy.restrictPostDeleteTitle'
- defaultMessage='Allow which users to delete messages:'
- />
- }
- value={this.state.restrictPostDelete}
- onChange={this.handleChange}
- helpText={
- <FormattedHTMLMessage
- id='admin.general.policy.restrictPostDeleteDescription'
- defaultMessage='Set policy on who has permission to delete messages.'
- />
- }
- />
- <PostEditSetting
- id='allowEditPost'
- timeLimitId='postEditTimeLimit'
- label={
- <FormattedMessage
- id='admin.general.policy.allowEditPostTitle'
- defaultMessage='Allow users to edit their messages:'
- />
- }
- value={this.state.allowEditPost}
- timeLimitValue={this.state.postEditTimeLimit}
- onChange={this.handleChange}
- helpText={
- <FormattedHTMLMessage
- id='admin.general.policy.allowEditPostDescription'
- defaultMessage='Set policy on the length of time authors have to edit their messages after posting.'
- />
- }
- />
- <BooleanSetting
- id='enableBanner'
- label={
- <FormattedMessage
- id='admin.general.policy.enableBannerTitle'
- defaultMessage='Enable Announcement Banner:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.general.policy.enableBannerDesc'
- defaultMessage='Enable an announcement banner across all teams.'
- />
- }
- value={this.state.enableBanner}
- onChange={this.handleChange}
- />
- <TextSetting
- id='bannerText'
- label={
- <FormattedMessage
- id='admin.general.policy.bannerTextTitle'
- defaultMessage='Banner Text:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.general.policy.bannerTextDesc'
- defaultMessage='Text that will appear in the announcement banner.'
- />
- }
- value={this.state.bannerText}
- onChange={this.handleChange}
- disabled={!this.state.enableBanner}
- />
- <ColorSetting
- id='bannerColor'
- label={
- <FormattedMessage
- id='admin.general.policy.bannerColorTitle'
- defaultMessage='Banner Color:'
- />
- }
- value={this.state.bannerColor}
- onChange={this.handleChange}
- disabled={!this.state.enableBanner}
- />
- <ColorSetting
- id='bannerTextColor'
- label={
- <FormattedMessage
- id='admin.general.policy.bannerTextColorTitle'
- defaultMessage='Banner Text Color:'
- />
- }
- value={this.state.bannerTextColor}
- onChange={this.handleChange}
- disabled={!this.state.enableBanner}
- />
- <BooleanSetting
- id='allowBannerDismissal'
- label={
- <FormattedMessage
- id='admin.general.policy.allowBannerDismissalTitle'
- defaultMessage='Allow Banner Dismissal:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.general.policy.allowBannerDismissalDesc'
- defaultMessage='When true, users can dismiss the banner until its next update. When false, the banner is permanently visible until it is turned off by the System Admin.'
- />
- }
- value={this.state.allowBannerDismissal}
- onChange={this.handleChange}
- disabled={!this.state.enableBanner}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/post_edit_setting.jsx b/webapp/components/admin_console/post_edit_setting.jsx
deleted file mode 100644
index 08fafc14b..000000000
--- a/webapp/components/admin_console/post_edit_setting.jsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import Setting from './setting.jsx';
-
-import Constants from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-export default class PostEditSetting extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- this.handleTimeLimitChange = this.handleTimeLimitChange.bind(this);
- }
-
- handleChange(e) {
- this.props.onChange(this.props.id, e.target.value);
- }
-
- handleTimeLimitChange(e) {
- this.props.onChange(this.props.timeLimitId, e.target.value);
- }
-
- render() {
- return (
- <Setting
- label={this.props.label}
- inputId={this.props.id}
- helpText={this.props.helpText}
- >
- <div className='radio'>
- <label>
- <input
- type='radio'
- value={Constants.ALLOW_EDIT_POST_ALWAYS}
- name={this.props.id}
- checked={this.props.value === Constants.ALLOW_EDIT_POST_ALWAYS}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- {Utils.localizeMessage('admin.general.policy.allowEditPostAlways', 'Any time')}
- </label>
- </div>
- <div className='radio'>
- <label>
- <input
- type='radio'
- value={Constants.ALLOW_EDIT_POST_NEVER}
- name={this.props.id}
- checked={this.props.value === Constants.ALLOW_EDIT_POST_NEVER}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- {Utils.localizeMessage('admin.general.policy.allowEditPostNever', 'Never')}
- </label>
- </div>
- <div className='radio form-inline'>
- <label>
- <input
- type='radio'
- value={Constants.ALLOW_EDIT_POST_TIME_LIMIT}
- name={this.props.id}
- checked={this.props.value === Constants.ALLOW_EDIT_POST_TIME_LIMIT}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- <input
- type='text'
- value={this.props.timeLimitValue}
- className='form-control'
- name={this.props.timeLimitId}
- onChange={this.handleTimeLimitChange}
- disabled={this.props.disabled || this.props.value !== Constants.ALLOW_EDIT_POST_TIME_LIMIT}
- />
- <span> {Utils.localizeMessage('admin.general.policy.allowEditPostTimeLimit', 'seconds after posting')}</span>
- </label>
- </div>
- </Setting>
- );
- }
-}
-
-PostEditSetting.defaultProps = {
- isDisabled: false
-};
-
-PostEditSetting.propTypes = {
- id: PropTypes.string.isRequired,
- timeLimitId: PropTypes.string.isRequired,
- label: PropTypes.node.isRequired,
- value: PropTypes.string.isRequired,
- timeLimitValue: PropTypes.number.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool,
- helpText: PropTypes.node
-};
diff --git a/webapp/components/admin_console/privacy_settings.jsx b/webapp/components/admin_console/privacy_settings.jsx
deleted file mode 100644
index 92fcb3e88..000000000
--- a/webapp/components/admin_console/privacy_settings.jsx
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-
-export default class PrivacySettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.PrivacySettings.ShowEmailAddress = this.state.showEmailAddress;
- config.PrivacySettings.ShowFullName = this.state.showFullName;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- showEmailAddress: config.PrivacySettings.ShowEmailAddress,
- showFullName: config.PrivacySettings.ShowFullName
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.general.privacy'
- defaultMessage='Privacy'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='showEmailAddress'
- label={
- <FormattedMessage
- id='admin.privacy.showEmailTitle'
- defaultMessage='Show Email Address: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.privacy.showEmailDescription'
- defaultMessage='When false, hides the email address of members from everyone except System Administrators.'
- />
- }
- value={this.state.showEmailAddress}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='showFullName'
- label={
- <FormattedMessage
- id='admin.privacy.showFullNameTitle'
- defaultMessage='Show Full Name: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.privacy.showFullNameDescription'
- defaultMessage='When false, hides the full name of members from everyone except System Administrators. Username is shown in place of full name.'
- />
- }
- value={this.state.showFullName}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/public_link_settings.jsx b/webapp/components/admin_console/public_link_settings.jsx
deleted file mode 100644
index a10574353..000000000
--- a/webapp/components/admin_console/public_link_settings.jsx
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import GeneratedSetting from './generated_setting.jsx';
-import SettingsGroup from './settings_group.jsx';
-
-export default class PublicLinkSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.FileSettings.EnablePublicLink = this.state.enablePublicLink;
- config.FileSettings.PublicLinkSalt = this.state.publicLinkSalt;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enablePublicLink: config.FileSettings.EnablePublicLink,
- publicLinkSalt: config.FileSettings.PublicLinkSalt
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.security.public_links'
- defaultMessage='Public Links'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enablePublicLink'
- label={
- <FormattedMessage
- id='admin.image.shareTitle'
- defaultMessage='Enable Public File Links: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.image.shareDescription'
- defaultMessage='Allow users to share public links to files and images.'
- />
- }
- value={this.state.enablePublicLink}
- onChange={this.handleChange}
- />
- <GeneratedSetting
- id='publicLinkSalt'
- label={
- <FormattedMessage
- id='admin.image.publicLinkTitle'
- defaultMessage='Public Link Salt:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.image.publicLinkDescription'
- defaultMessage='32-character salt added to signing of public image links. Randomly generated on install. Click "Regenerate" to create new salt.'
- />
- }
- value={this.state.publicLinkSalt}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/push_settings.jsx b/webapp/components/admin_console/push_settings.jsx
deleted file mode 100644
index b5f788c86..000000000
--- a/webapp/components/admin_console/push_settings.jsx
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import Constants from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-const PUSH_NOTIFICATIONS_OFF = 'off';
-const PUSH_NOTIFICATIONS_MHPNS = 'mhpns';
-const PUSH_NOTIFICATIONS_MTPNS = 'mtpns';
-const PUSH_NOTIFICATIONS_CUSTOM = 'custom';
-
-export default class PushSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.canSave = this.canSave.bind(this);
-
- this.handleAgreeChange = this.handleAgreeChange.bind(this);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- canSave() {
- return this.state.pushNotificationServerType !== PUSH_NOTIFICATIONS_MHPNS || this.state.agree;
- }
-
- handleAgreeChange(e) {
- this.setState({
- agree: e.target.checked
- });
- }
-
- handleChange(id, value) {
- if (id === 'pushNotificationServerType') {
- this.setState({
- agree: false
- });
-
- if (value === PUSH_NOTIFICATIONS_MHPNS) {
- this.setState({
- pushNotificationServer: Constants.MHPNS
- });
- } else if (value === PUSH_NOTIFICATIONS_MTPNS) {
- this.setState({
- pushNotificationServer: Constants.MTPNS
- });
- }
- }
-
- super.handleChange(id, value);
- }
-
- getConfigFromState(config) {
- config.EmailSettings.SendPushNotifications = this.state.pushNotificationServerType !== PUSH_NOTIFICATIONS_OFF;
- config.EmailSettings.PushNotificationServer = this.state.pushNotificationServer.trim();
- config.EmailSettings.PushNotificationContents = this.state.pushNotificationContents;
-
- return config;
- }
-
- getStateFromConfig(config) {
- let pushNotificationServerType = PUSH_NOTIFICATIONS_CUSTOM;
- let agree = false;
- if (!config.EmailSettings.SendPushNotifications) {
- pushNotificationServerType = PUSH_NOTIFICATIONS_OFF;
- } else if (config.EmailSettings.PushNotificationServer === Constants.MHPNS &&
- global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MHPNS === 'true') {
- pushNotificationServerType = PUSH_NOTIFICATIONS_MHPNS;
- agree = true;
- } else if (config.EmailSettings.PushNotificationServer === Constants.MTPNS) {
- pushNotificationServerType = PUSH_NOTIFICATIONS_MTPNS;
- }
-
- let pushNotificationServer = config.EmailSettings.PushNotificationServer;
- if (pushNotificationServerType === PUSH_NOTIFICATIONS_MTPNS) {
- pushNotificationServer = Constants.MTPNS;
- } else if (pushNotificationServerType === PUSH_NOTIFICATIONS_MHPNS) {
- pushNotificationServer = Constants.MHPNS;
- }
-
- return {
- pushNotificationServerType,
- pushNotificationServer,
- pushNotificationContents: config.EmailSettings.PushNotificationContents,
- agree
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.notifications.title'
- defaultMessage='Notification Settings'
- />
- );
- }
-
- renderSettings() {
- const pushNotificationServerTypes = [];
- pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_OFF, text: Utils.localizeMessage('admin.email.pushOff', 'Do not send push notifications')});
- if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MHPNS === 'true') {
- pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_MHPNS, text: Utils.localizeMessage('admin.email.mhpns', 'Use encrypted, production-quality HPNS connection to iOS and Android apps')});
- }
- pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_MTPNS, text: Utils.localizeMessage('admin.email.mtpns', 'Use iOS and Android apps on iTunes and Google Play with TPNS')});
- pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_CUSTOM, text: Utils.localizeMessage('admin.email.selfPush', 'Manually enter Push Notification Service location')});
-
- let sendHelpText = null;
- let pushServerHelpText = null;
- if (this.state.pushNotificationServerType === PUSH_NOTIFICATIONS_OFF) {
- sendHelpText = (
- <FormattedHTMLMessage
- id='admin.email.pushOffHelp'
- defaultMessage='Please see <a href="https://about.mattermost.com/default-mobile-push-notifications/" target="_blank">documentation on push notifications</a> to learn more about setup options.'
- />
- );
- } else if (this.state.pushNotificationServerType === PUSH_NOTIFICATIONS_MHPNS) {
- pushServerHelpText = (
- <FormattedHTMLMessage
- id='admin.email.mhpnsHelp'
- defaultMessage='Download <a href="https://about.mattermost.com/mattermost-ios-app/" target="_blank">Mattermost iOS app</a> from iTunes. Download <a href="https://about.mattermost.com/mattermost-android-app/" target="_blank">Mattermost Android app</a> from Google Play. Learn more about the <a href="https://about.mattermost.com/default-hpns/" target="_blank">Mattermost Hosted Push Notification Service</a>.'
- />
- );
- } else if (this.state.pushNotificationServerType === PUSH_NOTIFICATIONS_MTPNS) {
- pushServerHelpText = (
- <FormattedHTMLMessage
- id='admin.email.mtpnsHelp'
- defaultMessage='Download <a href="https://about.mattermost.com/mattermost-ios-app/" target="_blank">Mattermost iOS app</a> from iTunes. Download <a href="https://about.mattermost.com/mattermost-android-app/" target="_blank">Mattermost Android app</a> from Google Play. Learn more about the <a href="https://about.mattermost.com/default-tpns/" target="_blank">Mattermost Test Push Notification Service</a>.'
- />
- );
- } else {
- pushServerHelpText = (
- <FormattedHTMLMessage
- id='admin.email.easHelp'
- defaultMessage='Learn more about compiling and deploying your own mobile apps from an <a href="https://about.mattermost.com/default-enterprise-app-store" target="_blank">Enterprise App Store</a>.'
- />
- );
- }
-
- let tosCheckbox;
- if (this.state.pushNotificationServerType === PUSH_NOTIFICATIONS_MHPNS) {
- tosCheckbox = (
- <div className='form-group'>
- <div className='col-sm-4'/>
- <div className='col-sm-8'>
- <input
- type='checkbox'
- ref='agree'
- checked={this.state.agree}
- onChange={this.handleAgreeChange}
- />
- <FormattedHTMLMessage
- id='admin.email.agreeHPNS'
- defaultMessage=' I understand and accept the Mattermost Hosted Push Notification Service <a href="https://about.mattermost.com/hpns-terms/" target="_blank">Terms of Service</a> and <a href="https://about.mattermost.com/hpns-privacy/" target="_blank">Privacy Policy</a>.'
- />
- </div>
- </div>
- );
- }
-
- return (
- <SettingsGroup
- header={
- <FormattedMessage
- id='admin.notifications.push'
- defaultMessage='Mobile Push'
- />
- }
- >
- <DropdownSetting
- id='pushNotificationServerType'
- values={pushNotificationServerTypes}
- label={
- <FormattedMessage
- id='admin.email.pushTitle'
- defaultMessage='Enable Push Notifications: '
- />
- }
- value={this.state.pushNotificationServerType}
- onChange={this.handleChange}
- helpText={sendHelpText}
- />
- {tosCheckbox}
- <TextSetting
- id='pushNotificationServer'
- label={
- <FormattedMessage
- id='admin.email.pushServerTitle'
- defaultMessage='Push Notification Server:'
- />
- }
- placeholder={Utils.localizeMessage('admin.email.pushServerEx', 'E.g.: "http://push-test.mattermost.com"')}
- helpText={pushServerHelpText}
- value={this.state.pushNotificationServer}
- onChange={this.handleChange}
- disabled={this.state.pushNotificationServerType !== PUSH_NOTIFICATIONS_CUSTOM}
- />
- <DropdownSetting
- id='pushNotificationContents'
- values={[
- {value: 'generic_no_channel', text: Utils.localizeMessage('admin.email.genericNoChannelPushNotification', '"Send generic description with only sender name')},
- {value: 'generic', text: Utils.localizeMessage('admin.email.genericPushNotification', 'Send generic description with sender and channel names')},
- {value: 'full', text: Utils.localizeMessage('admin.email.fullPushNotification', 'Send full message snippet')}
- ]}
- label={
- <FormattedMessage
- id='admin.email.pushContentTitle'
- defaultMessage='Push Notification Contents:'
- />
- }
- value={this.state.pushNotificationContents}
- onChange={this.handleChange}
- disabled={this.state.pushNotificationServerType === PUSH_NOTIFICATIONS_OFF}
- helpText={
- <FormattedHTMLMessage
- id='admin.email.pushContentDesc'
- defaultMessage='"Send generic description with only sender name" includes only the name of the person who sent the message in push notifications, with no information about channel name or message contents.<br /><br />"Send generic description with sender and channel names" includes the name of the person who sent the message and the channel it was sent in, but not the message text.<br /><br />"Send full message snippet" includes a message excerpt in push notifications, which may contain confidential information sent in messages. If your Push Notification Service is outside your firewall, it is *highly recommended* this option only be used with an "https" protocol to encrypt the connection.'
- />
- }
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/radio_setting.jsx b/webapp/components/admin_console/radio_setting.jsx
deleted file mode 100644
index 7a6c2e459..000000000
--- a/webapp/components/admin_console/radio_setting.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import Setting from './setting.jsx';
-
-export default class RadioSetting extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- }
-
- handleChange(e) {
- this.props.onChange(this.props.id, e.target.value);
- }
-
- render() {
- const options = [];
- for (const {value, text} of this.props.values) {
- options.push(
- <div className='radio'>
- <label>
- <input
- type='radio'
- value={value}
- name={this.props.id}
- checked={value === this.props.value}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- {text}
- </label>
- </div>
- );
- }
-
- return (
- <Setting
- label={this.props.label}
- inputId={this.props.id}
- helpText={this.props.helpText}
- >
- {options}
- </Setting>
- );
- }
-}
-
-RadioSetting.defaultProps = {
- isDisabled: false
-};
-
-RadioSetting.propTypes = {
- id: PropTypes.string.isRequired,
- values: PropTypes.array.isRequired,
- label: PropTypes.node.isRequired,
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool,
- helpText: PropTypes.node
-};
diff --git a/webapp/components/admin_console/rate_settings.jsx b/webapp/components/admin_console/rate_settings.jsx
deleted file mode 100644
index a0cf14f75..000000000
--- a/webapp/components/admin_console/rate_settings.jsx
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class RateSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.RateLimitSettings.Enable = this.state.enable;
- config.RateLimitSettings.PerSec = this.parseIntNonZero(this.state.perSec);
- config.RateLimitSettings.MaxBurst = this.parseIntNonZero(this.state.maxBurst);
- config.RateLimitSettings.MemoryStoreSize = this.parseIntNonZero(this.state.memoryStoreSize);
- config.RateLimitSettings.VaryByRemoteAddr = this.state.varyByRemoteAddr;
- config.RateLimitSettings.VaryByHeader = this.state.varyByHeader;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enable: config.RateLimitSettings.Enable,
- perSec: config.RateLimitSettings.PerSec,
- maxBurst: config.RateLimitSettings.MaxBurst,
- memoryStoreSize: config.RateLimitSettings.MemoryStoreSize,
- varyByRemoteAddr: config.RateLimitSettings.VaryByRemoteAddr,
- varyByHeader: config.RateLimitSettings.VaryByHeader
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.rate.title'
- defaultMessage='Rate Limit Settings'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <div className='banner'>
- <div className='banner__content'>
- <FormattedMessage
- id='admin.rate.noteDescription'
- defaultMessage='Changing properties in this section will require a server restart before taking effect.'
- />
- </div>
- </div>
- <BooleanSetting
- id='enable'
- label={
- <FormattedMessage
- id='admin.rate.enableLimiterTitle'
- defaultMessage='Enable Rate Limiting: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.rate.enableLimiterDescription'
- defaultMessage='When true, APIs are throttled at rates specified below.'
- />
- }
- value={this.state.enable}
- onChange={this.handleChange}
- />
- <TextSetting
- id='perSec'
- label={
- <FormattedMessage
- id='admin.rate.queriesTitle'
- defaultMessage='Maximum Queries per Second:'
- />
- }
- placeholder={Utils.localizeMessage('admin.rate.queriesExample', 'Ex "10"')}
- helpText={
- <FormattedMessage
- id='admin.rate.queriesDescription'
- defaultMessage='Throttles API at this number of requests per second.'
- />
- }
- value={this.state.perSec}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='maxBurst'
- label={
- <FormattedMessage
- id='admin.rate.maxBurst'
- defaultMessage='Maximum Burst Size:'
- />
- }
- placeholder={Utils.localizeMessage('admin.rate.maxBurstExample', 'Ex "100"')}
- helpText={
- <FormattedMessage
- id='admin.rate.maxBurstDescription'
- defaultMessage='Maximum number of requests allowed beyond the per second query limit.'
- />
- }
- value={this.state.maxBurst}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='memoryStoreSize'
- label={
- <FormattedMessage
- id='admin.rate.memoryTitle'
- defaultMessage='Memory Store Size:'
- />
- }
- placeholder={Utils.localizeMessage('admin.rate.memoryExample', 'Ex "10000"')}
- helpText={
- <FormattedMessage
- id='admin.rate.memoryDescription'
- defaultMessage='Maximum number of users sessions connected to the system as determined by "Vary rate limit by remote address" and "Vary rate limit by HTTP header".'
- />
- }
- value={this.state.memoryStoreSize}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <BooleanSetting
- id='varyByRemoteAddr'
- label={
- <FormattedMessage
- id='admin.rate.remoteTitle'
- defaultMessage='Vary rate limit by remote address: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.rate.remoteDescription'
- defaultMessage='When true, rate limit API access by IP address.'
- />
- }
- value={this.state.varyByRemoteAddr}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='varyByHeader'
- label={
- <FormattedMessage
- id='admin.rate.httpHeaderTitle'
- defaultMessage='Vary rate limit by HTTP header:'
- />
- }
- placeholder={Utils.localizeMessage('admin.rate.httpHeaderExample', 'Ex "X-Real-IP", "X-Forwarded-For"')}
- helpText={
- <FormattedMessage
- id='admin.rate.httpHeaderDescription'
- defaultMessage='When filled in, vary rate limiting by HTTP header field specified (e.g. when configuring NGINX set to "X-Real-IP", when configuring AmazonELB set to "X-Forwarded-For").'
- />
- }
- value={this.state.varyByHeader}
- onChange={this.handleChange}
- disabled={!this.state.enable || this.state.varyByRemoteAddr}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/remove_file_setting.jsx b/webapp/components/admin_console/remove_file_setting.jsx
deleted file mode 100644
index ff453d9fc..000000000
--- a/webapp/components/admin_console/remove_file_setting.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Setting from './setting.jsx';
-
-export default class RemoveFileSetting extends Setting {
- static get propTypes() {
- return {
- id: PropTypes.string.isRequired,
- label: PropTypes.node.isRequired,
- helpText: PropTypes.node,
- removeButtonText: PropTypes.node.isRequired,
- removingText: PropTypes.node,
- fileName: PropTypes.string.isRequired,
- onSubmit: PropTypes.func.isRequired,
- disabled: PropTypes.bool
- };
- }
-
- constructor(props) {
- super(props);
- this.handleRemove = this.handleRemove.bind(this);
- }
-
- handleRemove(e) {
- e.preventDefault();
-
- $(this.refs.remove_button).button('loading');
- this.props.onSubmit(this.props.id, () => {
- $(this.refs.remove_button).button('reset');
- });
- }
-
- render() {
- return (
- <Setting
- label={this.props.label}
- helpText={this.props.helpText}
- inputId={this.props.id}
- >
- <div>
- <div className='help-text remove-filename'>
- {this.props.fileName}
- </div>
- <button
- className='btn btn-danger'
- onClick={this.handleRemove}
- ref='remove_button'
- disabled={this.props.disabled}
- data-loading-text={`<span class='glyphicon glyphicon-refresh glyphicon-refresh-animate'></span> ${this.props.removingText}`}
- >
- {this.props.removeButtonText}
- </button>
- </div>
- </Setting>
- );
- }
-}
diff --git a/webapp/components/admin_console/request_button/request_button.jsx b/webapp/components/admin_console/request_button/request_button.jsx
deleted file mode 100644
index e78d0443d..000000000
--- a/webapp/components/admin_console/request_button/request_button.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 {FormattedMessage} from 'react-intl';
-import PropTypes from 'prop-types';
-
-import * as Utils from 'utils/utils.jsx';
-
-/**
- * A button which, when clicked, performs an action and displays
- * its outcome as either success, or failure accompanied by the
- * `message` property of the `err` object.
- */
-export default class RequestButton extends React.Component {
- static propTypes = {
-
- /**
- * The action to be called to carry out the request.
- */
- requestAction: PropTypes.func.isRequired,
-
- /**
- * A component that displays help text for the request button.
- *
- * Typically, this will be a <FormattedMessage/>.
- */
- helpText: PropTypes.element.isRequired,
-
- /**
- * A component to be displayed on the button.
- *
- * Typically, this will be a <FormattedMessage/>
- */
- buttonText: PropTypes.element.isRequired,
-
- /**
- * The element to display as the field label.
- *
- * Typically, this will be a <FormattedMessage/>
- */
- label: PropTypes.element,
-
- /**
- * True if the button form control should be disabled, otherwise false.
- */
- disabled: PropTypes.bool,
-
- /**
- * True if the config needs to be saved before running the request, otherwise false.
- *
- * If set to true, the action provided in the `saveConfigAction` property will be
- * called before the action provided in the `requestAction` property, with the later
- * only being called if the former is successful.
- */
- saveNeeded: PropTypes.bool,
-
- /**
- * Action to be called to save the config, if saveNeeded is set to true.
- */
- saveConfigAction: PropTypes.func,
-
- /**
- * True if the success message should be show when the request completes successfully,
- * otherwise false.
- */
- showSuccessMessage: PropTypes.bool,
-
- /**
- * The message to show when the request completes successfully.
- */
- successMessage: PropTypes.shape({
-
- /**
- * The i18n string ID for the success message.
- */
- id: PropTypes.string.isRequired,
-
- /**
- * The i18n default value for the success message.
- */
- defaultMessage: PropTypes.string.isRequired
- }),
-
- /**
- * The message to show when the request returns an error.
- */
- errorMessage: PropTypes.shape({
-
- /**
- * The i18n string ID for the error message.
- */
- id: PropTypes.string.isRequired,
-
- /**
- * The i18n default value for the error message.
- *
- * The placeholder {error} may be used to include the error message returned
- * by the server in response to the failed request.
- */
- defaultMessage: PropTypes.string.isRequired
- }),
-
- /**
- * True if the {error} placeholder for the `errorMessage` property should include both
- * the `message` and `detailed_error` properties of the error returned from the server,
- * otherwise false to include only the `message` property.
- */
- includeDetailedError: PropTypes.bool,
-
- /**
- * An element to display adjacent to the request button.
- */
- alternativeActionElement: PropTypes.element
- }
-
- static defaultProps = {
- disabled: false,
- saveNeeded: false,
- showSuccessMessage: true,
- includeDetailedError: false,
- successMessage: {
- id: 'admin.requestButton.requestSuccess',
- defaultMessage: 'Test Successful'
- },
- errorMessage: {
- id: 'admin.requestButton.requestFailure',
- defaultMessage: 'Test Failure: {error}'
- }
- }
-
- constructor(props) {
- super(props);
-
- this.handleRequest = this.handleRequest.bind(this);
-
- this.state = {
- busy: false,
- fail: null,
- success: false
- };
- }
-
- handleRequest(e) {
- e.preventDefault();
-
- this.setState({
- busy: true,
- fail: null,
- success: false
- });
-
- const doRequest = () => { //eslint-disable-line func-style
- this.props.requestAction(
- () => {
- this.setState({
- busy: false,
- success: true
- });
- },
- (err) => {
- let errMsg = err.message;
- if (this.props.includeDetailedError) {
- errMsg += ' - ' + err.detailed_error;
- }
-
- this.setState({
- busy: false,
- fail: errMsg
- });
- }
- );
- };
-
- if (this.props.saveNeeded) {
- this.props.saveConfigAction(doRequest);
- } else {
- doRequest();
- }
- }
-
- render() {
- let message = null;
- if (this.state.fail) {
- message = (
- <div>
- <div className='alert alert-warning'>
- <i className='fa fa-warning'/>
- <FormattedMessage
- id={this.props.errorMessage.id}
- defaultMessage={this.props.errorMessage.defaultMessage}
- values={{
- error: this.state.fail
- }}
- />
- </div>
- </div>
- );
- } else if (this.state.success && this.props.showSuccessMessage) {
- message = (
- <div>
- <div className='alert alert-success'>
- <i className='fa fa-success'/>
- <FormattedMessage
- id={this.props.successMessage.id}
- defaultMessage={this.props.successMessage.defaultMessage}
- />
- </div>
- </div>
- );
- }
-
- let contents = null;
- if (this.state.busy) {
- contents = (
- <span>
- <span className='fa fa-refresh icon--rotate'/>
- {Utils.localizeMessage('admin.requestButton.loading', ' Loading...')}
- </span>
- );
- } else {
- contents = this.props.buttonText;
- }
-
- let widgetClassNames = 'col-sm-8';
- let label = null;
- if (this.props.label) {
- label = (
- <label
- className='control-label col-sm-4'
- >
- {this.props.label}
- </label>
- );
- } else {
- widgetClassNames = 'col-sm-offset-4 ' + widgetClassNames;
- }
-
- return (
- <div className='form-group'>
- {label}
- <div className={widgetClassNames}>
- <div>
- <button
- className='btn btn-default'
- onClick={this.handleRequest}
- disabled={this.props.disabled}
- >
- {contents}
- </button>
- {this.props.alternativeActionElement}
- {message}
- </div>
- <div className='help-text'>
- {this.props.helpText}
- </div>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/reset_password_modal.jsx b/webapp/components/admin_console/reset_password_modal.jsx
deleted file mode 100644
index 0a38adda1..000000000
--- a/webapp/components/admin_console/reset_password_modal.jsx
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import * as Utils from 'utils/utils.jsx';
-import {Modal} from 'react-bootstrap';
-
-import {FormattedMessage} from 'react-intl';
-
-import {adminResetPassword} from 'actions/admin_actions.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-export default class ResetPasswordModal extends React.Component {
- static propTypes = {
- user: PropTypes.object,
- show: PropTypes.bool.isRequired,
- onModalSubmit: PropTypes.func,
- onModalDismissed: PropTypes.func
- };
-
- static defaultProps = {
- show: false
- };
-
- constructor(props) {
- super(props);
-
- this.doSubmit = this.doSubmit.bind(this);
- this.doCancel = this.doCancel.bind(this);
-
- this.state = {
- serverError: null
- };
- }
-
- doSubmit(e) {
- e.preventDefault();
- const password = this.refs.password.value;
-
- const passwordErr = Utils.isValidPassword(password);
- if (passwordErr) {
- this.setState({serverError: passwordErr});
- return;
- }
- this.setState({serverError: null});
-
- adminResetPassword(
- this.props.user.id,
- password,
- () => {
- this.props.onModalSubmit(this.props.user);
- },
- (err) => {
- this.setState({serverError: err.message});
- }
- );
- }
-
- doCancel() {
- this.setState({serverError: null});
- this.props.onModalDismissed();
- }
-
- render() {
- const user = this.props.user;
- if (user == null) {
- return <div/>;
- }
-
- let urlClass = 'input-group input-group--limit';
- let serverError = null;
-
- if (this.state.serverError) {
- urlClass += ' has-error';
- serverError = <div className='has-error'><p className='input__help error'>{this.state.serverError}</p></div>;
- }
-
- let title;
- if (user.auth_service) {
- title = (
- <FormattedMessage
- id='admin.reset_password.titleSwitch'
- defaultMessage='Switch Account to Email/Password'
- />
- );
- } else {
- title = (
- <FormattedMessage
- id='admin.reset_password.titleReset'
- defaultMessage='Reset Password'
- />
- );
- }
-
- return (
- <Modal
- show={this.props.show}
- onHide={this.doCancel}
- >
- <Modal.Header closeButton={true}>
- <Modal.Title>
- {title}
- </Modal.Title>
- </Modal.Header>
- <form
- role='form'
- className='form-horizontal'
- >
- <Modal.Body>
- <div className='form-group'>
- <div className='col-sm-10'>
- <div className={urlClass}>
- <span
- data-toggle='tooltip'
- title='New Password'
- className='input-group-addon'
- >
- <FormattedMessage
- id='admin.reset_password.newPassword'
- defaultMessage='New Password'
- />
- </span>
- <input
- type='password'
- ref='password'
- className='form-control'
- maxLength='22'
- autoFocus={true}
- tabIndex='1'
- />
- </div>
- {serverError}
- </div>
- </div>
- </Modal.Body>
- <Modal.Footer>
- <button
- type='button'
- className='btn btn-default'
- onClick={this.doCancel}
- >
- <FormattedMessage
- id='admin.reset_password.close'
- defaultMessage='Close'
- />
- </button>
- <button
- onClick={this.doSubmit}
- type='submit'
- className='btn btn-primary'
- tabIndex='2'
- >
- <FormattedMessage
- id='admin.reset_password.select'
- defaultMessage='Select'
- />
- </button>
- </Modal.Footer>
- </form>
- </Modal>
- );
- }
-}
diff --git a/webapp/components/admin_console/revoke_token_button/index.js b/webapp/components/admin_console/revoke_token_button/index.js
deleted file mode 100644
index 6fada1bcc..000000000
--- a/webapp/components/admin_console/revoke_token_button/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 {revokeUserAccessToken} from 'mattermost-redux/actions/users';
-
-import RevokeTokenButton from './revoke_token_button.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- revokeUserAccessToken
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(RevokeTokenButton);
diff --git a/webapp/components/admin_console/revoke_token_button/revoke_token_button.jsx b/webapp/components/admin_console/revoke_token_button/revoke_token_button.jsx
deleted file mode 100644
index 4829a0cde..000000000
--- a/webapp/components/admin_console/revoke_token_button/revoke_token_button.jsx
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage} from 'react-intl';
-
-import {trackEvent} from 'actions/diagnostics_actions.jsx';
-
-export default class RevokeTokenButton extends React.PureComponent {
- static propTypes = {
-
- /*
- * Token id to revoke
- */
- tokenId: PropTypes.string.isRequired,
-
- /*
- * Function to call on error
- */
- onError: PropTypes.func.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * Function to revoke a user access token
- */
- revokeUserAccessToken: PropTypes.func.isRequired
- }).isRequired
- };
-
- handleClick = async (e) => {
- e.preventDefault();
-
- const {error} = await this.props.actions.revokeUserAccessToken(this.props.tokenId);
- trackEvent('system_console', 'revoke_user_access_token');
-
- if (error) {
- this.props.onError(error.message);
- }
- }
-
- render() {
- return (
- <button
- className='btn btn-danger'
- onClick={this.handleClick}
- >
- <FormattedMessage
- id='admin.revoke_token_button.delete'
- defaultMessage='Delete'
- />
- </button>
- );
- }
-}
diff --git a/webapp/components/admin_console/saml_settings.jsx b/webapp/components/admin_console/saml_settings.jsx
deleted file mode 100644
index 98c02e571..000000000
--- a/webapp/components/admin_console/saml_settings.jsx
+++ /dev/null
@@ -1,584 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import TextSetting from './text_setting.jsx';
-import FileUploadSetting from './file_upload_setting.jsx';
-import RemoveFileSetting from './remove_file_setting.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import * as AdminActions from 'actions/admin_actions.jsx';
-
-export default class SamlSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- this.uploadCertificate = this.uploadCertificate.bind(this);
- this.removeCertificate = this.removeCertificate.bind(this);
- }
-
- getConfigFromState(config) {
- config.SamlSettings.Enable = this.state.enable;
- config.SamlSettings.Verify = this.state.verify;
- config.SamlSettings.Encrypt = this.state.encrypt;
- config.SamlSettings.IdpUrl = this.state.idpUrl;
- config.SamlSettings.IdpDescriptorUrl = this.state.idpDescriptorUrl;
- config.SamlSettings.AssertionConsumerServiceURL = this.state.assertionConsumerServiceURL;
- config.SamlSettings.IdpCertificateFile = this.state.idpCertificateFile;
- config.SamlSettings.PublicCertificateFile = this.state.publicCertificateFile;
- config.SamlSettings.PrivateKeyFile = this.state.privateKeyFile;
- config.SamlSettings.FirstNameAttribute = this.state.firstNameAttribute;
- config.SamlSettings.LastNameAttribute = this.state.lastNameAttribute;
- config.SamlSettings.EmailAttribute = this.state.emailAttribute;
- config.SamlSettings.UsernameAttribute = this.state.usernameAttribute;
- config.SamlSettings.NicknameAttribute = this.state.nicknameAttribute;
- config.SamlSettings.PositionAttribute = this.state.positionAttribute;
- config.SamlSettings.LocaleAttribute = this.state.localeAttribute;
- config.SamlSettings.LoginButtonText = this.state.loginButtonText;
-
- return config;
- }
-
- getStateFromConfig(config) {
- const settings = config.SamlSettings;
-
- return {
- enable: settings.Enable,
- verify: settings.Verify,
- encrypt: settings.Encrypt,
- idpUrl: settings.IdpUrl,
- idpDescriptorUrl: settings.IdpDescriptorUrl,
- assertionConsumerServiceURL: settings.AssertionConsumerServiceURL,
- idpCertificateFile: settings.IdpCertificateFile,
- publicCertificateFile: settings.PublicCertificateFile,
- privateKeyFile: settings.PrivateKeyFile,
- firstNameAttribute: settings.FirstNameAttribute,
- lastNameAttribute: settings.LastNameAttribute,
- emailAttribute: settings.EmailAttribute,
- usernameAttribute: settings.UsernameAttribute,
- nicknameAttribute: settings.NicknameAttribute,
- positionAttribute: settings.PositionAttribute,
- localeAttribute: settings.LocaleAttribute,
- loginButtonText: settings.LoginButtonText
- };
- }
-
- componentWillMount() {
- AdminActions.samlCertificateStatus(
- (data) => {
- const files = {};
- if (!data.idp_certificate_file) {
- files.idpCertificateFile = '';
- }
-
- if (!data.public_certificate_file) {
- files.publicCertificateFile = '';
- }
-
- if (!data.private_key_file) {
- files.privateKeyFile = '';
- }
- this.setState(files);
- }
- );
- }
-
- uploadCertificate(id, file, callback) {
- const complete = () => {
- const fileName = file.name;
- this.handleChange(id, fileName);
- this.setState({[id]: fileName, [`${id}Error`]: null});
- if (callback && typeof callback === 'function') {
- callback();
- }
- };
-
- function fail(error) {
- if (callback && typeof callback === 'function') {
- callback(error.message);
- }
- }
-
- if (id === 'idpCertificateFile') {
- AdminActions.uploadIdpSamlCertificate(file, complete, fail);
- } else if (id === 'publicCertificateFile') {
- AdminActions.uploadPublicSamlCertificate(file, complete, fail);
- } else if (id === 'privateKeyFile') {
- AdminActions.uploadPrivateSamlCertificate(file, complete, fail);
- }
- }
-
- removeCertificate(id, callback) {
- const complete = () => {
- this.handleChange(id, '');
- this.setState({[id]: null, [`${id}Error`]: null});
- };
-
- const fail = (error) => {
- if (callback && typeof callback === 'function') {
- callback();
- }
- this.setState({[id]: null, [`${id}Error`]: error.message});
- };
-
- if (id === 'idpCertificateFile') {
- AdminActions.removeIdpSamlCertificate(complete, fail);
- } else if (id === 'publicCertificateFile') {
- AdminActions.removePublicSamlCertificate(complete, fail);
- } else if (id === 'privateKeyFile') {
- AdminActions.removePrivateSamlCertificate(complete, fail);
- }
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.authentication.saml'
- defaultMessage='SAML 2.0'
- />
- );
- }
-
- renderSettings() {
- const licenseEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.SAML === 'true';
- if (!licenseEnabled) {
- return null;
- }
-
- let idpCert;
- let privKey;
- let pubCert;
-
- if (this.state.idpCertificateFile) {
- idpCert = (
- <RemoveFileSetting
- id='idpCertificateFile'
- label={
- <FormattedMessage
- id='admin.saml.idpCertificateFileTitle'
- defaultMessage='Identity Provider Public Certificate:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.idpCertificateFileRemoveDesc'
- defaultMessage='Remove the public authentication certificate issued by your Identity Provider.'
- />
- }
- removeButtonText={Utils.localizeMessage('admin.saml.remove.idp_certificate', 'Remove Identity Provider Certificate')}
- removingText={Utils.localizeMessage('admin.saml.removing.certificate', 'Removing Certificate...')}
- fileName={this.state.idpCertificateFile}
- onSubmit={this.removeCertificate}
- disabled={!this.state.enable}
- />
- );
- } else {
- idpCert = (
- <FileUploadSetting
- id='idpCertificateFile'
- label={
- <FormattedMessage
- id='admin.saml.idpCertificateFileTitle'
- defaultMessage='Identity Provider Public Certificate:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.idpCertificateFileDesc'
- defaultMessage='The public authentication certificate issued by your Identity Provider.'
- />
- }
- uploadingText={Utils.localizeMessage('admin.saml.uploading.certificate', 'Uploading Certificate...')}
- disabled={!this.state.enable}
- fileType='.crt,.cer'
- onSubmit={this.uploadCertificate}
- error={this.state.idpCertificateFileError}
- />
- );
- }
-
- if (this.state.privateKeyFile) {
- privKey = (
- <RemoveFileSetting
- id='privateKeyFile'
- label={
- <FormattedMessage
- id='admin.saml.privateKeyFileTitle'
- defaultMessage='Service Provider Private Key:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.privateKeyFileFileRemoveDesc'
- defaultMessage='Remove the private key used to decrypt SAML Assertions from the Identity Provider.'
- />
- }
- removeButtonText={Utils.localizeMessage('admin.saml.remove.privKey', 'Remove Service Provider Private Key')}
- removingText={Utils.localizeMessage('admin.saml.removing.privKey', 'Removing Private Key...')}
- fileName={this.state.privateKeyFile}
- onSubmit={this.removeCertificate}
- disabled={!this.state.enable || !this.state.encrypt}
- />
- );
- } else {
- privKey = (
- <FileUploadSetting
- id='privateKeyFile'
- label={
- <FormattedMessage
- id='admin.saml.privateKeyFileTitle'
- defaultMessage='Service Provider Private Key:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.privateKeyFileFileDesc'
- defaultMessage='The private key used to decrypt SAML Assertions from the Identity Provider.'
- />
- }
- uploadingText={Utils.localizeMessage('admin.saml.uploading.privateKey', 'Uploading Private Key...')}
- disabled={!this.state.enable || !this.state.encrypt}
- fileType='.key'
- onSubmit={this.uploadCertificate}
- error={this.state.privateKeyFileError}
- />
- );
- }
-
- if (this.state.publicCertificateFile) {
- pubCert = (
- <RemoveFileSetting
- id='publicCertificateFile'
- label={
- <FormattedMessage
- id='admin.saml.publicCertificateFileTitle'
- defaultMessage='Service Provider Public Certificate:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.publicCertificateFileRemoveDesc'
- defaultMessage='Remove the certificate used to generate the signature on a SAML request to the Identity Provider for a service provider initiated SAML login, when Mattermost is the Service Provider.'
- />
- }
- removeButtonText={Utils.localizeMessage('admin.saml.remove.sp_certificate', 'Remove Service Provider Certificate')}
- removingText={Utils.localizeMessage('admin.saml.removing.certificate', 'Removing Certificate...')}
- fileName={this.state.publicCertificateFile}
- onSubmit={this.removeCertificate}
- disabled={!this.state.enable || !this.state.encrypt}
- />
- );
- } else {
- pubCert = (
- <FileUploadSetting
- id='publicCertificateFile'
- label={
- <FormattedMessage
- id='admin.saml.publicCertificateFileTitle'
- defaultMessage='Service Provider Public Certificate:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.publicCertificateFileDesc'
- defaultMessage='The certificate used to generate the signature on a SAML request to the Identity Provider for a service provider initiated SAML login, when Mattermost is the Service Provider.'
- />
- }
- uploadingText={Utils.localizeMessage('admin.saml.uploading.certificate', 'Uploading Certificate...')}
- disabled={!this.state.enable || !this.state.encrypt}
- fileType='.crt,.cer'
- onSubmit={this.uploadCertificate}
- error={this.state.publicCertificateFileError}
- />
- );
- }
-
- return (
- <SettingsGroup>
- <div className='banner'>
- <div className='banner__content'>
- <FormattedHTMLMessage
- id='admin.saml.bannerDesc'
- defaultMessage='User attributes in SAML server, including user deactivation or removal, are updated in Mattermost during user login. Learn more at: <a href=\"https://docs.mattermost.com/deployment/sso-saml.html\">https://docs.mattermost.com/deployment/sso-saml.html</a>'
- />
- </div>
- </div>
- <BooleanSetting
- id='enable'
- label={
- <FormattedMessage
- id='admin.saml.enableTitle'
- defaultMessage='Enable Login With SAML 2.0:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.saml.enableDescription'
- defaultMessage='When true, Mattermost allows login using SAML 2.0. Please see <a href="http://docs.mattermost.com/deployment/sso-saml.html" target="_blank">documentation</a> to learn more about configuring SAML for Mattermost.'
- />
- }
- value={this.state.enable}
- onChange={this.handleChange}
- />
- <TextSetting
- id='idpUrl'
- label={
- <FormattedMessage
- id='admin.saml.idpUrlTitle'
- defaultMessage='SAML SSO URL:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.idpUrlEx', 'Ex "https://idp.example.org/SAML2/SSO/Login"')}
- helpText={
- <FormattedMessage
- id='admin.saml.idpUrlDesc'
- defaultMessage='The URL where Mattermost sends a SAML request to start login sequence.'
- />
- }
- value={this.state.idpUrl}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='idpDescriptorUrl'
- label={
- <FormattedMessage
- id='admin.saml.idpDescriptorUrlTitle'
- defaultMessage='Identity Provider Issuer URL:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.idpDescriptorUrlEx', 'Ex "https://idp.example.org/SAML2/issuer"')}
- helpText={
- <FormattedMessage
- id='admin.saml.idpDescriptorUrlDesc'
- defaultMessage='The issuer URL for the Identity Provider you use for SAML requests.'
- />
- }
- value={this.state.idpDescriptorUrl}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- {idpCert}
- <BooleanSetting
- id='verify'
- label={
- <FormattedMessage
- id='admin.saml.verifyTitle'
- defaultMessage='Verify Signature:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.verifyDescription'
- defaultMessage='When false, Mattermost will not verify that the signature sent from a SAML Response matches the Service Provider Login URL. Not recommended for production environments. For testing only.'
- />
- }
- value={this.state.verify}
- disabled={!this.state.enable}
- onChange={this.handleChange}
- />
- <TextSetting
- id='assertionConsumerServiceURL'
- label={
- <FormattedMessage
- id='admin.saml.assertionConsumerServiceURLTitle'
- defaultMessage='Service Provider Login URL:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.assertionConsumerServiceURLEx', 'Ex "https://<your-mattermost-url>/login/sso/saml"')}
- helpText={
- <FormattedMessage
- id='admin.saml.assertionConsumerServiceURLDesc'
- defaultMessage='Enter https://<your-mattermost-url>/login/sso/saml. Make sure you use HTTP or HTTPS in your URL depending on your server configuration. This field is also known as the Assertion Consumer Service URL.'
- />
- }
- value={this.state.assertionConsumerServiceURL}
- onChange={this.handleChange}
- disabled={!this.state.enable || !this.state.verify}
- />
- <BooleanSetting
- id='encrypt'
- label={
- <FormattedMessage
- id='admin.saml.encryptTitle'
- defaultMessage='Enable Encryption:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.saml.encryptDescription'
- defaultMessage='When false, Mattermost will not decrypt SAML Assertions encrypted with your Service Provider Public Certificate. Not recommended for production environments. For testing only.'
- />
- }
- value={this.state.encrypt}
- disabled={!this.state.enable}
- onChange={this.handleChange}
- />
- {privKey}
- {pubCert}
- <TextSetting
- id='emailAttribute'
- label={
- <FormattedMessage
- id='admin.saml.emailAttrTitle'
- defaultMessage='Email Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.emailAttrEx', 'Ex "Email" or "PrimaryEmail"')}
- helpText={
- <FormattedMessage
- id='admin.saml.emailAttrDesc'
- defaultMessage='The attribute in the SAML Assertion that will be used to populate the email addresses of users in Mattermost.'
- />
- }
- value={this.state.emailAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='usernameAttribute'
- label={
- <FormattedMessage
- id='admin.saml.usernameAttrTitle'
- defaultMessage='Username Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.usernameAttrEx', 'Ex "Username"')}
- helpText={
- <FormattedMessage
- id='admin.saml.usernameAttrDesc'
- defaultMessage='The attribute in the SAML Assertion that will be used to populate the username field in Mattermost.'
- />
- }
- value={this.state.usernameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='firstNameAttribute'
- label={
- <FormattedMessage
- id='admin.saml.firstnameAttrTitle'
- defaultMessage='First Name Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.firstnameAttrEx', 'Ex "FirstName"')}
- helpText={
- <FormattedMessage
- id='admin.saml.firstnameAttrDesc'
- defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the first name of users in Mattermost.'
- />
- }
- value={this.state.firstNameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='lastNameAttribute'
- label={
- <FormattedMessage
- id='admin.saml.lastnameAttrTitle'
- defaultMessage='Last Name Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.lastnameAttrEx', 'Ex "LastName"')}
- helpText={
- <FormattedMessage
- id='admin.saml.lastnameAttrDesc'
- defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the last name of users in Mattermost.'
- />
- }
- value={this.state.lastNameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='nicknameAttribute'
- label={
- <FormattedMessage
- id='admin.saml.nicknameAttrTitle'
- defaultMessage='Nickname Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.nicknameAttrEx', 'Ex "Nickname"')}
- helpText={
- <FormattedMessage
- id='admin.saml.nicknameAttrDesc'
- defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the nickname of users in Mattermost.'
- />
- }
- value={this.state.nicknameAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='positionAttribute'
- label={
- <FormattedMessage
- id='admin.saml.positionAttrTitle'
- defaultMessage='Position Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.positionAttrEx', 'E.g.: "Role"')}
- helpText={
- <FormattedMessage
- id='admin.saml.positionAttrDesc'
- defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the position of users in Mattermost.'
- />
- }
- value={this.state.positionAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='localeAttribute'
- label={
- <FormattedMessage
- id='admin.saml.localeAttrTitle'
- defaultMessage='Preferred Language Attribute:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.localeAttrEx', 'Ex "Locale" or "PrimaryLanguage"')}
- helpText={
- <FormattedMessage
- id='admin.saml.localeAttrDesc'
- defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the language of users in Mattermost.'
- />
- }
- value={this.state.localeAttribute}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- <TextSetting
- id='loginButtonText'
- label={
- <FormattedMessage
- id='admin.saml.loginButtonTextTitle'
- defaultMessage='Login Button Text:'
- />
- }
- placeholder={Utils.localizeMessage('admin.saml.loginButtonTextEx', 'Ex "With OKTA"')}
- helpText={
- <FormattedMessage
- id='admin.saml.loginButtonTextDesc'
- defaultMessage='(Optional) The text that appears in the login button on the login page. Defaults to "With SAML".'
- />
- }
- value={this.state.loginButtonText}
- onChange={this.handleChange}
- disabled={!this.state.enable}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/save_button.jsx b/webapp/components/admin_console/save_button.jsx
deleted file mode 100644
index 4d2b562da..000000000
--- a/webapp/components/admin_console/save_button.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {FormattedMessage} from 'react-intl';
-
-export default class SaveButton extends React.Component {
- static get propTypes() {
- return {
- saving: PropTypes.bool.isRequired,
- disabled: PropTypes.bool
- };
- }
-
- static get defaultProps() {
- return {
- disabled: false
- };
- }
-
- render() {
- const {saving, disabled, ...props} = this.props; // eslint-disable-line no-use-before-define
-
- let contents;
- if (saving) {
- contents = (
- <span>
- <span className='icon fa fa-refresh icon--rotate'/>
- <FormattedMessage
- id='admin.saving'
- defaultMessage='Saving Config...'
- />
- </span>
- );
- } else {
- contents = (
- <FormattedMessage
- id='admin.save'
- defaultMessage='Save'
- />
- );
- }
-
- let className = 'save-button btn';
- if (!disabled) {
- className += ' btn-primary';
- }
-
- return (
- <button
- type='submit'
- id='saveSetting'
- className={className}
- disabled={disabled}
- {...props}
- >
- {contents}
- </button>
- );
- }
-}
diff --git a/webapp/components/admin_console/server_logs/index.js b/webapp/components/admin_console/server_logs/index.js
deleted file mode 100644
index 3adacaf1a..000000000
--- a/webapp/components/admin_console/server_logs/index.js
+++ /dev/null
@@ -1,27 +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 {getLogs} from 'mattermost-redux/actions/admin';
-
-import * as Selectors from 'mattermost-redux/selectors/entities/admin';
-
-import Logs from './logs.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- logs: Selectors.getLogs(state)
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getLogs
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(Logs);
diff --git a/webapp/components/admin_console/server_logs/logs.jsx b/webapp/components/admin_console/server_logs/logs.jsx
deleted file mode 100644
index b0d8b38ac..000000000
--- a/webapp/components/admin_console/server_logs/logs.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import LoadingScreen from 'components/loading_screen.jsx';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage} from 'react-intl';
-
-export default class Logs extends React.PureComponent {
- static propTypes = {
-
- /*
- * Array of logs to render
- */
- logs: PropTypes.arrayOf(PropTypes.string).isRequired,
-
- actions: PropTypes.shape({
-
- /*
- * Function to fetch logs
- */
- getLogs: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- loadingLogs: true
- };
- }
-
- componentDidMount() {
- this.refs.logPanel.focus();
-
- this.props.actions.getLogs().then(
- () => this.setState({loadingLogs: false})
- );
- }
-
- componentDidUpdate() {
- // Scroll Down to get the latest logs
- var node = this.refs.logPanel;
- node.scrollTop = node.scrollHeight;
- node.focus();
- }
-
- reload = () => {
- this.setState({loadingLogs: true});
- this.props.actions.getLogs().then(
- () => this.setState({loadingLogs: false})
- );
- }
-
- render() {
- let content = null;
-
- if (this.state.loadingLogs) {
- content = <LoadingScreen/>;
- } else {
- content = [];
-
- for (let i = 0; i < this.props.logs.length; i++) {
- const style = {
- whiteSpace: 'nowrap',
- fontFamily: 'monospace'
- };
-
- if (this.props.logs[i].indexOf('[EROR]') > 0) {
- style.color = 'red';
- }
-
- content.push(<br key={'br_' + i}/>);
- content.push(
- <span
- key={'log_' + i}
- style={style}
- >
- {this.props.logs[i]}
- </span>
- );
- }
- }
-
- return (
- <div className='panel'>
- <h3 className='admin-console-header'>
- <FormattedMessage
- id='admin.logs.title'
- defaultMessage='Server Logs'
- />
- </h3>
- <div className='banner'>
- <div className='banner__content'>
- <FormattedMessage
- id='admin.logs.bannerDesc'
- defaultMessage='To look up users by User ID or Token ID, go to Reporting > Users and paste the ID into the search filter.'
- />
- </div>
- </div>
- <button
- type='submit'
- className='btn btn-primary'
- onClick={this.reload}
- >
- <FormattedMessage
- id='admin.logs.reload'
- defaultMessage='Reload'
- />
- </button>
- <div
- tabIndex='-1'
- ref='logPanel'
- className='log__panel'
- >
- {content}
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/session_settings.jsx b/webapp/components/admin_console/session_settings.jsx
deleted file mode 100644
index a36126789..000000000
--- a/webapp/components/admin_console/session_settings.jsx
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import {FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class SessionSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.ServiceSettings.SessionLengthWebInDays = this.parseIntNonZero(this.state.sessionLengthWebInDays);
- config.ServiceSettings.SessionLengthMobileInDays = this.parseIntNonZero(this.state.sessionLengthMobileInDays);
- config.ServiceSettings.SessionLengthSSOInDays = this.parseIntNonZero(this.state.sessionLengthSSOInDays);
- config.ServiceSettings.SessionCacheInMinutes = this.parseIntNonZero(this.state.sessionCacheInMinutes);
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- sessionLengthWebInDays: config.ServiceSettings.SessionLengthWebInDays,
- sessionLengthMobileInDays: config.ServiceSettings.SessionLengthMobileInDays,
- sessionLengthSSOInDays: config.ServiceSettings.SessionLengthSSOInDays,
- sessionCacheInMinutes: config.ServiceSettings.SessionCacheInMinutes
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.security.session'
- defaultMessage='Sessions'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <TextSetting
- id='sessionLengthWebInDays'
- label={
- <FormattedMessage
- id='admin.service.webSessionDays'
- defaultMessage='Session length AD/LDAP and email (days):'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.sessionDaysEx', 'Ex "30"')}
- helpText={
- <FormattedMessage
- id='admin.service.webSessionDaysDesc'
- defaultMessage='The number of days from the last time a user entered their credentials to the expiry of the users session. After changing this setting, the new session length will take effect after the next time the user enters their credentials.'
- />
- }
- value={this.state.sessionLengthWebInDays}
- onChange={this.handleChange}
- />
- <TextSetting
- id='sessionLengthMobileInDays'
- label={
- <FormattedMessage
- id='admin.service.mobileSessionDays'
- defaultMessage='Session length mobile (days):'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.sessionDaysEx', 'Ex "30"')}
- helpText={
- <FormattedMessage
- id='admin.service.mobileSessionDaysDesc'
- defaultMessage='The number of days from the last time a user entered their credentials to the expiry of the users session. After changing this setting, the new session length will take effect after the next time the user enters their credentials.'
- />
- }
- value={this.state.sessionLengthMobileInDays}
- onChange={this.handleChange}
- />
- <TextSetting
- id='sessionLengthSSOInDays'
- label={
- <FormattedMessage
- id='admin.service.ssoSessionDays'
- defaultMessage='Session length SSO (days):'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.sessionDaysEx', 'Ex "30"')}
- helpText={
- <FormattedMessage
- id='admin.service.ssoSessionDaysDesc'
- defaultMessage='The number of days from the last time a user entered their credentials to the expiry of the users session. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials. '
- />
- }
- value={this.state.sessionLengthSSOInDays}
- onChange={this.handleChange}
- />
- <TextSetting
- id='sessionCacheInMinutes'
- label={
- <FormattedMessage
- id='admin.service.sessionCache'
- defaultMessage='Session Cache (minutes):'
- />
- }
- placeholder={Utils.localizeMessage('admin.service.sessionDaysEx', 'Ex "30"')}
- helpText={
- <FormattedMessage
- id='admin.service.sessionCacheDesc'
- defaultMessage='The number of minutes to cache a session in memory.'
- />
- }
- value={this.state.sessionCacheInMinutes}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/setting.jsx b/webapp/components/admin_console/setting.jsx
deleted file mode 100644
index 9ef6554ac..000000000
--- a/webapp/components/admin_console/setting.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React, {PureComponent} from 'react';
-import PropTypes from 'prop-types';
-
-export default class Settings extends PureComponent {
- static propTypes = {
- inputId: PropTypes.string,
- label: PropTypes.node.isRequired,
- children: PropTypes.node.isRequired,
- helpText: PropTypes.node
- };
-
- render() {
- const {children, helpText, inputId, label} = this.props;
-
- return (
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor={inputId}
- >
- {label}
- </label>
- <div className='col-sm-8'>
- {children}
- <div className='help-text'>
- {helpText}
- </div>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/settings_group.jsx b/webapp/components/admin_console/settings_group.jsx
deleted file mode 100644
index 79f8dac97..000000000
--- a/webapp/components/admin_console/settings_group.jsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-export default class SettingsGroup extends React.Component {
- static get propTypes() {
- return {
- show: PropTypes.bool.isRequired,
- header: PropTypes.node,
- children: PropTypes.node
- };
- }
-
- static get defaultProps() {
- return {
- show: true
- };
- }
-
- render() {
- if (!this.props.show) {
- return null;
- }
-
- let header = null;
- if (this.props.header) {
- header = (
- <h4>
- {this.props.header}
- </h4>
- );
- }
-
- return (
- <div className='admin-settings__group'>
- {header}
- {this.props.children}
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/signup_settings.jsx b/webapp/components/admin_console/signup_settings.jsx
deleted file mode 100644
index b3ae6fe60..000000000
--- a/webapp/components/admin_console/signup_settings.jsx
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-import GeneratedSetting from './generated_setting.jsx';
-import SettingsGroup from './settings_group.jsx';
-
-export default class SignupSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.EmailSettings.RequireEmailVerification = this.state.requireEmailVerification;
- config.EmailSettings.InviteSalt = this.state.inviteSalt;
- config.TeamSettings.EnableOpenServer = this.state.enableOpenServer;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- requireEmailVerification: config.EmailSettings.RequireEmailVerification,
- inviteSalt: config.EmailSettings.InviteSalt,
- enableOpenServer: config.TeamSettings.EnableOpenServer
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.security.signup'
- defaultMessage='Signup'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='requireEmailVerification'
- label={
- <FormattedMessage
- id='admin.email.requireVerificationTitle'
- defaultMessage='Require Email Verification: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.email.requireVerificationDescription'
- defaultMessage='Typically set to true in production. When true, Mattermost requires email verification after account creation prior to allowing login. Developers may set this field to false so skip sending verification emails for faster development.'
- />
- }
- value={this.state.requireEmailVerification}
- onChange={this.handleChange}
- disabled={this.state.sendEmailNotifications}
- disabledText={
- <FormattedMessage
- id='admin.security.requireEmailVerification.disabled'
- defaultMessage='Email verification cannot be changed while sending emails is disabled.'
- />
- }
- />
- <GeneratedSetting
- id='inviteSalt'
- label={
- <FormattedMessage
- id='admin.email.inviteSaltTitle'
- defaultMessage='Email Invite Salt:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.email.inviteSaltDescription'
- defaultMessage='32-character salt added to signing of email invites. Randomly generated on install. Click "Regenerate" to create new salt.'
- />
- }
- value={this.state.inviteSalt}
- onChange={this.handleChange}
- disabled={this.state.sendEmailNotifications}
- disabledText={
- <FormattedMessage
- id='admin.security.inviteSalt.disabled'
- defaultMessage='Invite salt cannot be changed while sending emails is disabled.'
- />
- }
- />
- <BooleanSetting
- id='enableOpenServer'
- label={
- <FormattedMessage
- id='admin.team.openServerTitle'
- defaultMessage='Enable Open Server: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.team.openServerDescription'
- defaultMessage='When true, anyone can signup for a user account on this server without the need to be invited.'
- />
- }
- value={this.state.enableOpenServer}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/storage_settings.jsx b/webapp/components/admin_console/storage_settings.jsx
deleted file mode 100644
index 4b20a8b93..000000000
--- a/webapp/components/admin_console/storage_settings.jsx
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-
-const DRIVER_LOCAL = 'local';
-const DRIVER_S3 = 'amazons3';
-
-export default class StorageSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.FileSettings.EnableFileAttachments = this.state.enableFileAttachments;
- config.FileSettings.EnableMobileUpload = this.state.enableMobileUpload;
- config.FileSettings.EnableMobileDownload = this.state.enableMobileDownload;
- config.FileSettings.MaxFileSize = this.parseInt(this.state.maxFileSize) * 1024 * 1024;
- config.FileSettings.DriverName = this.state.driverName;
- config.FileSettings.Directory = this.state.directory;
- config.FileSettings.AmazonS3AccessKeyId = this.state.amazonS3AccessKeyId;
- config.FileSettings.AmazonS3SecretAccessKey = this.state.amazonS3SecretAccessKey;
- config.FileSettings.AmazonS3Bucket = this.state.amazonS3Bucket;
- config.FileSettings.AmazonS3Endpoint = this.state.amazonS3Endpoint;
- config.FileSettings.AmazonS3SSL = this.state.amazonS3SSL;
- config.FileSettings.AmazonS3SSE = this.state.amazonS3SSE;
- config.FileSettings.AmazonS3Trace = this.state.amazonS3Trace;
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableFileAttachments: config.FileSettings.EnableFileAttachments,
- enableMobileUpload: config.FileSettings.EnableMobileUpload,
- enableMobileDownload: config.FileSettings.EnableMobileDownload,
- maxFileSize: config.FileSettings.MaxFileSize / 1024 / 1024,
- driverName: config.FileSettings.DriverName,
- directory: config.FileSettings.Directory,
- amazonS3AccessKeyId: config.FileSettings.AmazonS3AccessKeyId,
- amazonS3SecretAccessKey: config.FileSettings.AmazonS3SecretAccessKey,
- amazonS3Bucket: config.FileSettings.AmazonS3Bucket,
- amazonS3Endpoint: config.FileSettings.AmazonS3Endpoint,
- amazonS3SSL: config.FileSettings.AmazonS3SSL,
- amazonS3SSE: config.FileSettings.AmazonS3SSE,
- amazonS3Trace: config.FileSettings.AmazonS3Trace
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.files.storage'
- defaultMessage='Storage'
- />
- );
- }
-
- renderSettings() {
- let amazonSSEComp;
- const mobileUploadDownloadSettings = [];
- if (window.mm_license.IsLicensed === 'true' && window.mm_license.Compliance === 'true') {
- mobileUploadDownloadSettings.push(
- <BooleanSetting
- key='enableMobileUpload'
- id='enableMobileUpload'
- label={
- <FormattedMessage
- id='admin.file.enableMobileUploadTitle'
- defaultMessage='Allow File Uploads on Mobile:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.file.enableMobileUploadDesc'
- defaultMessage='When false, disables file uploads on mobile apps. If Allow File Sharing is set to true, users can still upload files from a mobile web browser.'
- />
- }
- value={this.state.enableMobileUpload}
- onChange={this.handleChange}
- disabled={!this.state.enableFileAttachments}
- />
- );
-
- mobileUploadDownloadSettings.push(
- <BooleanSetting
- key='enableMobileDownload'
- id='enableMobileDownload'
- label={
- <FormattedMessage
- id='admin.file.enableMobileDownloadTitle'
- defaultMessage='Allow File Downloads on Mobile:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.file.enableMobileDownloadDesc'
- defaultMessage='When false, disables file downloads on mobile apps. Users can still download files from a mobile web browser.'
- />
- }
- value={this.state.enableMobileDownload}
- onChange={this.handleChange}
- disabled={!this.state.enableFileAttachments}
- />
- );
-
- amazonSSEComp =
- (
- <BooleanSetting
- id='amazonS3SSE'
- label={
- <FormattedMessage
- id='admin.image.amazonS3SSETitle'
- defaultMessage='Enable Server-Side Encryption for Amazon S3:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.image.amazonS3SSEDescription'
- defaultMessage='When true, encrypt files in Amazon S3 using server-side encryption with Amazon S3-managed keys. See <a href="https://about.mattermost.com/default-server-side-encryption" target="_blank">documentation</a> to learn more.'
- />
- }
- value={this.state.amazonS3SSE}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_S3}
- />
- );
- }
-
- return (
- <SettingsGroup>
- <DropdownSetting
- id='driverName'
- values={[
- {value: DRIVER_LOCAL, text: Utils.localizeMessage('admin.image.storeLocal', 'Local File System')},
- {value: DRIVER_S3, text: Utils.localizeMessage('admin.image.storeAmazonS3', 'Amazon S3')}
- ]}
- label={
- <FormattedMessage
- id='admin.image.storeTitle'
- defaultMessage='File Storage System:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.image.storeDescription'
- defaultMessage='Storage system where files and image attachments are saved.<br /><br />
- Selecting "Amazon S3" enables fields to enter your Amazon credentials and bucket details.<br /><br />
- Selecting "Local File System" enables the field to specify a local file directory.'
- />
- }
- value={this.state.driverName}
- onChange={this.handleChange}
- />
- <TextSetting
- id='directory'
- label={
- <FormattedMessage
- id='admin.image.localTitle'
- defaultMessage='Local Storage Directory:'
- />
- }
- placeholder={Utils.localizeMessage('admin.image.localExample', 'Ex "./data/"')}
- helpText={
- <FormattedMessage
- id='admin.image.localDescription'
- defaultMessage='Directory to which files and images are written. If blank, defaults to ./data/.'
- />
- }
- value={this.state.directory}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_LOCAL}
- />
- <TextSetting
- id='amazonS3AccessKeyId'
- label={
- <FormattedMessage
- id='admin.image.amazonS3IdTitle'
- defaultMessage='Amazon S3 Access Key ID:'
- />
- }
- placeholder={Utils.localizeMessage('admin.image.amazonS3IdExample', 'Ex "AKIADTOVBGERKLCBV"')}
- helpText={
- <FormattedMessage
- id='admin.image.amazonS3IdDescription'
- defaultMessage='Obtain this credential from your Amazon EC2 administrator.'
- />
- }
- value={this.state.amazonS3AccessKeyId}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_S3}
- />
- <TextSetting
- id='amazonS3SecretAccessKey'
- label={
- <FormattedMessage
- id='admin.image.amazonS3SecretTitle'
- defaultMessage='Amazon S3 Secret Access Key:'
- />
- }
- placeholder={Utils.localizeMessage('admin.image.amazonS3SecretExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
- helpText={
- <FormattedMessage
- id='admin.image.amazonS3SecretDescription'
- defaultMessage='Obtain this credential from your Amazon EC2 administrator.'
- />
- }
- value={this.state.amazonS3SecretAccessKey}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_S3}
- />
- <TextSetting
- id='amazonS3Bucket'
- label={
- <FormattedMessage
- id='admin.image.amazonS3BucketTitle'
- defaultMessage='Amazon S3 Bucket:'
- />
- }
- placeholder={Utils.localizeMessage('admin.image.amazonS3BucketExample', 'Ex "mattermost-media"')}
- helpText={
- <FormattedMessage
- id='admin.image.amazonS3BucketDescription'
- defaultMessage='Name you selected for your S3 bucket in AWS.'
- />
- }
- value={this.state.amazonS3Bucket}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_S3}
- />
- <TextSetting
- id='amazonS3Endpoint'
- label={
- <FormattedMessage
- id='admin.image.amazonS3EndpointTitle'
- defaultMessage='Amazon S3 Endpoint:'
- />
- }
- placeholder={Utils.localizeMessage('admin.image.amazonS3EndpointExample', 'Ex "s3.amazonaws.com"')}
- helpText={
- <FormattedMessage
- id='admin.image.amazonS3EndpointDescription'
- defaultMessage='Hostname of your S3 Compatible Storage provider. Defaults to `s3.amazonaws.com`.'
- />
- }
- value={this.state.amazonS3Endpoint}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_S3}
- />
- <BooleanSetting
- id='amazonS3SSL'
- label={
- <FormattedMessage
- id='admin.image.amazonS3SSLTitle'
- defaultMessage='Enable Secure Amazon S3 Connections:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.image.amazonS3SSLDescription'
- defaultMessage='When false, allow insecure connections to Amazon S3. Defaults to secure connections only.'
- />
- }
- value={this.state.amazonS3SSL}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_S3}
- />
- {amazonSSEComp}
- <BooleanSetting
- id='amazonS3Trace'
- label={
- <FormattedMessage
- id='admin.image.amazonS3TraceTitle'
- defaultMessage='Enable Amazon S3 Debugging:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.image.amazonS3TraceDescription'
- defaultMessage='(Development Mode) When true, log additional debugging information to the system logs.'
- />
- }
- value={this.state.amazonS3Trace}
- onChange={this.handleChange}
- disabled={this.state.driverName !== DRIVER_S3}
- />
- <BooleanSetting
- id='enableFileAttachments'
- label={
- <FormattedMessage
- id='admin.file.enableFileAttachments'
- defaultMessage='Allow File Sharing:'
- />
- }
- helpText={
- <FormattedMessage
- id='admin.file.enableFileAttachmentsDesc'
- defaultMessage='When false, disables file sharing on the server. All file and image uploads on messages are forbidden across clients and devices, including mobile.'
- />
- }
- value={this.state.enableFileAttachments}
- onChange={this.handleChange}
- />
- {mobileUploadDownloadSettings}
- <TextSetting
- id='maxFileSize'
- label={
- <FormattedMessage
- id='admin.image.maxFileSizeTitle'
- defaultMessage='Maximum File Size:'
- />
- }
- placeholder={Utils.localizeMessage('admin.image.maxFileSizeExample', '50')}
- helpText={
- <FormattedMessage
- id='admin.image.maxFileSizeDescription'
- defaultMessage='Maximum file size for message attachments in megabytes. Caution: Verify server memory can support your setting choice. Large file sizes increase the risk of server crashes and failed uploads due to network interruptions.'
- />
- }
- value={this.state.maxFileSize}
- onChange={this.handleChange}
- disabled={!this.state.enableFileAttachments}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/system_users/index.js b/webapp/components/admin_console/system_users/index.js
deleted file mode 100644
index 261a11d7e..000000000
--- a/webapp/components/admin_console/system_users/index.js
+++ /dev/null
@@ -1,31 +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 {getTeams, getTeamStats} from 'mattermost-redux/actions/teams';
-import {getUser, getUserAccessToken} from 'mattermost-redux/actions/users';
-
-import {getTeamsList} from 'mattermost-redux/selectors/entities/teams';
-
-import SystemUsers from './system_users.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- teams: getTeamsList(state),
- ...ownProps
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getTeams,
- getTeamStats,
- getUser,
- getUserAccessToken
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(SystemUsers);
diff --git a/webapp/components/admin_console/system_users/system_users.jsx b/webapp/components/admin_console/system_users/system_users.jsx
deleted file mode 100644
index db8400217..000000000
--- a/webapp/components/admin_console/system_users/system_users.jsx
+++ /dev/null
@@ -1,372 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage} from 'react-intl';
-
-import {
- loadProfiles,
- loadProfilesAndTeamMembers,
- loadProfilesWithoutTeam,
- searchUsers
-} from 'actions/user_actions.jsx';
-
-import AnalyticsStore from 'stores/analytics_store.jsx';
-import TeamStore from 'stores/team_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-
-import {reloadIfServerVersionChanged} from 'actions/global_actions.jsx';
-import {getStandardAnalytics} from 'actions/admin_actions.jsx';
-import {Constants, StatTypes, UserSearchOptions} from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import SystemUsersList from './system_users_list.jsx';
-
-import store from 'stores/redux_store.jsx';
-import {searchProfiles, searchProfilesInTeam} from 'mattermost-redux/selectors/entities/users';
-
-const ALL_USERS = '';
-const NO_TEAM = 'no_team';
-
-const USER_ID_LENGTH = 26;
-const USERS_PER_PAGE = 50;
-
-export default class SystemUsers extends React.Component {
- static propTypes = {
-
- /*
- * Array of team objects
- */
- teams: PropTypes.arrayOf(PropTypes.object).isRequired,
-
- actions: PropTypes.shape({
-
- /*
- * Function to get teams
- */
- getTeams: PropTypes.func.isRequired,
-
- /*
- * Function to get statistics for a team
- */
- getTeamStats: PropTypes.func.isRequired,
-
- /*
- * Function to get a user
- */
- getUser: PropTypes.func.isRequired,
-
- /*
- * Function to get a user access token
- */
- getUserAccessToken: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.updateTotalUsersFromStore = this.updateTotalUsersFromStore.bind(this);
- this.updateUsersFromStore = this.updateUsersFromStore.bind(this);
-
- this.loadDataForTeam = this.loadDataForTeam.bind(this);
- this.loadComplete = this.loadComplete.bind(this);
-
- this.handleTeamChange = this.handleTeamChange.bind(this);
- this.handleTermChange = this.handleTermChange.bind(this);
- this.nextPage = this.nextPage.bind(this);
-
- this.doSearch = this.doSearch.bind(this);
- this.search = this.search.bind(this);
- this.getUserById = this.getUserById.bind(this);
-
- this.renderFilterRow = this.renderFilterRow.bind(this);
-
- this.state = {
- totalUsers: AnalyticsStore.getAllSystem()[StatTypes.TOTAL_USERS],
- users: UserStore.getProfileList(),
-
- teamId: ALL_USERS,
- term: '',
- loading: true,
- searching: false
- };
- }
-
- componentDidMount() {
- AnalyticsStore.addChangeListener(this.updateTotalUsersFromStore);
- TeamStore.addStatsChangeListener(this.updateTotalUsersFromStore);
-
- UserStore.addChangeListener(this.updateUsersFromStore);
- UserStore.addInTeamChangeListener(this.updateUsersFromStore);
- UserStore.addWithoutTeamChangeListener(this.updateUsersFromStore);
-
- this.loadDataForTeam(this.state.teamId);
- this.props.actions.getTeams(0, 1000).then(reloadIfServerVersionChanged);
- }
-
- componentWillUpdate(nextProps, nextState) {
- const nextTeamId = nextState.teamId;
-
- if (this.state.teamId !== nextTeamId) {
- this.updateTotalUsersFromStore(nextTeamId);
- this.updateUsersFromStore(nextTeamId, nextState.term);
-
- this.loadDataForTeam(nextTeamId);
- }
- }
-
- componentWillUnmount() {
- AnalyticsStore.removeChangeListener(this.updateTotalUsersFromStore);
- TeamStore.removeStatsChangeListener(this.updateTotalUsersFromStore);
-
- UserStore.removeChangeListener(this.updateUsersFromStore);
- UserStore.removeInTeamChangeListener(this.updateUsersFromStore);
- UserStore.removeWithoutTeamChangeListener(this.updateUsersFromStore);
- }
-
- updateTotalUsersFromStore(teamId = this.state.teamId) {
- if (teamId === ALL_USERS) {
- this.setState({
- totalUsers: AnalyticsStore.getAllSystem()[StatTypes.TOTAL_USERS]
- });
- } else if (teamId === NO_TEAM) {
- this.setState({
- totalUsers: 0
- });
- } else {
- this.setState({
- totalUsers: TeamStore.getStats(teamId).total_member_count
- });
- }
- }
-
- updateUsersFromStore(teamId = this.state.teamId, term = this.state.term) {
- if (term) {
- let users;
- if (teamId) {
- users = searchProfilesInTeam(store.getState(), teamId, term);
- } else {
- users = searchProfiles(store.getState(), term);
- }
-
- if (users.length === 0 && UserStore.hasProfile(term)) {
- users = [UserStore.getProfile(term)];
- }
-
- this.setState({users});
- return;
- }
-
- if (teamId === ALL_USERS) {
- this.setState({users: UserStore.getProfileList(false, true)});
- } else if (teamId === NO_TEAM) {
- this.setState({users: UserStore.getProfileListWithoutTeam()});
- } else {
- this.setState({users: UserStore.getProfileListInTeam(this.state.teamId)});
- }
- }
-
- loadDataForTeam(teamId) {
- if (this.state.term) {
- this.search(this.state.term, teamId);
- return;
- }
-
- if (teamId === ALL_USERS) {
- loadProfiles(0, Constants.PROFILE_CHUNK_SIZE, this.loadComplete);
- getStandardAnalytics();
- } else if (teamId === NO_TEAM) {
- loadProfilesWithoutTeam(0, Constants.PROFILE_CHUNK_SIZE, this.loadComplete);
- } else {
- loadProfilesAndTeamMembers(0, Constants.PROFILE_CHUNK_SIZE, teamId, this.loadComplete);
- this.props.actions.getTeamStats(teamId);
- }
- }
-
- loadComplete() {
- this.setState({loading: false});
- }
-
- handleTeamChange(e) {
- this.setState({teamId: e.target.value});
- }
-
- handleTermChange(term) {
- this.setState({term});
- }
-
- nextPage(page) {
- // Paging isn't supported while searching
-
- if (this.state.teamId === ALL_USERS) {
- loadProfiles(page, USERS_PER_PAGE, this.loadComplete);
- } else if (this.state.teamId === NO_TEAM) {
- loadProfilesWithoutTeam(page + 1, USERS_PER_PAGE, this.loadComplete);
- } else {
- loadProfilesAndTeamMembers(page + 1, USERS_PER_PAGE, this.state.teamId, this.loadComplete);
- }
- }
-
- search(term, teamId = this.state.teamId) {
- if (term === '') {
- this.updateUsersFromStore(teamId, term);
-
- this.setState({
- loading: false
- });
-
- this.searchTimeoutId = '';
- return;
- }
-
- this.doSearch(teamId, term);
- }
-
- doSearch(teamId, term, now = false) {
- clearTimeout(this.searchTimeoutId);
- this.term = term;
-
- this.setState({loading: true});
-
- const options = {
- [UserSearchOptions.ALLOW_INACTIVE]: true
- };
- if (teamId === NO_TEAM) {
- options[UserSearchOptions.WITHOUT_TEAM] = true;
- }
-
- this.searchTimeoutId = setTimeout(
- () => {
- searchUsers(
- term,
- teamId,
- options,
- (users) => {
- if (users.length === 0 && term.length === USER_ID_LENGTH) {
- // This term didn't match any users name, but it does look like it might be a user's ID
- this.getUserByTokenOrId(term);
- } else {
- this.setState({loading: false});
- }
- },
- () => {
- this.setState({loading: false});
- }
- );
- },
- now ? 0 : Constants.SEARCH_TIMEOUT_MILLISECONDS
- );
- }
-
- getUserById(id) {
- if (UserStore.hasProfile(id)) {
- this.setState({loading: false});
- return;
- }
-
- this.props.actions.getUser(id).then(
- () => {
- this.setState({
- loading: false
- });
- }
- );
- }
-
- getUserByTokenOrId = async (id) => {
- if (global.window.mm_config.EnableUserAccessTokens === 'true') {
- const {data} = await this.props.actions.getUserAccessToken(id);
-
- if (data) {
- this.term = data.user_id;
- this.setState({term: data.user_id});
- this.updateUsersFromStore(this.state.teamId, data.user_id);
- this.getUserById(data.user_id);
- return;
- }
- }
-
- this.getUserById(id);
- }
-
- renderFilterRow(doSearch) {
- const teams = this.props.teams.map((team) => {
- return (
- <option
- key={team.id}
- value={team.id}
- >
- {team.display_name}
- </option>
- );
- });
-
- return (
- <div className='system-users__filter-row'>
- <div className='system-users__filter'>
- <input
- id='searchUsers'
- ref='filter'
- className='form-control filter-textbox'
- placeholder={Utils.localizeMessage('filtered_user_list.search', 'Search users')}
- onInput={doSearch}
- />
- </div>
- <label>
- <span className='system-users__team-filter-label'>
- <FormattedMessage
- id='filtered_user_list.show'
- defaultMessage='Filter:'
- />
- </span>
- <select
- className='form-control system-users__team-filter'
- onChange={this.handleTeamChange}
- value={this.state.teamId}
- >
- <option value={ALL_USERS}>{Utils.localizeMessage('admin.system_users.allUsers', 'All Users')}</option>
- <option value={NO_TEAM}>{Utils.localizeMessage('admin.system_users.noTeams', 'No Teams')}</option>
- {teams}
- </select>
- </label>
- </div>
- );
- }
-
- render() {
- let users = null;
- if (!this.state.loading) {
- users = this.state.users;
- }
-
- return (
- <div className='wrapper--fixed'>
- <h3 className='admin-console-header'>
- <FormattedMessage
- id='admin.system_users.title'
- defaultMessage='{siteName} Users'
- values={{
- siteName: global.mm_config.SiteName
- }}
- />
- </h3>
- <div className='more-modal__list member-list-holder'>
- <SystemUsersList
- renderFilterRow={this.renderFilterRow}
- search={this.search}
- nextPage={this.nextPage}
- users={users}
- usersPerPage={USERS_PER_PAGE}
- total={this.state.totalUsers}
- teams={this.props.teams}
- teamId={this.state.teamId}
- term={this.state.term}
- onTermChange={this.handleTermChange}
- />
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/system_users/system_users_dropdown.jsx b/webapp/components/admin_console/system_users/system_users_dropdown.jsx
deleted file mode 100644
index 79ccc8b31..000000000
--- a/webapp/components/admin_console/system_users/system_users_dropdown.jsx
+++ /dev/null
@@ -1,529 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ConfirmModal from 'components/confirm_modal.jsx';
-
-import TeamStore from 'stores/team_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-
-import Constants from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-import {updateActive} from 'actions/user_actions.jsx';
-import {adminResetMfa} from 'actions/admin_actions.jsx';
-import * as UserUtils from 'mattermost-redux/utils/user_utils';
-
-import {FormattedMessage} from 'react-intl';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-
-export default class SystemUsersDropdown extends React.Component {
- static propTypes = {
-
- /*
- * User to manage with dropdown
- */
- user: PropTypes.object.isRequired,
-
- /*
- * Function to open password reset, takes user as an argument
- */
- doPasswordReset: PropTypes.func.isRequired,
-
- /*
- * Function to open manage teams, takes user as an argument
- */
- doManageTeams: PropTypes.func.isRequired,
-
- /*
- * Function to open manage roles, takes user as an argument
- */
- doManageRoles: PropTypes.func.isRequired,
-
- /*
- * Function to open manage tokens, takes user as an argument
- */
- doManageTokens: PropTypes.func.isRequired
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- serverError: null,
- showDemoteModal: false,
- showDeactivateMemberModal: false,
- user: null,
- role: null
- };
- }
-
- handleMakeActive = (e) => {
- e.preventDefault();
- updateActive(this.props.user.id, true, null,
- (err) => {
- this.setState({serverError: err.message});
- }
- );
- }
-
- handleManageTeams = (e) => {
- e.preventDefault();
-
- this.props.doManageTeams(this.props.user);
- }
-
- handleManageRoles = (e) => {
- e.preventDefault();
-
- this.props.doManageRoles(this.props.user);
- }
-
- handleManageTokens = (e) => {
- e.preventDefault();
-
- this.props.doManageTokens(this.props.user);
- }
-
- handleResetPassword = (e) => {
- e.preventDefault();
- this.props.doPasswordReset(this.props.user);
- }
-
- handleResetMfa = (e) => {
- e.preventDefault();
-
- adminResetMfa(this.props.user.id,
- null,
- (err) => {
- this.setState({serverError: err.message});
- }
- );
- }
-
- handleDemoteSystemAdmin = (user, role) => {
- this.setState({
- serverError: this.state.serverError,
- showDemoteModal: true,
- user,
- role
- });
- }
-
- handleDemoteCancel = () => {
- this.setState({
- serverError: null,
- showDemoteModal: false,
- user: null,
- role: null
- });
- }
-
- handleDemoteSubmit = () => {
- if (this.state.role === 'member') {
- this.doMakeMember();
- }
-
- const teamUrl = TeamStore.getCurrentTeamUrl();
- if (teamUrl) {
- // the channel is added to the URL cause endless loading not being fully fixed
- window.location.href = teamUrl + '/channels/town-square';
- } else {
- window.location.href = '/';
- }
- }
-
- handleShowDeactivateMemberModal = (e) => {
- e.preventDefault();
-
- this.setState({showDeactivateMemberModal: true});
- }
-
- handleDeactivateMember = () => {
- updateActive(this.props.user.id, false, null,
- (err) => {
- this.setState({serverError: err.message});
- }
- );
-
- this.setState({showDeactivateMemberModal: false});
- }
-
- handleDeactivateCancel = () => {
- this.setState({showDeactivateMemberModal: false});
- }
-
- renderDeactivateMemberModal = () => {
- const title = (
- <FormattedMessage
- id='deactivate_member_modal.title'
- defaultMessage='Deactivate {username}'
- values={{
- username: this.props.user.username
- }}
- />
- );
-
- const message = (
- <FormattedMessage
- id='deactivate_member_modal.desc'
- defaultMessage='This action deactivates {username}. They will be logged out and not have access to any teams or channels on this system. Are you sure you want to deactivate {username}?'
- values={{
- username: this.props.user.username
- }}
- />
- );
-
- const confirmButtonClass = 'btn btn-danger';
- const deactivateMemberButton = (
- <FormattedMessage
- id='deactivate_member_modal.deactivate'
- defaultMessage='Deactivate'
- />
- );
-
- return (
- <ConfirmModal
- show={this.state.showDeactivateMemberModal}
- title={title}
- message={message}
- confirmButtonClass={confirmButtonClass}
- confirmButtonText={deactivateMemberButton}
- onConfirm={this.handleDeactivateMember}
- onCancel={this.handleDeactivateCancel}
- />
- );
- }
-
- renderAccessToken = () => {
- const userAccessTokensEnabled = global.window.mm_config.EnableUserAccessTokens === 'true';
- if (!userAccessTokensEnabled) {
- return null;
- }
-
- const user = this.props.user;
- const hasPostAllRole = UserUtils.hasPostAllRole(user.roles);
- const hasPostAllPublicRole = UserUtils.hasPostAllPublicRole(user.roles);
- const hasUserAccessTokenRole = UserUtils.hasUserAccessTokenRole(user.roles);
- const isSystemAdmin = UserUtils.isSystemAdmin(user.roles);
-
- let messageId = '';
- if (hasUserAccessTokenRole || isSystemAdmin) {
- if (hasPostAllRole) {
- messageId = 'admin.user_item.userAccessTokenPostAll';
- } else if (hasPostAllPublicRole) {
- messageId = 'admin.user_item.userAccessTokenPostAllPublic';
- } else {
- messageId = 'admin.user_item.userAccessTokenYes';
- }
- }
-
- if (!messageId) {
- return null;
- }
-
- return (
- <div className='light margin-top half'>
- <FormattedMessage
- key='admin.user_item.userAccessToken'
- id={messageId}
- />
- </div>
- );
- }
-
- render() {
- let serverError = null;
- if (this.state.serverError) {
- serverError = (
- <div className='has-error'>
- <label className='has-error control-label'>{this.state.serverError}</label>
- </div>
- );
- }
-
- const user = this.props.user;
- if (!user) {
- return <div/>;
- }
- let currentRoles = (
- <FormattedMessage
- id='admin.user_item.member'
- defaultMessage='Member'
- />
- );
-
- if (user.roles.length > 0 && Utils.isSystemAdmin(user.roles)) {
- currentRoles = (
- <FormattedMessage
- id='team_members_dropdown.systemAdmin'
- defaultMessage='System Admin'
- />
- );
- }
-
- const me = UserStore.getCurrentUser();
- let showMakeActive = false;
- let showMakeNotActive = !Utils.isSystemAdmin(user.roles);
- let showManageTeams = true;
- const mfaEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true' && global.window.mm_config.EnableMultifactorAuthentication === 'true';
- const showMfaReset = mfaEnabled && user.mfa_active;
-
- if (user.delete_at > 0) {
- currentRoles = (
- <FormattedMessage
- id='admin.user_item.inactive'
- defaultMessage='Inactive'
- />
- );
- showMakeActive = true;
- showMakeNotActive = false;
- showManageTeams = false;
- }
-
- let disableActivationToggle = false;
- if (user.auth_service === Constants.LDAP_SERVICE) {
- disableActivationToggle = true;
- }
-
- let menuClass = '';
- if (disableActivationToggle) {
- menuClass = 'disabled';
- }
-
- let makeActive = null;
- if (showMakeActive) {
- makeActive = (
- <li
- role='presentation'
- className={menuClass}
- >
- <a
- id='activate'
- role='menuitem'
- href='#'
- onClick={this.handleMakeActive}
- >
- <FormattedMessage
- id='admin.user_item.makeActive'
- defaultMessage='Activate'
- />
- </a>
- </li>
- );
- }
-
- let makeNotActive = null;
- if (showMakeNotActive) {
- makeNotActive = (
- <li
- role='presentation'
- className={menuClass}
- >
- <a
- id='deactivate'
- role='menuitem'
- href='#'
- onClick={this.handleShowDeactivateMemberModal}
- >
- <FormattedMessage
- id='admin.user_item.makeInactive'
- defaultMessage='Deactivate'
- />
- </a>
- </li>
- );
- }
-
- let manageTeams = null;
- if (showManageTeams) {
- manageTeams = (
- <li role='presentation'>
- <a
- id='manageTeams'
- role='menuitem'
- href='#'
- onClick={this.handleManageTeams}
- >
- <FormattedMessage
- id='admin.user_item.manageTeams'
- defaultMessage='Manage Teams'
- />
- </a>
- </li>
- );
- }
-
- let mfaReset = null;
- if (showMfaReset) {
- mfaReset = (
- <li role='presentation'>
- <a
- id='removeMFA'
- role='menuitem'
- href='#'
- onClick={this.handleResetMfa}
- >
- <FormattedMessage
- id='admin.user_item.resetMfa'
- defaultMessage='Remove MFA'
- />
- </a>
- </li>
- );
- }
-
- let passwordReset;
- if (user.auth_service) {
- passwordReset = (
- <li role='presentation'>
- <a
- id='switchEmailPassword'
- role='menuitem'
- href='#'
- onClick={this.handleResetPassword}
- >
- <FormattedMessage
- id='admin.user_item.switchToEmail'
- defaultMessage='Switch to Email/Password'
- />
- </a>
- </li>
- );
- } else {
- passwordReset = (
- <li role='presentation'>
- <a
- id='resetPassword'
- role='menuitem'
- href='#'
- onClick={this.handleResetPassword}
- >
- <FormattedMessage
- id='admin.user_item.resetPwd'
- defaultMessage='Reset Password'
- />
- </a>
- </li>
- );
- }
-
- let manageTokens;
- if (global.window.mm_config.EnableUserAccessTokens === 'true') {
- manageTokens = (
- <li role='presentation'>
- <a
- id='manageTokens'
- role='menuitem'
- href='#'
- onClick={this.handleManageTokens}
- >
- <FormattedMessage
- id='admin.user_item.manageTokens'
- defaultMessage='Manage Tokens'
- />
- </a>
- </li>
- );
- }
-
- let makeDemoteModal = null;
- if (this.props.user.id === me.id) {
- const title = (
- <FormattedMessage
- id='admin.user_item.confirmDemoteRoleTitle'
- defaultMessage='Confirm demotion from System Admin role'
- />
- );
-
- const message = (
- <div>
- <FormattedMessage
- id='admin.user_item.confirmDemoteDescription'
- defaultMessage="If you demote yourself from the System Admin role and there is not another user with System Admin privileges, you'll need to re-assign a System Admin by accessing the Mattermost server through a terminal and running the following command."
- />
- <br/>
- <br/>
- <FormattedMessage
- id='admin.user_item.confirmDemotionCmd'
- defaultMessage='platform roles system_admin {username}'
- values={{
- username: me.username
- }}
- />
- {serverError}
- </div>
- );
-
- const confirmButton = (
- <FormattedMessage
- id='admin.user_item.confirmDemotion'
- defaultMessage='Confirm Demotion'
- />
- );
-
- makeDemoteModal = (
- <ConfirmModal
- show={this.state.showDemoteModal}
- title={title}
- message={message}
- confirmButtonText={confirmButton}
- onConfirm={this.handleDemoteSubmit}
- onCancel={this.handleDemoteCancel}
- />
- );
- }
-
- const deactivateMemberModal = this.renderDeactivateMemberModal();
-
- let displayedName = Utils.getDisplayName(user);
- if (displayedName !== user.username) {
- displayedName += ' (@' + user.username + ')';
- }
-
- return (
- <div className='dropdown member-drop text-right'>
- <a
- id='memberDropdown'
- href='#'
- className='dropdown-toggle theme'
- type='button'
- data-toggle='dropdown'
- aria-expanded='true'
- >
- <span>{currentRoles} </span>
- <span className='caret'/>
- </a>
- {this.renderAccessToken()}
- <ul
- className='dropdown-menu member-menu'
- role='menu'
- >
- {makeActive}
- {makeNotActive}
- <li role='presentation'>
- <a
- id='manageRoles'
- role='menuitem'
- href='#'
- onClick={this.handleManageRoles}
- >
- <FormattedMessage
- id='admin.user_item.manageRoles'
- defaultMessage='Manage Roles'
- />
- </a>
- </li>
- {manageTeams}
- {manageTokens}
- {mfaReset}
- {passwordReset}
- </ul>
- {makeDemoteModal}
- {deactivateMemberModal}
- {serverError}
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/system_users/system_users_list.jsx b/webapp/components/admin_console/system_users/system_users_list.jsx
deleted file mode 100644
index 8a7f30e1b..000000000
--- a/webapp/components/admin_console/system_users/system_users_list.jsx
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-import ManageTeamsModal from 'components/admin_console/manage_teams_modal/manage_teams_modal.jsx';
-import ManageRolesModal from 'components/admin_console/manage_roles_modal';
-import ManageTokensModal from 'components/admin_console/manage_tokens_modal';
-import ResetPasswordModal from 'components/admin_console/reset_password_modal.jsx';
-import SearchableUserList from 'components/searchable_user_list/searchable_user_list.jsx';
-
-import store from 'stores/redux_store.jsx';
-const dispatch = store.dispatch;
-const getState = store.getState;
-
-import {getUser} from 'mattermost-redux/actions/users';
-import {Constants} from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import SystemUsersDropdown from './system_users_dropdown.jsx';
-
-export default class SystemUsersList extends React.Component {
- static propTypes = {
- users: PropTypes.arrayOf(PropTypes.object),
- usersPerPage: PropTypes.number,
- total: PropTypes.number,
- nextPage: PropTypes.func,
- search: PropTypes.func.isRequired,
- focusOnMount: PropTypes.bool,
- renderFilterRow: PropTypes.func,
-
- teamId: PropTypes.string.isRequired,
- term: PropTypes.string.isRequired,
- onTermChange: PropTypes.func.isRequired
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- page: 0,
-
- showManageTeamsModal: false,
- showManageRolesModal: false,
- showManageTokensModal: false,
- showPasswordModal: false,
- user: null
- };
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.teamId !== this.props.teamId) {
- this.setState({page: 0});
- }
- }
-
- nextPage = () => {
- this.setState({page: this.state.page + 1});
-
- this.props.nextPage(this.state.page + 1);
- }
-
- previousPage = () => {
- this.setState({page: this.state.page - 1});
- }
-
- search = (term) => {
- this.props.search(term);
-
- if (term !== '') {
- this.setState({page: 0});
- }
- }
-
- doManageTeams = (user) => {
- this.setState({
- showManageTeamsModal: true,
- user
- });
- }
-
- doManageRoles = (user) => {
- this.setState({
- showManageRolesModal: true,
- user
- });
- }
-
- doManageTokens = (user) => {
- this.setState({
- showManageTokensModal: true,
- user
- });
- }
-
- doManageTeamsDismiss = () => {
- this.setState({
- showManageTeamsModal: false,
- user: null
- });
- }
-
- doManageRolesDismiss = () => {
- this.setState({
- showManageRolesModal: false,
- user: null
- });
- }
-
- doManageTokensDismiss = () => {
- this.setState({
- showManageTokensModal: false,
- user: null
- });
- }
-
- doPasswordReset = (user) => {
- this.setState({
- showPasswordModal: true,
- user
- });
- }
-
- doPasswordResetDismiss = () => {
- this.setState({
- showPasswordModal: false,
- user: null
- });
- }
-
- doPasswordResetSubmit = (user) => {
- getUser(user.id)(dispatch, getState);
-
- this.setState({
- showPasswordModal: false,
- user: null
- });
- }
-
- getInfoForUser(user) {
- const info = [];
-
- if (user.auth_service) {
- let service;
- if (user.auth_service === Constants.LDAP_SERVICE || user.auth_service === Constants.SAML_SERVICE) {
- service = user.auth_service.toUpperCase();
- } else {
- service = Utils.toTitleCase(user.auth_service);
- }
-
- info.push(
- <FormattedHTMLMessage
- key='admin.user_item.authServiceNotEmail'
- id='admin.user_item.authServiceNotEmail'
- defaultMessage='<strong>Sign-in Method:</strong> {service}'
- values={{
- service
- }}
- />
- );
- } else {
- info.push(
- <FormattedHTMLMessage
- key='admin.user_item.authServiceEmail'
- id='admin.user_item.authServiceEmail'
- defaultMessage='<strong>Sign-in Method:</strong> Email'
- />
- );
- }
-
- const mfaEnabled = global.window.mm_license.IsLicensed === 'true' &&
- global.window.mm_license.MFA === 'true' &&
- global.window.mm_config.EnableMultifactorAuthentication === 'true';
- if (mfaEnabled) {
- info.push(', ');
-
- if (user.mfa_active) {
- info.push(
- <FormattedHTMLMessage
- key='admin.user_item.mfaYes'
- id='admin.user_item.mfaYes'
- defaultMessage='<strong>MFA</strong>: Yes'
- />
- );
- } else {
- info.push(
- <FormattedHTMLMessage
- key='admin.user_item.mfaNo'
- id='admin.user_item.mfaNo'
- defaultMessage='<strong>MFA</strong>: No'
- />
- );
- }
- }
-
- return info;
- }
-
- renderCount(count, total, startCount, endCount, isSearch) {
- if (total) {
- if (isSearch) {
- return (
- <FormattedMessage
- id='system_users_list.countSearch'
- defaultMessage='{count, number} {count, plural, one {user} other {users}} of {total, number} total'
- values={{
- count,
- total
- }}
- />
- );
- } else if (startCount !== 0 || endCount !== total) {
- return (
- <FormattedMessage
- id='system_users_list.countPage'
- defaultMessage='{startCount, number} - {endCount, number} {count, plural, one {user} other {users}} of {total, number} total'
- values={{
- count,
- startCount: startCount + 1,
- endCount,
- total
- }}
- />
- );
- }
-
- return (
- <FormattedMessage
- id='system_users_list.count'
- defaultMessage='{count, number} {count, plural, one {user} other {users}}'
- values={{
- count
- }}
- />
- );
- }
-
- return null;
- }
-
- render() {
- const extraInfo = {};
- if (this.props.users) {
- for (const user of this.props.users) {
- extraInfo[user.id] = this.getInfoForUser(user);
- }
- }
-
- return (
- <div>
- <SearchableUserList
- {...this.props}
- renderCount={this.renderCount}
- extraInfo={extraInfo}
- actions={[SystemUsersDropdown]}
- actionProps={{
- doPasswordReset: this.doPasswordReset,
- doManageTeams: this.doManageTeams,
- doManageRoles: this.doManageRoles,
- doManageTokens: this.doManageTokens
- }}
- nextPage={this.nextPage}
- previousPage={this.previousPage}
- search={this.search}
- page={this.state.page}
- term={this.props.term}
- onTermChange={this.props.onTermChange}
- />
- <ManageTeamsModal
- user={this.state.user}
- show={this.state.showManageTeamsModal}
- onModalDismissed={this.doManageTeamsDismiss}
- />
- <ManageRolesModal
- user={this.state.user}
- show={this.state.showManageRolesModal}
- onModalDismissed={this.doManageRolesDismiss}
- />
- <ManageTokensModal
- user={this.state.user}
- show={this.state.showManageTokensModal}
- onModalDismissed={this.doManageTokensDismiss}
- />
- <ResetPasswordModal
- user={this.state.user}
- show={this.state.showPasswordModal}
- onModalSubmit={this.doPasswordResetSubmit}
- onModalDismissed={this.doPasswordResetDismiss}
- />
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/text_setting.jsx b/webapp/components/admin_console/text_setting.jsx
deleted file mode 100644
index 5830828d2..000000000
--- a/webapp/components/admin_console/text_setting.jsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import Setting from './setting.jsx';
-
-export default class TextSetting extends React.Component {
- static get propTypes() {
- return {
- id: PropTypes.string.isRequired,
- label: PropTypes.node.isRequired,
- placeholder: PropTypes.string,
- helpText: PropTypes.node,
- value: PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.number
- ]).isRequired,
- maxLength: PropTypes.number,
- onChange: PropTypes.func,
- disabled: PropTypes.bool,
- type: PropTypes.oneOf([
- 'input',
- 'textarea'
- ])
- };
- }
-
- static get defaultProps() {
- return {
- type: 'input',
- maxLength: null
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleChange = this.handleChange.bind(this);
- }
-
- handleChange(e) {
- this.props.onChange(this.props.id, e.target.value);
- }
-
- render() {
- let input = null;
- if (this.props.type === 'input') {
- input = (
- <input
- id={this.props.id}
- className='form-control'
- type='text'
- placeholder={this.props.placeholder}
- value={this.props.value}
- maxLength={this.props.maxLength}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- );
- } else if (this.props.type === 'textarea') {
- input = (
- <textarea
- id={this.props.id}
- className='form-control'
- rows='5'
- placeholder={this.props.placeholder}
- value={this.props.value}
- maxLength={this.props.maxLength}
- onChange={this.handleChange}
- disabled={this.props.disabled}
- />
- );
- }
-
- return (
- <Setting
- label={this.props.label}
- helpText={this.props.helpText}
- inputId={this.props.id}
- >
- {input}
- </Setting>
- );
- }
-}
diff --git a/webapp/components/admin_console/users_and_teams_settings.jsx b/webapp/components/admin_console/users_and_teams_settings.jsx
deleted file mode 100644
index bfd67b638..000000000
--- a/webapp/components/admin_console/users_and_teams_settings.jsx
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import DropdownSetting from './dropdown_setting.jsx';
-import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import TextSetting from './text_setting.jsx';
-
-const RESTRICT_DIRECT_MESSAGE_ANY = 'any';
-const RESTRICT_DIRECT_MESSAGE_TEAM = 'team';
-
-export default class UsersAndTeamsSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
-
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.TeamSettings.EnableUserCreation = this.state.enableUserCreation;
- config.TeamSettings.EnableTeamCreation = this.state.enableTeamCreation;
- config.TeamSettings.MaxUsersPerTeam = this.parseIntNonZero(this.state.maxUsersPerTeam, Constants.DEFAULT_MAX_USERS_PER_TEAM);
- config.TeamSettings.RestrictCreationToDomains = this.state.restrictCreationToDomains;
- config.TeamSettings.RestrictDirectMessage = this.state.restrictDirectMessage;
- config.TeamSettings.TeammateNameDisplay = this.state.teammateNameDisplay;
- config.TeamSettings.MaxChannelsPerTeam = this.parseIntNonZero(this.state.maxChannelsPerTeam, Constants.DEFAULT_MAX_CHANNELS_PER_TEAM);
- config.TeamSettings.MaxNotificationsPerChannel = this.parseIntNonZero(this.state.maxNotificationsPerChannel, Constants.DEFAULT_MAX_NOTIFICATIONS_PER_CHANNEL);
-
- return config;
- }
-
- getStateFromConfig(config) {
- return {
- enableUserCreation: config.TeamSettings.EnableUserCreation,
- enableTeamCreation: config.TeamSettings.EnableTeamCreation,
- maxUsersPerTeam: config.TeamSettings.MaxUsersPerTeam,
- restrictCreationToDomains: config.TeamSettings.RestrictCreationToDomains,
- restrictDirectMessage: config.TeamSettings.RestrictDirectMessage,
- teammateNameDisplay: config.TeamSettings.TeammateNameDisplay,
- maxChannelsPerTeam: config.TeamSettings.MaxChannelsPerTeam,
- maxNotificationsPerChannel: config.TeamSettings.MaxNotificationsPerChannel
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.general.usersAndTeams'
- defaultMessage='Users and Teams'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableUserCreation'
- label={
- <FormattedMessage
- id='admin.team.userCreationTitle'
- defaultMessage='Enable Account Creation: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.team.userCreationDescription'
- defaultMessage='When false, the ability to create accounts is disabled. The create account button displays error when pressed.'
- />
- }
- value={this.state.enableUserCreation}
- onChange={this.handleChange}
- />
- <BooleanSetting
- id='enableTeamCreation'
- label={
- <FormattedMessage
- id='admin.team.teamCreationTitle'
- defaultMessage='Enable Team Creation: '
- />
- }
- helpText={
- <FormattedMessage
- id='admin.team.teamCreationDescription'
- defaultMessage='When false, only System Administrators can create teams.'
- />
- }
- value={this.state.enableTeamCreation}
- onChange={this.handleChange}
- />
- <TextSetting
- id='maxUsersPerTeam'
- label={
- <FormattedMessage
- id='admin.team.maxUsersTitle'
- defaultMessage='Max Users Per Team:'
- />
- }
- placeholder={Utils.localizeMessage('admin.team.maxUsersExample', 'Ex "25"')}
- helpText={
- <FormattedMessage
- id='admin.team.maxUsersDescription'
- defaultMessage='Maximum total number of users per team, including both active and inactive users.'
- />
- }
- value={this.state.maxUsersPerTeam}
- onChange={this.handleChange}
- />
- <TextSetting
- id='maxChannelsPerTeam'
- label={
- <FormattedMessage
- id='admin.team.maxChannelsTitle'
- defaultMessage='Max Channels Per Team:'
- />
- }
- placeholder={Utils.localizeMessage('admin.team.maxChannelsExample', 'Ex "100"')}
- helpText={
- <FormattedMessage
- id='admin.team.maxChannelsDescription'
- defaultMessage='Maximum total number of channels per team, including both active and deleted channels.'
- />
- }
- value={this.state.maxChannelsPerTeam}
- onChange={this.handleChange}
- />
- <TextSetting
- id='maxNotificationsPerChannel'
- label={
- <FormattedMessage
- id='admin.team.maxNotificationsPerChannelTitle'
- defaultMessage='Max Notifications Per Channel:'
- />
- }
- placeholder={Utils.localizeMessage('admin.team.maxNotificationsPerChannelExample', 'Ex "1000"')}
- helpText={
- <FormattedMessage
- id='admin.team.maxNotificationsPerChannelDescription'
- defaultMessage='Maximum total number of users in a channel before users typing messages, @all, @here, and @channel no longer send notifications because of performance.'
- />
- }
- value={this.state.maxNotificationsPerChannel}
- onChange={this.handleChange}
- />
- <TextSetting
- id='restrictCreationToDomains'
- label={
- <FormattedMessage
- id='admin.team.restrictTitle'
- defaultMessage='Restrict account creation to specified email domains:'
- />
- }
- placeholder={Utils.localizeMessage('admin.team.restrictExample', 'Ex "corp.mattermost.com, mattermost.org"')}
- helpText={
- <FormattedMessage
- id='admin.team.restrictDescription'
- defaultMessage='Teams and user accounts can only be created from a specific domain (e.g. "mattermost.org") or list of comma-separated domains (e.g. "corp.mattermost.com, mattermost.org").'
- />
- }
- value={this.state.restrictCreationToDomains}
- onChange={this.handleChange}
- />
- <DropdownSetting
- id='restrictDirectMessage'
- values={[
- {value: RESTRICT_DIRECT_MESSAGE_ANY, text: Utils.localizeMessage('admin.team.restrict_direct_message_any', 'Any user on the Mattermost server')},
- {value: RESTRICT_DIRECT_MESSAGE_TEAM, text: Utils.localizeMessage('admin.team.restrict_direct_message_team', 'Any member of the team')}
- ]}
- label={
- <FormattedMessage
- id='admin.team.restrictDirectMessage'
- defaultMessage='Enable users to open Direct Message channels with:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.team.restrictDirectMessageDesc'
- defaultMessage='"Any user on the Mattermost server" enables users to open a Direct Message channel with any user on the server, even if they are not on any teams together. "Any member of the team" limits the ability to open Direct Message channels to only users who are in the same team.'
- />
- }
- value={this.state.restrictDirectMessage}
- onChange={this.handleChange}
- />
- <DropdownSetting
- id='teammateNameDisplay'
- values={[
- {value: Constants.TEAMMATE_NAME_DISPLAY.SHOW_USERNAME, text: Utils.localizeMessage('admin.team.showUsername', 'Show username (default)')},
- {value: Constants.TEAMMATE_NAME_DISPLAY.SHOW_NICKNAME_FULLNAME, text: Utils.localizeMessage('admin.team.showNickname', 'Show nickname if one exists, otherwise show first and last name')},
- {value: Constants.TEAMMATE_NAME_DISPLAY.SHOW_FULLNAME, text: Utils.localizeMessage('admin.team.showFullname', 'Show first and last name')}
- ]}
- label={
- <FormattedMessage
- id='admin.team.teammateNameDisplay'
- defaultMessage='Teammate Name Display:'
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.team.teammateNameDisplayDesc'
- defaultMessage="Set how to display users' names in posts and the Direct Messages list."
- />
- }
- value={this.state.teammateNameDisplay}
- onChange={this.handleChange}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/webrtc_settings.jsx b/webapp/components/admin_console/webrtc_settings.jsx
deleted file mode 100644
index d9453936c..000000000
--- a/webapp/components/admin_console/webrtc_settings.jsx
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import * as Utils from 'utils/utils.jsx';
-
-import AdminSettings from './admin_settings.jsx';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import SettingsGroup from './settings_group.jsx';
-import BooleanSetting from './boolean_setting.jsx';
-import TextSetting from './text_setting.jsx';
-
-export default class WebrtcSettings extends AdminSettings {
- constructor(props) {
- super(props);
-
- this.getConfigFromState = this.getConfigFromState.bind(this);
- this.renderSettings = this.renderSettings.bind(this);
- }
-
- getConfigFromState(config) {
- config.WebrtcSettings.Enable = this.state.enableWebrtc;
- config.WebrtcSettings.GatewayWebsocketUrl = this.state.gatewayWebsocketUrl;
- config.WebrtcSettings.GatewayAdminUrl = this.state.gatewayAdminUrl;
- config.WebrtcSettings.GatewayAdminSecret = this.state.gatewayAdminSecret;
- config.WebrtcSettings.StunURI = this.state.stunURI;
- config.WebrtcSettings.TurnURI = this.state.turnURI;
- config.WebrtcSettings.TurnUsername = this.state.turnUsername;
- config.WebrtcSettings.TurnSharedKey = this.state.turnSharedKey;
-
- return config;
- }
-
- getStateFromConfig(config) {
- const settings = config.WebrtcSettings;
-
- return {
- hasErrors: false,
- enableWebrtc: settings.Enable,
- gatewayWebsocketUrl: settings.GatewayWebsocketUrl,
- gatewayAdminUrl: settings.GatewayAdminUrl,
- gatewayAdminSecret: settings.GatewayAdminSecret,
- stunURI: settings.StunURI,
- turnURI: settings.TurnURI,
- turnUsername: settings.TurnUsername,
- turnSharedKey: settings.TurnSharedKey
- };
- }
-
- renderTitle() {
- return (
- <FormattedMessage
- id='admin.integrations.webrtc'
- defaultMessage='Mattermost WebRTC (Beta)'
- />
- );
- }
-
- renderSettings() {
- return (
- <SettingsGroup>
- <BooleanSetting
- id='enableWebrtc'
- label={
- <FormattedMessage
- id='admin.webrtc.enableTitle'
- defaultMessage='Enable Mattermost WebRTC: '
- />
- }
- helpText={
- <FormattedHTMLMessage
- id='admin.webrtc.enableDescription'
- defaultMessage='When true, Mattermost allows making <strong>one-on-one</strong> video calls. WebRTC calls are available on Chrome, Firefox and Mattermost Desktop Apps.'
- />
- }
- value={this.state.enableWebrtc}
- onChange={this.handleChange}
- />
- <TextSetting
- id='gatewayWebsocketUrl'
- label={
- <FormattedMessage
- id='admin.webrtc.gatewayWebsocketUrlTitle'
- defaultMessage='Gateway WebSocket URL:'
- />
- }
- placeholder={Utils.localizeMessage('admin.webrtc.gatewayWebsocketUrlExample', 'Ex "wss://webrtc.mattermost.com:8189"')}
- helpText={
- <FormattedMessage
- id='admin.webrtc.gatewayWebsocketUrlDescription'
- defaultMessage='Enter wss://<mattermost-webrtc-gateway-url>:<port>. Make sure you use WS or WSS in your URL depending on your server configuration.
- This is the WebSocket used to signal and establish communication between the peers.'
- />
- }
- value={this.state.gatewayWebsocketUrl}
- onChange={this.handleChange}
- disabled={!this.state.enableWebrtc}
- />
- <TextSetting
- id='gatewayAdminUrl'
- label={
- <FormattedMessage
- id='admin.webrtc.gatewayAdminUrlTitle'
- defaultMessage='Gateway Admin URL:'
- />
- }
- placeholder={Utils.localizeMessage('admin.webrtc.gatewayAdminUrlExample', 'Ex "https://webrtc.mattermost.com:7089/admin"')}
- helpText={
- <FormattedMessage
- id='admin.webrtc.gatewayAdminUrlDescription'
- defaultMessage='Enter https://<mattermost-webrtc-gateway-url>:<port>/admin. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.
- Mattermost WebRTC uses this URL to obtain valid tokens for each peer to establish the connection.'
- />
- }
- value={this.state.gatewayAdminUrl}
- onChange={this.handleChange}
- disabled={!this.state.enableWebrtc}
- />
- <TextSetting
- id='gatewayAdminSecret'
- label={
- <FormattedMessage
- id='admin.webrtc.gatewayAdminSecretTitle'
- defaultMessage='Gateway Admin Secret:'
- />
- }
- placeholder={Utils.localizeMessage('admin.webrtc.gatewayAdminSecretExample', 'Ex "PVRzWNN1Tg6szn7IQWvhpAvLByScWxdy"')}
- helpText={
- <FormattedMessage
- id='admin.webrtc.gatewayAdminSecretDescription'
- defaultMessage='Enter your admin secret password to access the Gateway Admin URL.'
- />
- }
- value={this.state.gatewayAdminSecret}
- onChange={this.handleChange}
- disabled={!this.state.enableWebrtc}
- />
- <TextSetting
- id='stunURI'
- label={
- <FormattedMessage
- id='admin.webrtc.stunUriTitle'
- defaultMessage='STUN URI:'
- />
- }
- placeholder={Utils.localizeMessage('admin.webrtc.stunUriExample', 'Ex "stun:webrtc.mattermost.com:5349"')}
- helpText={
- <FormattedMessage
- id='admin.webrtc.stunUriDescription'
- defaultMessage='Enter your STUN URI as stun:<your-stun-url>:<port>. STUN is a standardized network protocol to allow an end host to assist devices to access its public IP address if it is located behind a NAT.'
- />
- }
- value={this.state.stunURI}
- onChange={this.handleChange}
- disabled={!this.state.enableWebrtc}
- />
- <TextSetting
- id='turnURI'
- label={
- <FormattedMessage
- id='admin.webrtc.turnUriTitle'
- defaultMessage='TURN URI:'
- />
- }
- placeholder={Utils.localizeMessage('admin.webrtc.turnUriExample', 'Ex "turn:webrtc.mattermost.com:5349"')}
- helpText={
- <FormattedMessage
- id='admin.webrtc.turnUriDescription'
- defaultMessage='Enter your TURN URI as turn:<your-turn-url>:<port>. TURN is a standardized network protocol to allow an end host to assist devices to establish a connection by using a relay public IP address if it is located behind a symmetric NAT.'
- />
- }
- value={this.state.turnURI}
- onChange={this.handleChange}
- disabled={!this.state.enableWebrtc}
- />
- <TextSetting
- id='turnUsername'
- label={
- <FormattedMessage
- id='admin.webrtc.turnUsernameTitle'
- defaultMessage='TURN Username:'
- />
- }
- placeholder={Utils.localizeMessage('admin.webrtc.turnUsernameExample', 'Ex "myusername"')}
- helpText={
- <FormattedMessage
- id='admin.webrtc.turnUsernameDescription'
- defaultMessage='Enter your TURN Server Username.'
- />
- }
- value={this.state.turnUsername}
- onChange={this.handleChange}
- disabled={!this.state.enableWebrtc || !this.state.turnURI}
- />
- <TextSetting
- id='turnSharedKey'
- label={
- <FormattedMessage
- id='admin.webrtc.turnSharedKeyTitle'
- defaultMessage='TURN Shared Key:'
- />
- }
- placeholder={Utils.localizeMessage('admin.webrtc.turnSharedKeyExample', 'Ex "bXdkOWQxc3d0Ynk3emY5ZmsxZ3NtazRjaWg="')}
- helpText={
- <FormattedMessage
- id='admin.webrtc.turnSharedKeyDescription'
- defaultMessage='Enter your TURN Server Shared Key. This is used to created dynamic passwords to establish the connection. Each password is valid for a short period of time.'
- />
- }
- value={this.state.turnSharedKey}
- onChange={this.handleChange}
- disabled={!this.state.enableWebrtc || !this.state.turnURI}
- />
- </SettingsGroup>
- );
- }
-}
diff --git a/webapp/components/admin_console/webserver_mode_dropdown_setting.jsx b/webapp/components/admin_console/webserver_mode_dropdown_setting.jsx
deleted file mode 100644
index e9ddee677..000000000
--- a/webapp/components/admin_console/webserver_mode_dropdown_setting.jsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import * as Utils from 'utils/utils.jsx';
-
-import DropdownSetting from './dropdown_setting.jsx';
-import {FormattedMessage} from 'react-intl';
-
-const WEBSERVER_MODE_HELP_TEXT = (
- <div>
- <table
- className='table table-bordered table-margin--none'
- cellPadding='5'
- >
- <tbody>
- <tr>
- <td>
- <FormattedMessage
- id='admin.webserverModeGzip'
- defaultMessage='gzip'
- />
- </td>
- <td>
- <FormattedMessage
- id='admin.webserverModeGzipDescription'
- defaultMessage='The Mattermost server will serve static files compressed with gzip.'
- />
- </td>
- </tr>
- <tr>
- <td>
- <FormattedMessage
- id='admin.webserverModeUncompressed'
- defaultMessage='Uncompressed'
- />
- </td>
- <td>
- <FormattedMessage
- id='admin.webserverModeUncompressedDescription'
- defaultMessage='The Mattermost server will serve static files uncompressed.'
- />
- </td>
- </tr>
- <tr>
- <td>
- <FormattedMessage
- id='admin.webserverModeDisabled'
- defaultMessage='Disabled'
- />
- </td>
- <td>
- <FormattedMessage
- id='admin.webserverModeDisabledDescription'
- defaultMessage='The Mattermost server will not serve static files.'
- />
- </td>
- </tr>
- </tbody>
- </table>
- <p className='help-text'>
- <FormattedMessage
- id='admin.webserverModeHelpText'
- defaultMessage='gzip compression applies to static content files. It is recommended to enable gzip to improve performance unless your environment has specific restrictions, such as a web proxy that distributes gzip files poorly.'
- />
- </p>
- </div>
-);
-
-export default function WebserverModeDropdownSetting(props) {
- return (
- <DropdownSetting
- id='webserverMode'
- values={[
- {value: 'gzip', text: Utils.localizeMessage('admin.webserverModeGzip', 'gzip')},
- {value: 'uncompressed', text: Utils.localizeMessage('admin.webserverModeUncompressed', 'Uncompressed')},
- {value: 'disabled', text: Utils.localizeMessage('admin.webserverModeDisabled', 'Disabled')}
- ]}
- label={
- <FormattedMessage
- id='admin.webserverModeTitle'
- defaultMessage='Webserver Mode:'
- />
- }
- value={props.value}
- onChange={props.onChange}
- disabled={props.disabled}
- helpText={WEBSERVER_MODE_HELP_TEXT}
- />
- );
-}
-WebserverModeDropdownSetting.defaultProps = {
-};
-
-WebserverModeDropdownSetting.propTypes = {
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool.isRequired
-};