Commit 5e0aa96b authored by Joram Wilander's avatar Joram Wilander Committed by Harrison Healey

PLT-6657 Move system console to use v4 endpoints and redux (#6572)

* Move system console to use v4 endpoints and redux

* Rename logs dir to get past gitignore

* Fix test email

* Update brand unit test

* Updates per feedback
parent 75984393
......@@ -2,201 +2,154 @@
// See License.txt for license information.
import Client from 'client/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {browserHistory} from 'react-router/es6';
// Redux actions
import store from 'stores/redux_store.jsx';
const dispatch = store.dispatch;
const getState = store.getState;
import {getUser} from 'mattermost-redux/actions/users';
import {updateUserMfa, updateUserPassword} from 'mattermost-redux/actions/users';
import * as AdminActions from 'mattermost-redux/actions/admin';
export function saveConfig(config, success, error) {
Client.saveConfig(
config,
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.updateConfig(config)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.updateConfig.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function reloadConfig(success, error) {
Client.reloadConfig(
() => {
AsyncClient.getConfig();
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.reloadConfig()(dispatch, getState).then(
(data) => {
if (data && success) {
AdminActions.getConfig()(dispatch, getState);
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.reloadConfig.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function adminResetMfa(userId, success, error) {
Client.adminResetMfa(
userId,
() => {
getUser(userId)(dispatch, getState);
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
updateUserMfa(userId, false)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.users.updateUser.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function getClusterStatus(success, error) {
Client.getClusterStatus(
AdminActions.getClusterStatus()(dispatch, getState).then(
(data) => {
if (success) {
if (data && success) {
success(data);
}
},
(err) => {
AsyncClient.dispatchError(err, 'getClusterStatus');
if (error) {
error(err);
}
}
);
}
export function saveComplianceReports(job, success, error) {
Client.saveComplianceReports(
job,
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
} else if (data == null && error) {
const serverError = getState().requests.admin.getClusterStatus.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function testEmail(config, success, error) {
Client.testEmail(
config,
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.testEmail(config)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.testEmail.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function ldapTest(success, error) {
Client.ldapTest(
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.testLdap()(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.testLdap.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function invalidateAllCaches(success, error) {
Client.invalidateAllCaches(
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.invalidateCaches()(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.invalidateCaches.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function recycleDatabaseConnection(success, error) {
Client.recycleDatabaseConnection(
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.recycleDatabase()(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.recycleDatabase.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function adminResetPassword(userId, password, success, error) {
Client.adminResetPassword(
userId,
password,
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
updateUserPassword(userId, '', password)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.users.updateUser.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function samlCertificateStatus(success, error) {
Client.samlCertificateStatus(
AdminActions.getSamlCertificateStatus()(dispatch, getState).then(
(data) => {
if (success) {
if (data && success) {
success(data);
}
},
(err) => {
if (error) {
error(err);
} else if (data == null && error) {
const serverError = getState().requests.admin.getSamlCertificateStatus.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function ldapSyncNow(success, error) {
Client.ldapSyncNow(
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.syncLdap()(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.syncLdap.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
......@@ -316,16 +269,13 @@ export function regenerateOAuthAppSecret(oauthAppId, success, error) {
}
export function uploadBrandImage(brandImage, success, error) {
Client.uploadBrandImage(
brandImage,
() => {
if (success) {
success();
}
},
(err) => {
if (error) {
error(err);
AdminActions.uploadBrandImage(brandImage)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.uploadBrandImage.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
......@@ -362,33 +312,79 @@ export function removeLicenseFile(success, error) {
);
}
export function uploadCertificateFile(certificateFile, success, error) {
Client.uploadCertificateFile(
certificateFile,
() => {
if (success) {
success();
export function uploadPublicSamlCertificate(file, success, error) {
AdminActions.uploadPublicSamlCertificate(file)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.uploadPublicSamlCertificate.error;
error({id: serverError.server_error_id, ...serverError});
}
},
(err) => {
if (error) {
error(err);
}
);
}
export function uploadPrivateSamlCertificate(file, success, error) {
AdminActions.uploadPrivateSamlCertificate(file)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.uploadPrivateSamlCertificate.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function removeCertificateFile(certificateId, success, error) {
Client.removeCertificateFile(
certificateId,
() => {
if (success) {
success();
export function uploadIdpSamlCertificate(file, success, error) {
AdminActions.uploadIdpSamlCertificate(file)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.uploadIdpSamlCertificate.error;
error({id: serverError.server_error_id, ...serverError});
}
},
(err) => {
if (error) {
error(err);
}
);
}
export function removePublicSamlCertificate(success, error) {
AdminActions.removePublicSamlCertificate()(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.removePublicSamlCertificate.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function removePrivateSamlCertificate(success, error) {
AdminActions.removePrivateSamlCertificate()(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.removePrivateSamlCertificate.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function removeIdpSamlCertificate(success, error) {
AdminActions.removeIdpSamlCertificate()(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.removeIdpSamlCertificate.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
......
......@@ -6,46 +6,37 @@ import PropTypes from 'prop-types';
import 'bootstrap';
import AnnouncementBar from 'components/announcement_bar';
import AdminStore from 'stores/admin_store.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import AdminSidebar from './admin_sidebar.jsx';
export default class AdminConsole extends React.Component {
static get propTypes() {
return {
children: PropTypes.node.isRequired
};
}
static propTypes = {
constructor(props) {
super(props);
/*
* Children components to render
*/
children: PropTypes.node.isRequired,
this.handleConfigChange = this.handleConfigChange.bind(this);
this.state = {
config: AdminStore.getConfig()
};
}
/*
* Object representing the config file
*/
config: PropTypes.object.isRequired,
componentWillMount() {
AdminStore.addConfigChangeListener(this.handleConfigChange);
AsyncClient.getConfig();
}
actions: PropTypes.shape({
componentWillUnmount() {
AdminStore.removeConfigChangeListener(this.handleConfigChange);
/*
* Function to get the config file
*/
getConfig: PropTypes.func.isRequired
}).isRequired
}
handleConfigChange() {
this.setState({
config: AdminStore.getConfig()
});
componentWillMount() {
this.props.actions.getConfig();
}
render() {
const config = this.state.config;
if (!config) {
const config = this.props.config;
if (Object.keys(config).length === 0) {
return <div/>;
}
if (config && Object.keys(config).length === 0 && config.constructor === 'Object') {
......@@ -59,7 +50,7 @@ export default class AdminConsole extends React.Component {
// not every page in the system console will need the config, but the vast majority will
const children = React.cloneElement(this.props.children, {
config: this.state.config
config
});
return (
<div className='admin-console__wrapper'>
......
import PropTypes from 'prop-types';
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React from 'react';
import * as AsyncClient from 'utils/async_client.jsx';
import PropTypes from 'prop-types';
import FormError from 'components/form_error.jsx';
import SaveButton from 'components/admin_console/save_button.jsx';
......@@ -13,10 +10,12 @@ import SaveButton from 'components/admin_console/save_button.jsx';
import {saveConfig} from 'actions/admin_actions.jsx';
export default class AdminSettings extends React.Component {
static get propTypes() {
return {
config: PropTypes.object
};
static propTypes = {
/*
* Object representing the config file
*/
config: PropTypes.object
}
constructor(props) {
......@@ -58,10 +57,8 @@ export default class AdminSettings extends React.Component {
saveConfig(
config,
() => {
AsyncClient.getConfig((savedConfig) => {
this.setState(this.getStateFromConfig(savedConfig));
});
(savedConfig) => {
this.setState(this.getStateFromConfig(savedConfig));
this.setState({
saveNeeded: false,
......
......@@ -4,7 +4,7 @@
import $ from 'jquery';
import AdminNavbarDropdown from './admin_navbar_dropdown.jsx';
import UserStore from 'stores/user_store.jsx';
import Client from 'client/web_client.jsx';
import {Client4} from 'mattermost-redux/client';
import {FormattedMessage} from 'react-intl';
......@@ -14,12 +14,10 @@ export default class SidebarHeader extends React.Component {
constructor(props) {
super(props);
this.toggleDropdown = this.toggleDropdown.bind(this);
this.state = {};
}
toggleDropdown(e) {
toggleDropdown = (e) => {
e.preventDefault();
if (this.refs.dropdown.blockToggle) {
......@@ -42,7 +40,7 @@ export default class SidebarHeader extends React.Component {
profilePicture = (
<img
className='user__picture'
src={Client.getUsersRoute() + '/' + me.id + '/image?time=' + me.last_picture_update}
src={Client4.getProfilePictureUrl(me.id, me.last_picture_update)}
/>
);
}
......
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import LoadingScreen from '../loading_screen.jsx';
import AuditTable from '../audit_table.jsx';
import ComplianceReports from './compliance_reports.jsx';
import LoadingScreen from 'components/loading_screen.jsx';
import AuditTable from 'components/audit_table.jsx';
import ComplianceReports from 'components/admin_console/compliance_reports';
import AdminStore from 'stores/admin_store.jsx';
import React from 'react';
import PropTypes from 'prop-types';
import {FormattedMessage} from 'react-intl';
import * as AsyncClient from 'utils/async_client.jsx';
export default class Audits extends React.PureComponent {
static propTypes = {
import {FormattedMessage} from 'react-intl';
/*
* Array of audits to render
*/
audits: PropTypes.arrayOf(PropTypes.object).isRequired,
import React from 'react';
actions: PropTypes.shape({
/*
* Function to fetch audits
*/
getAudits: PropTypes.func.isRequired
}).isRequired
}
export default class Audits extends React.Component {
constructor(props) {
super(props);
this.onAuditListenerChange = this.onAuditListenerChange.bind(this);
this.reload = this.reload.bind(this);
this.state = {
audits: AdminStore.getAudits()
loadingAudits: true
};
}
componentDidMount() {
AdminStore.addAuditChangeListener(this.onAuditListenerChange);
AsyncClient.getServerAudits();
}
componentWillUnmount() {
AdminStore.removeAuditChangeListener(this.onAuditListenerChange);
}
onAuditListenerChange() {
this.setState({
audits: AdminStore.getAudits()
});
this.props.actions.getAudits().then(
() => this.setState({loadingAudits: false})
);
}
reload() {
AdminStore.saveAudits(null);
this.setState({
audits: null
});
AsyncClient.getServerAudits();
reload = () => {
this.setState({loadingAudits: true});
this.props.actions.getAudits().then(
() => this.setState({loadingAudits: false})
);
}
render() {
var content = null;
let content = null;
if (global.window.mm_license.IsLicensed !== 'true') {
return <div/>;
}
if (this.state.audits === null) {
if (this.state.loadingAudits) {
content = <LoadingScreen/>;
} else {
content = (
<div style={{margin: '10px'}}>
<AuditTable
audits={this.state.audits}
audits={this.props.audits}
showUserId={true}
showIp={true}
showSession={true}
......
// 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))