summaryrefslogtreecommitdiffstats
path: root/webapp/components/admin_console
diff options
context:
space:
mode:
authorHarrison Healey <harrisonmhealey@gmail.com>2017-03-30 12:46:47 -0400
committerCorey Hulen <corey@hulen.com>2017-03-30 09:46:47 -0700
commit689cac535e45c47a4f603b236dc129dd456efcc9 (patch)
tree767ef80b310d6d073840bd5216da38c439f6e193 /webapp/components/admin_console
parent9a9729f22fea7275637eafb4046900c9f372ec56 (diff)
downloadchat-689cac535e45c47a4f603b236dc129dd456efcc9.tar.gz
chat-689cac535e45c47a4f603b236dc129dd456efcc9.tar.bz2
chat-689cac535e45c47a4f603b236dc129dd456efcc9.zip
PLT-2713/PLT-6028 Added System Users list to System Console (#5882)
* PLT-2713 Added ability for admins to list users not in any team * Updated style of unit test * Split SearchableUserList to give better control over its properties * Added users without any teams to the user store * Added ManageUsers page * Renamed ManageUsers to SystemUsers * Added ability to search by user id in SystemUsers page * Added SystemUsersDropdown * Removed unnecessary injectIntl * Created TeamUtils * Reduced scope of system console heading CSS * Added team filter to TeamAnalytics page * Updated admin console sidebar * Removed unnecessary TODO * Removed unused reference to deleted modal * Fixed system console sidebar not scrolling on first load * Fixed TeamAnalytics page not rendering on first load * Fixed chart.js throwing an error when switching between teams * Changed TeamAnalytics header to show the team's display name * Fixed appearance of TeamAnalytics and SystemUsers on small screen widths * Fixed placement of 'No users found' message * Fixed teams not appearing in SystemUsers on first load * Updated user count text for SystemUsers * Changed search by id fallback to trigger less often * Fixed SystemUsers list items not updating when searching * Fixed localization strings for SystemUsers page
Diffstat (limited to 'webapp/components/admin_console')
-rw-r--r--webapp/components/admin_console/admin_navbar_dropdown.jsx2
-rw-r--r--webapp/components/admin_console/admin_settings.jsx4
-rw-r--r--webapp/components/admin_console/admin_sidebar.jsx175
-rw-r--r--webapp/components/admin_console/admin_sidebar_team.jsx87
-rw-r--r--webapp/components/admin_console/audits.jsx2
-rw-r--r--webapp/components/admin_console/cluster_settings.jsx10
-rw-r--r--webapp/components/admin_console/compliance_settings.jsx10
-rw-r--r--webapp/components/admin_console/configuration_settings.jsx10
-rw-r--r--webapp/components/admin_console/connection_settings.jsx10
-rw-r--r--webapp/components/admin_console/custom_brand_settings.jsx12
-rw-r--r--webapp/components/admin_console/custom_emoji_settings.jsx10
-rw-r--r--webapp/components/admin_console/custom_integrations_settings.jsx10
-rw-r--r--webapp/components/admin_console/database_settings.jsx10
-rw-r--r--webapp/components/admin_console/developer_settings.jsx10
-rw-r--r--webapp/components/admin_console/email_authentication_settings.jsx10
-rw-r--r--webapp/components/admin_console/email_settings.jsx10
-rw-r--r--webapp/components/admin_console/external_service_settings.jsx10
-rw-r--r--webapp/components/admin_console/gitlab_settings.jsx10
-rw-r--r--webapp/components/admin_console/image_settings.jsx10
-rw-r--r--webapp/components/admin_console/ldap_settings.jsx10
-rw-r--r--webapp/components/admin_console/legal_and_support_settings.jsx10
-rw-r--r--webapp/components/admin_console/license_settings.jsx2
-rw-r--r--webapp/components/admin_console/link_previews_settings.jsx10
-rw-r--r--webapp/components/admin_console/localization_settings.jsx10
-rw-r--r--webapp/components/admin_console/log_settings.jsx10
-rw-r--r--webapp/components/admin_console/logs.jsx2
-rw-r--r--webapp/components/admin_console/metrics_settings.jsx10
-rw-r--r--webapp/components/admin_console/mfa_settings.jsx10
-rw-r--r--webapp/components/admin_console/native_app_link_settings.jsx10
-rw-r--r--webapp/components/admin_console/oauth_settings.jsx10
-rw-r--r--webapp/components/admin_console/password_settings.jsx10
-rw-r--r--webapp/components/admin_console/policy_settings.jsx10
-rw-r--r--webapp/components/admin_console/privacy_settings.jsx10
-rw-r--r--webapp/components/admin_console/public_link_settings.jsx10
-rw-r--r--webapp/components/admin_console/push_settings.jsx10
-rw-r--r--webapp/components/admin_console/rate_settings.jsx10
-rw-r--r--webapp/components/admin_console/reset_password_modal.jsx30
-rw-r--r--webapp/components/admin_console/saml_settings.jsx10
-rw-r--r--webapp/components/admin_console/select_team_modal.jsx120
-rw-r--r--webapp/components/admin_console/session_settings.jsx10
-rw-r--r--webapp/components/admin_console/signup_settings.jsx10
-rw-r--r--webapp/components/admin_console/storage_settings.jsx10
-rw-r--r--webapp/components/admin_console/system_users/system_users.jsx370
-rw-r--r--webapp/components/admin_console/system_users/system_users_dropdown.jsx (renamed from webapp/components/admin_console/admin_team_members_dropdown.jsx)121
-rw-r--r--webapp/components/admin_console/system_users/system_users_list.jsx232
-rw-r--r--webapp/components/admin_console/team_users.jsx298
-rw-r--r--webapp/components/admin_console/users_and_teams_settings.jsx10
-rw-r--r--webapp/components/admin_console/webrtc_settings.jsx10
48 files changed, 796 insertions, 1001 deletions
diff --git a/webapp/components/admin_console/admin_navbar_dropdown.jsx b/webapp/components/admin_console/admin_navbar_dropdown.jsx
index a1ec2885b..b4fd889bc 100644
--- a/webapp/components/admin_console/admin_navbar_dropdown.jsx
+++ b/webapp/components/admin_console/admin_navbar_dropdown.jsx
@@ -6,7 +6,7 @@ import ReactDOM from 'react-dom';
import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
-import {sortTeamsByDisplayName} from 'utils/utils.jsx';
+import {sortTeamsByDisplayName} from 'utils/team_utils.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {FormattedMessage} from 'react-intl';
diff --git a/webapp/components/admin_console/admin_settings.jsx b/webapp/components/admin_console/admin_settings.jsx
index b9883d7d8..30b9cbd11 100644
--- a/webapp/components/admin_console/admin_settings.jsx
+++ b/webapp/components/admin_console/admin_settings.jsx
@@ -112,7 +112,9 @@ export default class AdminSettings extends React.Component {
render() {
return (
<div className='wrapper--fixed'>
- {this.renderTitle()}
+ <h3 className='admin-console-header'>
+ {this.renderTitle()}
+ </h3>
<form
className='form-horizontal'
role='form'
diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx
index 2f299bdeb..73ec436f4 100644
--- a/webapp/components/admin_console/admin_sidebar.jsx
+++ b/webapp/components/admin_console/admin_sidebar.jsx
@@ -3,18 +3,12 @@
import $ from 'jquery';
import React from 'react';
+import {FormattedMessage} from 'react-intl';
-import AdminStore from 'stores/admin_store.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
-import AdminSidebarHeader from './admin_sidebar_header.jsx';
-import AdminSidebarTeam from './admin_sidebar_team.jsx';
-import {FormattedMessage} from 'react-intl';
-import {browserHistory} from 'react-router/es6';
-import {OverlayTrigger, Tooltip} from 'react-bootstrap';
-import SelectTeamModal from './select_team_modal.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 {
@@ -27,84 +21,23 @@ export default class AdminSidebar extends React.Component {
constructor(props) {
super(props);
- this.handleAllTeamsChange = this.handleAllTeamsChange.bind(this);
-
- this.removeTeam = this.removeTeam.bind(this);
-
- this.showTeamSelect = this.showTeamSelect.bind(this);
- this.teamSelectedModal = this.teamSelectedModal.bind(this);
- this.teamSelectedModalDismissed = this.teamSelectedModalDismissed.bind(this);
-
this.updateTitle = this.updateTitle.bind(this);
-
- this.renderAddTeamButton = this.renderAddTeamButton.bind(this);
- this.renderTeams = this.renderTeams.bind(this);
-
- this.state = {
- teams: AdminStore.getAllTeams(),
- selectedTeams: AdminStore.getSelectedTeams(),
- showSelectModal: false
- };
}
componentDidMount() {
- AdminStore.addAllTeamsChangeListener(this.handleAllTeamsChange);
- AsyncClient.getAllTeams();
-
this.updateTitle();
- }
- componentDidUpdate() {
if (!Utils.isMobile()) {
$('.admin-sidebar .nav-pills__container').perfectScrollbar();
}
}
- componentWillUnmount() {
- AdminStore.removeAllTeamsChangeListener(this.handleAllTeamsChange);
- }
-
- handleAllTeamsChange() {
- this.setState({
- teams: AdminStore.getAllTeams(),
- selectedTeams: AdminStore.getSelectedTeams()
- });
- }
-
- removeTeam(team) {
- const selectedTeams = Object.assign({}, this.state.selectedTeams);
- Reflect.deleteProperty(selectedTeams, team.id);
- AdminStore.saveSelectedTeams(selectedTeams);
-
- this.handleAllTeamsChange();
-
- if (this.context.router.isActive('/admin_console/team/' + team.id)) {
- browserHistory.push('/admin_console');
+ componentDidUpdate() {
+ if (!Utils.isMobile()) {
+ $('.admin-sidebar .nav-pills__container').perfectScrollbar();
}
}
- showTeamSelect(e) {
- e.preventDefault();
- this.setState({showSelectModal: true});
- }
-
- teamSelectedModal(teamId) {
- this.setState({
- showSelectModal: false
- });
-
- const selectedTeams = Object.assign({}, this.state.selectedTeams);
- selectedTeams[teamId] = true;
-
- AdminStore.saveSelectedTeams(selectedTeams);
-
- this.handleAllTeamsChange();
- }
-
- teamSelectedModalDismissed() {
- this.setState({showSelectModal: false});
- }
-
updateTitle() {
let currentSiteName = '';
if (global.window.mm_config.SiteName != null) {
@@ -114,79 +47,6 @@ export default class AdminSidebar extends React.Component {
document.title = Utils.localizeMessage('sidebar_right_menu.console', 'System Console') + ' - ' + currentSiteName;
}
- renderAddTeamButton() {
- const addTeamTooltip = (
- <Tooltip id='add-team-tooltip'>
- <FormattedMessage
- id='admin.sidebar.addTeamSidebar'
- defaultMessage='Add team from sidebar menu'
- />
- </Tooltip>
- );
-
- return (
- <span className='menu-icon--right'>
- <OverlayTrigger
- delayShow={1000}
- placement='top'
- overlay={addTeamTooltip}
- >
- <a
- href='#'
- onClick={this.showTeamSelect}
- >
- <i
- className='fa fa-plus'
- />
- </a>
- </OverlayTrigger>
- </span>
- );
- }
-
- renderTeams() {
- const teams = [];
- let teamsArray = [];
-
- Reflect.ownKeys(this.state.selectedTeams).forEach((key) => {
- if (this.state.teams[key]) {
- teamsArray.push(this.state.teams[key]);
- }
- });
-
- teamsArray = teamsArray.sort(Utils.sortTeamsByDisplayName);
-
- for (let i = 0; i < teamsArray.length; i++) {
- const team = teamsArray[i];
- teams.push(
- <AdminSidebarTeam
- key={team.id}
- team={team}
- onRemoveTeam={this.removeTeam}
- />
- );
- }
-
- return (
- <AdminSidebarCategory
- parentLink='/admin_console'
- icon='fa-user'
- title={
- <FormattedMessage
- id='admin.sidebar.teams'
- defaultMessage='TEAMS ({count, number})'
- values={{
- count: Object.keys(this.state.teams).length
- }}
- />
- }
- action={this.renderAddTeamButton()}
- >
- {teams}
- </AdminSidebarCategory>
- );
- }
-
render() {
let oauthSettings = null;
let ldapSettings = null;
@@ -422,6 +282,24 @@ export default class AdminSidebar extends React.Component {
}
/>
<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
@@ -760,16 +638,9 @@ export default class AdminSidebar extends React.Component {
{metricsSettings}
</AdminSidebarSection>
</AdminSidebarCategory>
- {this.renderTeams()}
{otherCategory}
</ul>
</div>
- <SelectTeamModal
- teams={this.state.teams}
- show={this.state.showSelectModal}
- onModalSubmit={this.teamSelectedModal}
- onModalDismissed={this.teamSelectedModalDismissed}
- />
</div>
);
}
diff --git a/webapp/components/admin_console/admin_sidebar_team.jsx b/webapp/components/admin_console/admin_sidebar_team.jsx
deleted file mode 100644
index b1df92491..000000000
--- a/webapp/components/admin_console/admin_sidebar_team.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {FormattedMessage} from 'react-intl';
-import {OverlayTrigger, Tooltip} from 'react-bootstrap';
-import AdminSidebarSection from './admin_sidebar_section.jsx';
-
-export default class AdminSidebarTeam extends React.Component {
- static get propTypes() {
- return {
- team: React.PropTypes.object.isRequired,
- onRemoveTeam: React.PropTypes.func.isRequired,
- parentLink: React.PropTypes.string
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleRemoveTeam = this.handleRemoveTeam.bind(this);
- }
-
- handleRemoveTeam(e) {
- e.preventDefault();
-
- this.props.onRemoveTeam(this.props.team);
- }
-
- render() {
- const team = this.props.team;
-
- const removeTeamTooltip = (
- <Tooltip id='remove-team-tooltip'>
- <FormattedMessage
- id='admin.sidebar.rmTeamSidebar'
- defaultMessage='Remove team from sidebar menu'
- />
- </Tooltip>
- );
-
- const removeTeamButton = (
- <OverlayTrigger
- delayShow={1000}
- placement='top'
- overlay={removeTeamTooltip}
- >
- <span
- className='menu-icon--right menu__close'
- onClick={this.handleRemoveTeam}
- >
- {'×'}
- </span>
- </OverlayTrigger>
- );
-
- return (
- <AdminSidebarSection
- key={team.id}
- name={'team/' + team.id}
- parentLink={this.props.parentLink}
- title={team.display_name}
- action={removeTeamButton}
- >
- <AdminSidebarSection
- name='users'
- title={
- <FormattedMessage
- id='admin.sidebar.users'
- defaultMessage='- Users'
- />
- }
- />
- <AdminSidebarSection
- name='analytics'
- title={
- <FormattedMessage
- id='admin.sidebar.statistics'
- defaultMessage='- Team Statistics'
- />
- }
- />
- </AdminSidebarSection>
- );
- }
-}
diff --git a/webapp/components/admin_console/audits.jsx b/webapp/components/admin_console/audits.jsx
index 5e0e03607..47a7e8d89 100644
--- a/webapp/components/admin_console/audits.jsx
+++ b/webapp/components/admin_console/audits.jsx
@@ -76,7 +76,7 @@ export default class Audits extends React.Component {
<ComplianceReports/>
<div className='panel audit-panel'>
- <h3>
+ <h3 className='admin-console-header'>
<FormattedMessage
id='admin.audits.title'
defaultMessage='User Activity Logs'
diff --git a/webapp/components/admin_console/cluster_settings.jsx b/webapp/components/admin_console/cluster_settings.jsx
index bbd135e50..31634d0bd 100644
--- a/webapp/components/admin_console/cluster_settings.jsx
+++ b/webapp/components/admin_console/cluster_settings.jsx
@@ -51,12 +51,10 @@ export default class ClusterSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.advance.cluster'
- defaultMessage='High Availability (Beta)'
- />
- </h3>
+ <FormattedMessage
+ id='admin.advance.cluster'
+ defaultMessage='High Availability (Beta)'
+ />
);
}
diff --git a/webapp/components/admin_console/compliance_settings.jsx b/webapp/components/admin_console/compliance_settings.jsx
index f9dc61c1d..e2df967d5 100644
--- a/webapp/components/admin_console/compliance_settings.jsx
+++ b/webapp/components/admin_console/compliance_settings.jsx
@@ -38,12 +38,10 @@ export default class ComplianceSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.compliance.title'
- defaultMessage='Compliance Settings'
- />
- </h3>
+ <FormattedMessage
+ id='admin.compliance.title'
+ defaultMessage='Compliance Settings'
+ />
);
}
diff --git a/webapp/components/admin_console/configuration_settings.jsx b/webapp/components/admin_console/configuration_settings.jsx
index a5e5abe87..ec5606fa1 100644
--- a/webapp/components/admin_console/configuration_settings.jsx
+++ b/webapp/components/admin_console/configuration_settings.jsx
@@ -64,12 +64,10 @@ export default class ConfigurationSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.general.configuration'
- defaultMessage='Configuration'
- />
- </h3>
+ <FormattedMessage
+ id='admin.general.configuration'
+ defaultMessage='Configuration'
+ />
);
}
diff --git a/webapp/components/admin_console/connection_settings.jsx b/webapp/components/admin_console/connection_settings.jsx
index 8e030b207..b35f3acf7 100644
--- a/webapp/components/admin_console/connection_settings.jsx
+++ b/webapp/components/admin_console/connection_settings.jsx
@@ -36,12 +36,10 @@ export default class ConnectionSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.security.connection'
- defaultMessage='Connections'
- />
- </h3>
+ <FormattedMessage
+ id='admin.security.connection'
+ defaultMessage='Connections'
+ />
);
}
diff --git a/webapp/components/admin_console/custom_brand_settings.jsx b/webapp/components/admin_console/custom_brand_settings.jsx
index ee8e464da..48954ef78 100644
--- a/webapp/components/admin_console/custom_brand_settings.jsx
+++ b/webapp/components/admin_console/custom_brand_settings.jsx
@@ -44,12 +44,10 @@ export default class CustomBrandSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.customization.customBrand'
- defaultMessage='Custom Branding'
- />
- </h3>
+ <FormattedMessage
+ id='admin.customization.customBrand'
+ defaultMessage='Custom Branding'
+ />
);
}
@@ -155,4 +153,4 @@ export default class CustomBrandSettings extends AdminSettings {
</SettingsGroup>
);
}
-} \ No newline at end of file
+}
diff --git a/webapp/components/admin_console/custom_emoji_settings.jsx b/webapp/components/admin_console/custom_emoji_settings.jsx
index 90b70241d..c1457d7e9 100644
--- a/webapp/components/admin_console/custom_emoji_settings.jsx
+++ b/webapp/components/admin_console/custom_emoji_settings.jsx
@@ -39,12 +39,10 @@ export default class CustomEmojiSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.customization.customEmoji'
- defaultMessage='Custom Emoji'
- />
- </h3>
+ <FormattedMessage
+ id='admin.customization.customEmoji'
+ defaultMessage='Custom Emoji'
+ />
);
}
diff --git a/webapp/components/admin_console/custom_integrations_settings.jsx b/webapp/components/admin_console/custom_integrations_settings.jsx
index 6a4202d00..63015a061 100644
--- a/webapp/components/admin_console/custom_integrations_settings.jsx
+++ b/webapp/components/admin_console/custom_integrations_settings.jsx
@@ -43,12 +43,10 @@ export default class WebhookSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.integrations.custom'
- defaultMessage='Custom Integrations'
- />
- </h3>
+ <FormattedMessage
+ id='admin.integrations.custom'
+ defaultMessage='Custom Integrations'
+ />
);
}
diff --git a/webapp/components/admin_console/database_settings.jsx b/webapp/components/admin_console/database_settings.jsx
index 2cd4929ec..84adae29c 100644
--- a/webapp/components/admin_console/database_settings.jsx
+++ b/webapp/components/admin_console/database_settings.jsx
@@ -46,12 +46,10 @@ export default class DatabaseSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.database.title'
- defaultMessage='Database Settings'
- />
- </h3>
+ <FormattedMessage
+ id='admin.database.title'
+ defaultMessage='Database Settings'
+ />
);
}
diff --git a/webapp/components/admin_console/developer_settings.jsx b/webapp/components/admin_console/developer_settings.jsx
index 119b92a5a..3bcc2a19b 100644
--- a/webapp/components/admin_console/developer_settings.jsx
+++ b/webapp/components/admin_console/developer_settings.jsx
@@ -33,12 +33,10 @@ export default class DeveloperSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.developer.title'
- defaultMessage='Developer Settings'
- />
- </h3>
+ <FormattedMessage
+ id='admin.developer.title'
+ defaultMessage='Developer Settings'
+ />
);
}
diff --git a/webapp/components/admin_console/email_authentication_settings.jsx b/webapp/components/admin_console/email_authentication_settings.jsx
index cb7ef3419..177f36d64 100644
--- a/webapp/components/admin_console/email_authentication_settings.jsx
+++ b/webapp/components/admin_console/email_authentication_settings.jsx
@@ -35,12 +35,10 @@ export default class EmailAuthenticationSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.authentication.email'
- defaultMessage='Email'
- />
- </h3>
+ <FormattedMessage
+ id='admin.authentication.email'
+ defaultMessage='Email'
+ />
);
}
diff --git a/webapp/components/admin_console/email_settings.jsx b/webapp/components/admin_console/email_settings.jsx
index 9dc02857b..6cf09f653 100644
--- a/webapp/components/admin_console/email_settings.jsx
+++ b/webapp/components/admin_console/email_settings.jsx
@@ -56,12 +56,10 @@ export default class EmailSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.notifications.email'
- defaultMessage='Email'
- />
- </h3>
+ <FormattedMessage
+ id='admin.notifications.email'
+ defaultMessage='Email'
+ />
);
}
diff --git a/webapp/components/admin_console/external_service_settings.jsx b/webapp/components/admin_console/external_service_settings.jsx
index 53fdbfb53..21fc6c106 100644
--- a/webapp/components/admin_console/external_service_settings.jsx
+++ b/webapp/components/admin_console/external_service_settings.jsx
@@ -32,12 +32,10 @@ export default class ExternalServiceSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.integrations.external'
- defaultMessage='External Services'
- />
- </h3>
+ <FormattedMessage
+ id='admin.integrations.external'
+ defaultMessage='External Services'
+ />
);
}
diff --git a/webapp/components/admin_console/gitlab_settings.jsx b/webapp/components/admin_console/gitlab_settings.jsx
index ec3849b26..6ba2245b8 100644
--- a/webapp/components/admin_console/gitlab_settings.jsx
+++ b/webapp/components/admin_console/gitlab_settings.jsx
@@ -44,12 +44,10 @@ export default class GitLabSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.authentication.gitlab'
- defaultMessage='GitLab'
- />
- </h3>
+ <FormattedMessage
+ id='admin.authentication.gitlab'
+ defaultMessage='GitLab'
+ />
);
}
diff --git a/webapp/components/admin_console/image_settings.jsx b/webapp/components/admin_console/image_settings.jsx
index 8e8e2868e..0249e3979 100644
--- a/webapp/components/admin_console/image_settings.jsx
+++ b/webapp/components/admin_console/image_settings.jsx
@@ -43,12 +43,10 @@ export default class ImageSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.files.images'
- defaultMessage='Images'
- />
- </h3>
+ <FormattedMessage
+ id='admin.files.images'
+ defaultMessage='Images'
+ />
);
}
diff --git a/webapp/components/admin_console/ldap_settings.jsx b/webapp/components/admin_console/ldap_settings.jsx
index b774d34f3..50883ac22 100644
--- a/webapp/components/admin_console/ldap_settings.jsx
+++ b/webapp/components/admin_console/ldap_settings.jsx
@@ -76,12 +76,10 @@ export default class LdapSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.authentication.ldap'
- defaultMessage='AD/LDAP'
- />
- </h3>
+ <FormattedMessage
+ id='admin.authentication.ldap'
+ defaultMessage='AD/LDAP'
+ />
);
}
diff --git a/webapp/components/admin_console/legal_and_support_settings.jsx b/webapp/components/admin_console/legal_and_support_settings.jsx
index 3108dd60b..b0f85f43d 100644
--- a/webapp/components/admin_console/legal_and_support_settings.jsx
+++ b/webapp/components/admin_console/legal_and_support_settings.jsx
@@ -41,12 +41,10 @@ export default class LegalAndSupportSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.customization.support'
- defaultMessage='Legal and Support'
- />
- </h3>
+ <FormattedMessage
+ id='admin.customization.support'
+ defaultMessage='Legal and Support'
+ />
);
}
diff --git a/webapp/components/admin_console/license_settings.jsx b/webapp/components/admin_console/license_settings.jsx
index 6c14394b7..7e77f44b6 100644
--- a/webapp/components/admin_console/license_settings.jsx
+++ b/webapp/components/admin_console/license_settings.jsx
@@ -221,7 +221,7 @@ class LicenseSettings extends React.Component {
return (
<div className='wrapper--fixed'>
- <h3>
+ <h3 className='admin-console-header'>
<FormattedMessage
id='admin.license.title'
defaultMessage='Edition and License'
diff --git a/webapp/components/admin_console/link_previews_settings.jsx b/webapp/components/admin_console/link_previews_settings.jsx
index aea8a56f1..f223ccc3e 100644
--- a/webapp/components/admin_console/link_previews_settings.jsx
+++ b/webapp/components/admin_console/link_previews_settings.jsx
@@ -31,12 +31,10 @@ export default class LinkPreviewsSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.customization.linkPreviews'
- defaultMessage='Link Previews'
- />
- </h3>
+ <FormattedMessage
+ id='admin.customization.linkPreviews'
+ defaultMessage='Link Previews'
+ />
);
}
diff --git a/webapp/components/admin_console/localization_settings.jsx b/webapp/components/admin_console/localization_settings.jsx
index 7868ca8eb..b3e8a7b65 100644
--- a/webapp/components/admin_console/localization_settings.jsx
+++ b/webapp/components/admin_console/localization_settings.jsx
@@ -52,12 +52,10 @@ export default class LocalizationSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.general.localization'
- defaultMessage='Localization'
- />
- </h3>
+ <FormattedMessage
+ id='admin.general.localization'
+ defaultMessage='Localization'
+ />
);
}
diff --git a/webapp/components/admin_console/log_settings.jsx b/webapp/components/admin_console/log_settings.jsx
index 135369942..69dd4eda7 100644
--- a/webapp/components/admin_console/log_settings.jsx
+++ b/webapp/components/admin_console/log_settings.jsx
@@ -49,12 +49,10 @@ export default class LogSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.general.log'
- defaultMessage='Logging'
- />
- </h3>
+ <FormattedMessage
+ id='admin.general.log'
+ defaultMessage='Logging'
+ />
);
}
diff --git a/webapp/components/admin_console/logs.jsx b/webapp/components/admin_console/logs.jsx
index 5846c91db..d2464b37f 100644
--- a/webapp/components/admin_console/logs.jsx
+++ b/webapp/components/admin_console/logs.jsx
@@ -85,7 +85,7 @@ export default class Logs extends React.Component {
return (
<div className='panel'>
- <h3>
+ <h3 className='admin-console-header'>
<FormattedMessage
id='admin.logs.title'
defaultMessage='Server Logs'
diff --git a/webapp/components/admin_console/metrics_settings.jsx b/webapp/components/admin_console/metrics_settings.jsx
index 29fa028ec..607a21fb9 100644
--- a/webapp/components/admin_console/metrics_settings.jsx
+++ b/webapp/components/admin_console/metrics_settings.jsx
@@ -38,12 +38,10 @@ export default class MetricsSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.advance.metrics'
- defaultMessage='Performance Monitoring'
- />
- </h3>
+ <FormattedMessage
+ id='admin.advance.metrics'
+ defaultMessage='Performance Monitoring'
+ />
);
}
diff --git a/webapp/components/admin_console/mfa_settings.jsx b/webapp/components/admin_console/mfa_settings.jsx
index 5a7e0076f..7ae1f2e18 100644
--- a/webapp/components/admin_console/mfa_settings.jsx
+++ b/webapp/components/admin_console/mfa_settings.jsx
@@ -38,12 +38,10 @@ export default class MfaSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.mfa.title'
- defaultMessage='Multi-factor Authentication'
- />
- </h3>
+ <FormattedMessage
+ id='admin.mfa.title'
+ defaultMessage='Multi-factor Authentication'
+ />
);
}
diff --git a/webapp/components/admin_console/native_app_link_settings.jsx b/webapp/components/admin_console/native_app_link_settings.jsx
index 05d61a284..d932af645 100644
--- a/webapp/components/admin_console/native_app_link_settings.jsx
+++ b/webapp/components/admin_console/native_app_link_settings.jsx
@@ -35,12 +35,10 @@ export default class NativeAppLinkSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.customization.nativeAppLinks'
- defaultMessage='Mattermost App Links'
- />
- </h3>
+ <FormattedMessage
+ id='admin.customization.nativeAppLinks'
+ defaultMessage='Mattermost App Links'
+ />
);
}
diff --git a/webapp/components/admin_console/oauth_settings.jsx b/webapp/components/admin_console/oauth_settings.jsx
index 9a86abfa0..f5eac13eb 100644
--- a/webapp/components/admin_console/oauth_settings.jsx
+++ b/webapp/components/admin_console/oauth_settings.jsx
@@ -111,12 +111,10 @@ export default class OAuthSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.authentication.oauth'
- defaultMessage='OAuth 2.0'
- />
- </h3>
+ <FormattedMessage
+ id='admin.authentication.oauth'
+ defaultMessage='OAuth 2.0'
+ />
);
}
diff --git a/webapp/components/admin_console/password_settings.jsx b/webapp/components/admin_console/password_settings.jsx
index 43ec40904..edb9669e1 100644
--- a/webapp/components/admin_console/password_settings.jsx
+++ b/webapp/components/admin_console/password_settings.jsx
@@ -138,12 +138,10 @@ export default class PasswordSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.security.password'
- defaultMessage='Password'
- />
- </h3>
+ <FormattedMessage
+ id='admin.security.password'
+ defaultMessage='Password'
+ />
);
}
diff --git a/webapp/components/admin_console/policy_settings.jsx b/webapp/components/admin_console/policy_settings.jsx
index 5d82fc69c..c8c145b8d 100644
--- a/webapp/components/admin_console/policy_settings.jsx
+++ b/webapp/components/admin_console/policy_settings.jsx
@@ -55,12 +55,10 @@ export default class PolicySettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.general.policy'
- defaultMessage='Policy'
- />
- </h3>
+ <FormattedMessage
+ id='admin.general.policy'
+ defaultMessage='Policy'
+ />
);
}
diff --git a/webapp/components/admin_console/privacy_settings.jsx b/webapp/components/admin_console/privacy_settings.jsx
index 6da9e6c4f..518ec807e 100644
--- a/webapp/components/admin_console/privacy_settings.jsx
+++ b/webapp/components/admin_console/privacy_settings.jsx
@@ -33,12 +33,10 @@ export default class PrivacySettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.general.privacy'
- defaultMessage='Privacy'
- />
- </h3>
+ <FormattedMessage
+ id='admin.general.privacy'
+ defaultMessage='Privacy'
+ />
);
}
diff --git a/webapp/components/admin_console/public_link_settings.jsx b/webapp/components/admin_console/public_link_settings.jsx
index 9b93a6adc..592d607d1 100644
--- a/webapp/components/admin_console/public_link_settings.jsx
+++ b/webapp/components/admin_console/public_link_settings.jsx
@@ -34,12 +34,10 @@ export default class PublicLinkSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.security.public_links'
- defaultMessage='Public Links'
- />
- </h3>
+ <FormattedMessage
+ id='admin.security.public_links'
+ defaultMessage='Public Links'
+ />
);
}
diff --git a/webapp/components/admin_console/push_settings.jsx b/webapp/components/admin_console/push_settings.jsx
index 73189cd8f..2fc63afe0 100644
--- a/webapp/components/admin_console/push_settings.jsx
+++ b/webapp/components/admin_console/push_settings.jsx
@@ -100,12 +100,10 @@ export default class PushSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.notifications.title'
- defaultMessage='Notification Settings'
- />
- </h3>
+ <FormattedMessage
+ id='admin.notifications.title'
+ defaultMessage='Notification Settings'
+ />
);
}
diff --git a/webapp/components/admin_console/rate_settings.jsx b/webapp/components/admin_console/rate_settings.jsx
index 73e9a4131..9b0a8076f 100644
--- a/webapp/components/admin_console/rate_settings.jsx
+++ b/webapp/components/admin_console/rate_settings.jsx
@@ -44,12 +44,10 @@ export default class RateSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.rate.title'
- defaultMessage='Rate Limit Settings'
- />
- </h3>
+ <FormattedMessage
+ id='admin.rate.title'
+ defaultMessage='Rate Limit Settings'
+ />
);
}
diff --git a/webapp/components/admin_console/reset_password_modal.jsx b/webapp/components/admin_console/reset_password_modal.jsx
index 1b9e5b37a..d01fc15f3 100644
--- a/webapp/components/admin_console/reset_password_modal.jsx
+++ b/webapp/components/admin_console/reset_password_modal.jsx
@@ -4,13 +4,24 @@
import * as Utils from 'utils/utils.jsx';
import {Modal} from 'react-bootstrap';
-import {injectIntl, intlShape, FormattedMessage} from 'react-intl';
+import {FormattedMessage} from 'react-intl';
import {adminResetPassword} from 'actions/admin_actions.jsx';
import React from 'react';
-class ResetPasswordModal extends React.Component {
+export default class ResetPasswordModal extends React.Component {
+ static propTypes = {
+ user: React.PropTypes.object,
+ show: React.PropTypes.bool.isRequired,
+ onModalSubmit: React.PropTypes.func,
+ onModalDismissed: React.PropTypes.func
+ };
+
+ static defaultProps = {
+ show: false
+ };
+
constructor(props) {
super(props);
@@ -150,18 +161,3 @@ class ResetPasswordModal extends React.Component {
);
}
}
-
-ResetPasswordModal.defaultProps = {
- show: false
-};
-
-ResetPasswordModal.propTypes = {
- intl: intlShape.isRequired,
- user: React.PropTypes.object,
- team: React.PropTypes.object,
- show: React.PropTypes.bool.isRequired,
- onModalSubmit: React.PropTypes.func,
- onModalDismissed: React.PropTypes.func
-};
-
-export default injectIntl(ResetPasswordModal);
diff --git a/webapp/components/admin_console/saml_settings.jsx b/webapp/components/admin_console/saml_settings.jsx
index 7b9ed38b8..6025abe28 100644
--- a/webapp/components/admin_console/saml_settings.jsx
+++ b/webapp/components/admin_console/saml_settings.jsx
@@ -130,12 +130,10 @@ export default class SamlSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.authentication.saml'
- defaultMessage='SAML'
- />
- </h3>
+ <FormattedMessage
+ id='admin.authentication.saml'
+ defaultMessage='SAML'
+ />
);
}
diff --git a/webapp/components/admin_console/select_team_modal.jsx b/webapp/components/admin_console/select_team_modal.jsx
deleted file mode 100644
index 68e20f852..000000000
--- a/webapp/components/admin_console/select_team_modal.jsx
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ReactDOM from 'react-dom';
-import {FormattedMessage} from 'react-intl';
-import {Modal} from 'react-bootstrap';
-import React from 'react';
-
-import {sortTeamsByDisplayName} from 'utils/utils.jsx';
-
-export default class SelectTeamModal extends React.Component {
- constructor(props) {
- super(props);
-
- this.doSubmit = this.doSubmit.bind(this);
- this.doCancel = this.doCancel.bind(this);
- }
-
- doSubmit(e) {
- e.preventDefault();
- this.props.onModalSubmit(ReactDOM.findDOMNode(this.refs.team).value);
- }
- doCancel() {
- this.props.onModalDismissed();
- }
-
- render() {
- if (this.props.teams == null) {
- return <div/>;
- }
-
- const options = [];
- let teamsArray = [];
-
- Reflect.ownKeys(this.props.teams).forEach((key) => {
- teamsArray.push(this.props.teams[key]);
- });
-
- teamsArray = teamsArray.sort(sortTeamsByDisplayName);
- for (let i = 0; i < teamsArray.length; i++) {
- const team = teamsArray[i];
- options.push(
- <option
- key={'opt_' + team.id}
- value={team.id}
- >
- {team.display_name}
- </option>
- );
- }
-
- return (
- <Modal
- show={this.props.show}
- onHide={this.doCancel}
- >
- <Modal.Header closeButton={true}>
- <Modal.Title>
- <FormattedMessage
- id='admin.select_team.selectTeam'
- defaultMessage='Select Team'
- />
- </Modal.Title>
- </Modal.Header>
- <form
- role='form'
- className='form-horizontal'
- >
- <Modal.Body>
- <div className='form-group'>
- <div className='col-sm-12'>
- <select
- ref='team'
- size='10'
- className='form-control'
- >
- {options}
- </select>
- </div>
- </div>
- </Modal.Body>
- <Modal.Footer>
- <button
- type='button'
- className='btn btn-default'
- onClick={this.doCancel}
- >
- <FormattedMessage
- id='admin.select_team.close'
- defaultMessage='Close'
- />
- </button>
- <button
- onClick={this.doSubmit}
- type='submit'
- className='btn btn-primary'
- tabIndex='2'
- >
- <FormattedMessage
- id='admin.select_team.select'
- defaultMessage='Select'
- />
- </button>
- </Modal.Footer>
- </form>
- </Modal>
- );
- }
-}
-
-SelectTeamModal.defaultProps = {
- show: false
-};
-
-SelectTeamModal.propTypes = {
- teams: React.PropTypes.object,
- show: React.PropTypes.bool.isRequired,
- onModalSubmit: React.PropTypes.func,
- onModalDismissed: React.PropTypes.func
-};
diff --git a/webapp/components/admin_console/session_settings.jsx b/webapp/components/admin_console/session_settings.jsx
index 9624dea18..b238da90f 100644
--- a/webapp/components/admin_console/session_settings.jsx
+++ b/webapp/components/admin_console/session_settings.jsx
@@ -39,12 +39,10 @@ export default class SessionSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.security.session'
- defaultMessage='Sessions'
- />
- </h3>
+ <FormattedMessage
+ id='admin.security.session'
+ defaultMessage='Sessions'
+ />
);
}
diff --git a/webapp/components/admin_console/signup_settings.jsx b/webapp/components/admin_console/signup_settings.jsx
index 0c884f486..b75b7591a 100644
--- a/webapp/components/admin_console/signup_settings.jsx
+++ b/webapp/components/admin_console/signup_settings.jsx
@@ -36,12 +36,10 @@ export default class SignupSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.security.signup'
- defaultMessage='Signup'
- />
- </h3>
+ <FormattedMessage
+ id='admin.security.signup'
+ defaultMessage='Signup'
+ />
);
}
diff --git a/webapp/components/admin_console/storage_settings.jsx b/webapp/components/admin_console/storage_settings.jsx
index 381206bf0..41d38d1ca 100644
--- a/webapp/components/admin_console/storage_settings.jsx
+++ b/webapp/components/admin_console/storage_settings.jsx
@@ -52,12 +52,10 @@ export default class StorageSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.files.storage'
- defaultMessage='Storage'
- />
- </h3>
+ <FormattedMessage
+ id='admin.files.storage'
+ defaultMessage='Storage'
+ />
);
}
diff --git a/webapp/components/admin_console/system_users/system_users.jsx b/webapp/components/admin_console/system_users/system_users.jsx
new file mode 100644
index 000000000..a311aebb7
--- /dev/null
+++ b/webapp/components/admin_console/system_users/system_users.jsx
@@ -0,0 +1,370 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+import {FormattedMessage} from 'react-intl';
+
+import {
+ loadProfiles,
+ loadProfilesAndTeamMembers,
+ loadProfilesWithoutTeam,
+ searchUsers
+} from 'actions/user_actions.jsx';
+
+import AdminStore from 'stores/admin_store.jsx';
+import AnalyticsStore from 'stores/analytics_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+
+import {getAllTeams, getStandardAnalytics, getTeamStats, getUser} from 'utils/async_client.jsx';
+import {Constants, StatTypes, UserSearchOptions} from 'utils/constants.jsx';
+import {convertTeamMapToList} from 'utils/team_utils.jsx';
+import * as Utils from 'utils/utils.jsx';
+
+import SystemUsersList from './system_users_list.jsx';
+
+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 {
+ constructor(props) {
+ super(props);
+
+ this.updateTeamsFromStore = this.updateTeamsFromStore.bind(this);
+ 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 = {
+ teams: convertTeamMapToList(AdminStore.getAllTeams()),
+ totalUsers: AnalyticsStore.getAllSystem()[StatTypes.TOTAL_USERS],
+ users: UserStore.getProfileList(),
+
+ teamId: ALL_USERS,
+ term: '',
+ loading: true,
+ searching: false
+ };
+ }
+
+ componentDidMount() {
+ AdminStore.addAllTeamsChangeListener(this.updateTeamsFromStore);
+
+ 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);
+ getAllTeams();
+ }
+
+ componentWillUpdate(nextProps, nextState) {
+ const nextTeamId = nextState.teamId;
+
+ if (this.state.teamId !== nextTeamId) {
+ this.updateTotalUsersFromStore(nextTeamId);
+ this.updateUsersFromStore(nextTeamId, nextState.term);
+
+ this.loadDataForTeam(nextTeamId);
+ }
+ }
+
+ componentWillUnmount() {
+ AdminStore.removeAllTeamsChangeListener(this.updateTeamsFromStore);
+
+ AnalyticsStore.removeChangeListener(this.updateTotalUsersFromStore);
+ TeamStore.removeStatsChangeListener(this.updateTotalUsersFromStore);
+
+ UserStore.removeChangeListener(this.updateUsersFromStore);
+ UserStore.removeInTeamChangeListener(this.updateUsersFromStore);
+ UserStore.removeWithoutTeamChangeListener(this.updateUsersFromStore);
+ }
+
+ updateTeamsFromStore() {
+ this.setState({teams: convertTeamMapToList(AdminStore.getAllTeams())});
+ }
+
+ 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) {
+ if (teamId === this.state.teamId) {
+ // Search results aren't in the store, so manually update the users in them
+ const users = [...this.state.users];
+
+ for (let i = 0; i < users.length; i++) {
+ const user = users[i];
+
+ if (UserStore.hasProfile(user.id)) {
+ users[i] = UserStore.getProfile(user.id);
+ }
+ }
+
+ this.setState({
+ users
+ });
+ } else {
+ this.doSearch(teamId, term, true);
+ }
+
+ 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 (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);
+ 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 + 1) * USERS_PER_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, USERS_PER_PAGE, this.state.teamId, this.loadComplete);
+ }
+ }
+
+ search(term) {
+ if (term === '') {
+ this.updateUsersFromStore(this.state.teamId, term);
+
+ this.setState({
+ loading: false
+ });
+
+ this.searchTimeoutId = '';
+ return;
+ }
+
+ this.doSearch(this.state.teamId, term);
+ }
+
+ doSearch(teamId, term, now = false) {
+ clearTimeout(this.searchTimeoutId);
+
+ this.setState({
+ loading: true,
+ users: []
+ });
+
+ const options = {
+ [UserSearchOptions.ALLOW_INACTIVE]: true
+ };
+ if (teamId === NO_TEAM) {
+ options[UserSearchOptions.WITHOUT_TEAM] = true;
+ }
+
+ const searchTimeoutId = setTimeout(
+ () => {
+ searchUsers(
+ term,
+ teamId,
+ options,
+ (users) => {
+ if (searchTimeoutId !== this.searchTimeoutId) {
+ return;
+ }
+
+ if (users.length > 0) {
+ this.setState({
+ loading: false,
+ users
+ });
+ } else if (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.getUserById(term, searchTimeoutId);
+ } else {
+ this.setState({
+ loading: false
+ });
+ }
+ },
+ () => {
+ this.setState({
+ loading: false
+ });
+ }
+ );
+ },
+ now ? 0 : Constants.SEARCH_TIMEOUT_MILLISECONDS
+ );
+
+ this.searchTimeoutId = searchTimeoutId;
+ }
+
+ getUserById(id, searchTimeoutId) {
+ if (UserStore.hasProfile(id)) {
+ this.setState({
+ loading: false,
+ users: [UserStore.getProfile(id)]
+ });
+
+ return;
+ }
+
+ getUser(
+ id,
+ (user) => {
+ if (searchTimeoutId !== this.searchTimeoutId) {
+ return;
+ }
+
+ this.setState({
+ loading: false,
+ users: [user]
+ });
+ },
+ () => {
+ if (searchTimeoutId !== this.searchTimeoutId) {
+ return;
+ }
+
+ this.setState({
+ loading: false,
+ users: []
+ });
+ }
+ );
+ }
+
+ renderFilterRow(doSearch) {
+ const teams = this.state.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
+ 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.state.teams}
+ teamId={this.state.teamId}
+ term={this.state.term}
+ onTermChange={this.handleTermChange}
+ />
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/webapp/components/admin_console/admin_team_members_dropdown.jsx b/webapp/components/admin_console/system_users/system_users_dropdown.jsx
index 037d8c73f..6f18754a1 100644
--- a/webapp/components/admin_console/admin_team_members_dropdown.jsx
+++ b/webapp/components/admin_console/system_users/system_users_dropdown.jsx
@@ -1,38 +1,38 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import ConfirmModal from '../confirm_modal.jsx';
+import ConfirmModal from 'components/confirm_modal.jsx';
-import UserStore from 'stores/user_store.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 {updateUserRoles, updateActive} from 'actions/user_actions.jsx';
-import {updateTeamMemberRoles, removeUserFromTeam} from 'actions/team_actions.jsx';
import {adminResetMfa} from 'actions/admin_actions.jsx';
import {FormattedMessage} from 'react-intl';
import React from 'react';
-export default class AdminTeamMembersDropdown extends React.Component {
+export default class SystemUsersDropdown extends React.Component {
+ static propTypes = {
+ user: React.PropTypes.object.isRequired,
+ doPasswordReset: React.PropTypes.func.isRequired
+ };
+
constructor(props) {
super(props);
this.handleMakeMember = this.handleMakeMember.bind(this);
- this.handleRemoveFromTeam = this.handleRemoveFromTeam.bind(this);
this.handleMakeActive = this.handleMakeActive.bind(this);
this.handleMakeNotActive = this.handleMakeNotActive.bind(this);
- this.handleMakeTeamAdmin = this.handleMakeTeamAdmin.bind(this);
this.handleMakeSystemAdmin = this.handleMakeSystemAdmin.bind(this);
this.handleResetPassword = this.handleResetPassword.bind(this);
this.handleResetMfa = this.handleResetMfa.bind(this);
this.handleDemoteSystemAdmin = this.handleDemoteSystemAdmin.bind(this);
this.handleDemoteSubmit = this.handleDemoteSubmit.bind(this);
this.handleDemoteCancel = this.handleDemoteCancel.bind(this);
- this.doMakeMember = this.doMakeMember.bind(this);
- this.doMakeTeamAdmin = this.doMakeTeamAdmin.bind(this);
this.state = {
serverError: null,
@@ -51,16 +51,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
this.setState({serverError: err.message});
}
);
-
- updateTeamMemberRoles(
- this.props.teamMember.team_id,
- this.props.user.id,
- 'team_user',
- null,
- (err) => {
- this.setState({serverError: err.message});
- }
- );
}
handleMakeMember(e) {
@@ -73,17 +63,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
}
}
- handleRemoveFromTeam() {
- removeUserFromTeam(
- this.props.teamMember.team_id,
- this.props.user.id,
- null,
- (err) => {
- this.setState({serverError: err.message});
- }
- );
- }
-
handleMakeActive(e) {
e.preventDefault();
updateActive(this.props.user.id, true, null,
@@ -102,28 +81,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
);
}
- doMakeTeamAdmin() {
- updateTeamMemberRoles(
- this.props.teamMember.team_id,
- this.props.user.id,
- 'team_user team_admin',
- null,
- (err) => {
- this.setState({serverError: err.message});
- }
- );
- }
-
- handleMakeTeamAdmin(e) {
- e.preventDefault();
- const me = UserStore.getCurrentUser();
- if (this.props.user.id === me.id && me.roles.includes('system_admin')) {
- this.handleDemoteSystemAdmin(this.props.user, 'teamadmin');
- } else {
- this.doMakeTeamAdmin();
- }
- }
-
handleMakeSystemAdmin(e) {
e.preventDefault();
@@ -174,8 +131,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
handleDemoteSubmit() {
if (this.state.role === 'member') {
this.doMakeMember();
- } else {
- this.doMakeTeamAdmin();
}
const teamUrl = TeamStore.getCurrentTeamUrl();
@@ -197,9 +152,8 @@ export default class AdminTeamMembersDropdown extends React.Component {
);
}
- const teamMember = this.props.teamMember;
const user = this.props.user;
- if (!user || !teamMember) {
+ if (!user) {
return <div/>;
}
let currentRoles = (
@@ -209,15 +163,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
/>
);
- if (teamMember.roles.length > 0 && Utils.isAdmin(teamMember.roles)) {
- currentRoles = (
- <FormattedMessage
- id='team_members_dropdown.teamAdmin'
- defaultMessage='Team Admin'
- />
- );
- }
-
if (user.roles.length > 0 && Utils.isSystemAdmin(user.roles)) {
currentRoles = (
<FormattedMessage
@@ -228,8 +173,7 @@ export default class AdminTeamMembersDropdown extends React.Component {
}
const me = UserStore.getCurrentUser();
- let showMakeMember = Utils.isAdmin(teamMember.roles) || Utils.isSystemAdmin(user.roles);
- let showMakeAdmin = !Utils.isAdmin(teamMember.roles) && !Utils.isSystemAdmin(user.roles);
+ let showMakeMember = Utils.isSystemAdmin(user.roles);
let showMakeSystemAdmin = !Utils.isSystemAdmin(user.roles);
let showMakeActive = false;
let showMakeNotActive = !Utils.isSystemAdmin(user.roles);
@@ -244,7 +188,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
/>
);
showMakeMember = false;
- showMakeAdmin = false;
showMakeSystemAdmin = false;
showMakeActive = true;
showMakeNotActive = false;
@@ -273,24 +216,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
);
}
- let makeAdmin = null;
- if (showMakeAdmin) {
- makeAdmin = (
- <li role='presentation'>
- <a
- role='menuitem'
- href='#'
- onClick={this.handleMakeTeamAdmin}
- >
- <FormattedMessage
- id='admin.user_item.makeTeamAdmin'
- defaultMessage='Make Team Admin'
- />
- </a>
- </li>
- );
- }
-
let makeMember = null;
if (showMakeMember) {
makeMember = (
@@ -309,24 +234,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
);
}
- let removeFromTeam = null;
- if (this.props.user.id !== me.id) {
- removeFromTeam = (
- <li role='presentation'>
- <a
- role='menuitem'
- href='#'
- onClick={this.handleRemoveFromTeam}
- >
- <FormattedMessage
- id='team_members_dropdown.leave_team'
- defaultMessage='Remove From Team'
- />
- </a>
- </li>
- );
- }
-
let menuClass = '';
if (disableActivationToggle) {
menuClass = 'disabled';
@@ -493,8 +400,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
className='dropdown-menu member-menu'
role='menu'
>
- {removeFromTeam}
- {makeAdmin}
{makeMember}
{makeActive}
{makeNotActive}
@@ -508,9 +413,3 @@ export default class AdminTeamMembersDropdown extends React.Component {
);
}
}
-
-AdminTeamMembersDropdown.propTypes = {
- user: React.PropTypes.object.isRequired,
- teamMember: React.PropTypes.object.isRequired,
- doPasswordReset: React.PropTypes.func.isRequired
-};
diff --git a/webapp/components/admin_console/system_users/system_users_list.jsx b/webapp/components/admin_console/system_users/system_users_list.jsx
new file mode 100644
index 000000000..5d8837164
--- /dev/null
+++ b/webapp/components/admin_console/system_users/system_users_list.jsx
@@ -0,0 +1,232 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
+
+import ResetPasswordModal from 'components/admin_console/reset_password_modal.jsx';
+import SearchableUserList from 'components/searchable_user_list/searchable_user_list.jsx';
+
+import {getUser} from 'utils/async_client.jsx';
+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: React.PropTypes.arrayOf(React.PropTypes.object),
+ usersPerPage: React.PropTypes.number,
+ total: React.PropTypes.number,
+ nextPage: React.PropTypes.func,
+ search: React.PropTypes.func.isRequired,
+ focusOnMount: React.PropTypes.bool,
+ renderFilterRow: React.PropTypes.func,
+
+ teamId: React.PropTypes.string.isRequired,
+ term: React.PropTypes.string.isRequired,
+ onTermChange: React.PropTypes.func.isRequired
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.nextPage = this.nextPage.bind(this);
+ this.previousPage = this.previousPage.bind(this);
+ this.search = this.search.bind(this);
+
+ this.doPasswordReset = this.doPasswordReset.bind(this);
+ this.doPasswordResetDismiss = this.doPasswordResetDismiss.bind(this);
+ this.doPasswordResetSubmit = this.doPasswordResetSubmit.bind(this);
+
+ this.state = {
+ page: 0,
+
+ 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});
+ }
+ }
+
+ doPasswordReset(user) {
+ this.setState({
+ showPasswordModal: true,
+ user
+ });
+ }
+
+ doPasswordResetDismiss() {
+ this.setState({
+ showPasswordModal: false,
+ user: null
+ });
+ }
+
+ doPasswordResetSubmit(user) {
+ getUser(user.id);
+
+ 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} 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} 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
+ }}
+ nextPage={this.nextPage}
+ previousPage={this.previousPage}
+ search={this.search}
+ page={this.state.page}
+ term={this.props.term}
+ onTermChange={this.props.onTermChange}
+ />
+ <ResetPasswordModal
+ user={this.state.user}
+ show={this.state.showPasswordModal}
+ onModalSubmit={this.doPasswordResetSubmit}
+ onModalDismissed={this.doPasswordResetDismiss}
+ />
+ </div>
+ );
+ }
+}
diff --git a/webapp/components/admin_console/team_users.jsx b/webapp/components/admin_console/team_users.jsx
deleted file mode 100644
index 5bdaedf6e..000000000
--- a/webapp/components/admin_console/team_users.jsx
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import SearchableUserList from 'components/searchable_user_list.jsx';
-import AdminTeamMembersDropdown from './admin_team_members_dropdown.jsx';
-import ResetPasswordModal from './reset_password_modal.jsx';
-import FormError from 'components/form_error.jsx';
-
-import AdminStore from 'stores/admin_store.jsx';
-import TeamStore from 'stores/team_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-
-import {searchUsers, loadProfilesAndTeamMembers, loadTeamMembersForProfilesList} from 'actions/user_actions.jsx';
-import {getTeamStats, getUser} from 'utils/async_client.jsx';
-
-import {Constants, UserSearchOptions} from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import React from 'react';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-const USERS_PER_PAGE = 50;
-
-export default class UserList extends React.Component {
- static get propTypes() {
- return {
- params: React.PropTypes.object.isRequired
- };
- }
-
- constructor(props) {
- super(props);
-
- this.onAllTeamsChange = this.onAllTeamsChange.bind(this);
- this.onStatsChange = this.onStatsChange.bind(this);
- this.onUsersChange = this.onUsersChange.bind(this);
- this.onTeamChange = this.onTeamChange.bind(this);
-
- this.doPasswordReset = this.doPasswordReset.bind(this);
- this.doPasswordResetDismiss = this.doPasswordResetDismiss.bind(this);
- this.doPasswordResetSubmit = this.doPasswordResetSubmit.bind(this);
- this.nextPage = this.nextPage.bind(this);
- this.search = this.search.bind(this);
- this.loadComplete = this.loadComplete.bind(this);
-
- this.searchTimeoutId = 0;
-
- const stats = TeamStore.getStats(this.props.params.team);
-
- this.state = {
- team: AdminStore.getTeam(this.props.params.team),
- users: [],
- teamMembers: TeamStore.getMembersInTeam(this.props.params.team),
- total: stats.total_member_count,
- serverError: null,
- showPasswordModal: false,
- loading: true,
- user: null
- };
- }
-
- componentDidMount() {
- AdminStore.addAllTeamsChangeListener(this.onAllTeamsChange);
- UserStore.addChangeListener(this.onUsersChange);
- UserStore.addInTeamChangeListener(this.onUsersChange);
- TeamStore.addChangeListener(this.onTeamChange);
- TeamStore.addStatsChangeListener(this.onStatsChange);
-
- loadProfilesAndTeamMembers(0, Constants.PROFILE_CHUNK_SIZE, this.props.params.team, this.loadComplete);
- getTeamStats(this.props.params.team);
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.params.team !== this.props.params.team) {
- const stats = TeamStore.getStats(nextProps.params.team);
-
- this.setState({
- team: AdminStore.getTeam(nextProps.params.team),
- users: [],
- teamMembers: TeamStore.getMembersInTeam(nextProps.params.team),
- total: stats.total_member_count,
- serverError: null,
- showPasswordModal: false,
- loading: true,
- user: null
- });
-
- loadProfilesAndTeamMembers(0, Constants.PROFILE_CHUNK_SIZE, nextProps.params.team, this.loadComplete);
- getTeamStats(nextProps.params.team);
- }
- }
-
- componentWillUnmount() {
- AdminStore.removeAllTeamsChangeListener(this.onAllTeamsChange);
- UserStore.removeChangeListener(this.onUsersChange);
- UserStore.removeInTeamChangeListener(this.onUsersChange);
- TeamStore.removeChangeListener(this.onTeamChange);
- TeamStore.removeStatsChangeListener(this.onStatsChange);
- }
-
- loadComplete() {
- this.setState({loading: false});
- }
-
- onAllTeamsChange() {
- this.setState({
- team: AdminStore.getTeam(this.props.params.team)
- });
- }
-
- onStatsChange() {
- const stats = TeamStore.getStats(this.props.params.team);
- this.setState({total: stats.total_member_count});
- }
-
- onUsersChange() {
- this.setState({users: UserStore.getProfileListInTeam(this.props.params.team)});
- }
-
- onTeamChange() {
- this.setState({teamMembers: TeamStore.getMembersInTeam(this.props.params.team)});
- }
-
- nextPage(page) {
- loadProfilesAndTeamMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE, this.props.params.team);
- }
-
- doPasswordReset(user) {
- this.setState({
- showPasswordModal: true,
- user
- });
- }
-
- doPasswordResetDismiss() {
- this.setState({
- showPasswordModal: false,
- user: null
- });
- }
-
- doPasswordResetSubmit(user) {
- getUser(user.id);
- this.setState({
- showPasswordModal: false,
- user: null
- });
- }
-
- search(term) {
- clearTimeout(this.searchTimeoutId);
-
- if (term === '') {
- this.setState({search: false, users: UserStore.getProfileListInTeam(this.props.params.team)});
- this.searchTimeoutId = '';
- return;
- }
-
- const options = {};
- options[UserSearchOptions.ALLOW_INACTIVE] = true;
-
- const searchTimeoutId = setTimeout(
- () => {
- searchUsers(
- term,
- this.props.params.team,
- options,
- (users) => {
- if (searchTimeoutId !== this.searchTimeoutId) {
- return;
- }
-
- this.setState({loading: true, search: true, users});
- loadTeamMembersForProfilesList(users, this.props.params.team, this.loadComplete);
- }
- );
- },
- Constants.SEARCH_TIMEOUT_MILLISECONDS
- );
-
- this.searchTimeoutId = searchTimeoutId;
- }
-
- render() {
- if (!this.state.team) {
- return null;
- }
-
- const teamMembers = this.state.teamMembers;
- const users = this.state.users;
- const actionUserProps = {};
- const extraInfo = {};
- const mfaEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true' && global.window.mm_config.EnableMultifactorAuthentication === 'true';
-
- let usersToDisplay;
- if (this.state.loading) {
- usersToDisplay = null;
- } else {
- usersToDisplay = [];
-
- for (let i = 0; i < users.length; i++) {
- const user = users[i];
-
- if (teamMembers[user.id]) {
- usersToDisplay.push(user);
- actionUserProps[user.id] = {
- teamMember: teamMembers[user.id]
- };
-
- const info = [];
-
- if (user.auth_service) {
- const service = (user.auth_service === Constants.LDAP_SERVICE || user.auth_service === Constants.SAML_SERVICE) ? user.auth_service.toUpperCase() : 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'
- />
- );
- }
-
- 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'
- />
- );
- }
- }
-
- extraInfo[user.id] = info;
- }
- }
- }
-
- return (
- <div className='wrapper--fixed'>
- <h3>
- <FormattedMessage
- id='admin.userList.title2'
- defaultMessage='Users for {team} ({count})'
- values={{
- team: this.state.team.name,
- count: this.state.total
- }}
- />
- </h3>
- <FormError error={this.state.serverError}/>
- <div className='more-modal__list member-list-holder'>
- <SearchableUserList
- users={usersToDisplay}
- usersPerPage={USERS_PER_PAGE}
- total={this.state.total}
- extraInfo={extraInfo}
- nextPage={this.nextPage}
- search={this.search}
- actions={[AdminTeamMembersDropdown]}
- actionProps={{
- doPasswordReset: this.doPasswordReset
- }}
- actionUserProps={actionUserProps}
- />
- </div>
- <ResetPasswordModal
- user={this.state.user}
- show={this.state.showPasswordModal}
- team={this.state.team}
- onModalSubmit={this.doPasswordResetSubmit}
- onModalDismissed={this.doPasswordResetDismiss}
- />
- </div>
- );
- }
-}
diff --git a/webapp/components/admin_console/users_and_teams_settings.jsx b/webapp/components/admin_console/users_and_teams_settings.jsx
index 2cb5b4e51..6e83c01e3 100644
--- a/webapp/components/admin_console/users_and_teams_settings.jsx
+++ b/webapp/components/admin_console/users_and_teams_settings.jsx
@@ -51,12 +51,10 @@ export default class UsersAndTeamsSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.general.usersAndTeams'
- defaultMessage='Users and Teams'
- />
- </h3>
+ <FormattedMessage
+ id='admin.general.usersAndTeams'
+ defaultMessage='Users and Teams'
+ />
);
}
diff --git a/webapp/components/admin_console/webrtc_settings.jsx b/webapp/components/admin_console/webrtc_settings.jsx
index 63c17f598..e0238e7f3 100644
--- a/webapp/components/admin_console/webrtc_settings.jsx
+++ b/webapp/components/admin_console/webrtc_settings.jsx
@@ -50,12 +50,10 @@ export default class WebrtcSettings extends AdminSettings {
renderTitle() {
return (
- <h3>
- <FormattedMessage
- id='admin.integrations.webrtc'
- defaultMessage='Mattermost WebRTC (Beta)'
- />
- </h3>
+ <FormattedMessage
+ id='admin.integrations.webrtc'
+ defaultMessage='Mattermost WebRTC (Beta)'
+ />
);
}