From 00e8b6621a7ddf13222144d4acf80421204a23cc Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Tue, 1 Aug 2017 13:11:29 +0100 Subject: PLT-6595 (Client): Elasticsearch indexing system console UI (#6991) * PLT-6595: System Console for Elasticsearch Job Management. * Fixing UI issues * Fixing colors * ESLint Fixes. * Update test snapshots. * Fixing cancel button * Fix review comments. * Config capitalisation. * Review fixes. --- .../admin_console/elasticsearch_status/index.js | 28 ++ .../admin_console/elasticsearch_status/status.jsx | 361 +++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 webapp/components/admin_console/elasticsearch_status/index.js create mode 100644 webapp/components/admin_console/elasticsearch_status/status.jsx (limited to 'webapp/components/admin_console/elasticsearch_status') diff --git a/webapp/components/admin_console/elasticsearch_status/index.js b/webapp/components/admin_console/elasticsearch_status/index.js new file mode 100644 index 000000000..6446195d2 --- /dev/null +++ b/webapp/components/admin_console/elasticsearch_status/index.js @@ -0,0 +1,28 @@ +// 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 new file mode 100644 index 000000000..0a32d39c8 --- /dev/null +++ b/webapp/components/admin_console/elasticsearch_status/status.jsx @@ -0,0 +1,361 @@ +// 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 = ( + + ); + let cancelButton = null; + let indexButtonHelp = ( + + ); + + 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 = ( + + + + + ); + } + + if (chosenJob.status === JobStatuses.PENDING || chosenJob.status === JobStatuses.IN_PROGRESS || chosenJob.status === JobStatuses.CANCEL_REQUESTED) { + indexButtonHelp = ( + + ); + } + + if (!this.state.cancelInProgress && (chosenJob.status === JobStatuses.PENDING || chosenJob.status === JobStatuses.IN_PROGRESS)) { + cancelButton = ( + + + + ); + } + } + + const indexButton = ( + + )} + /> + ); + + let status = null; + let statusHelp = null; + let statusClass = null; + if (!this.props.isConfigured) { + status = ( + + ); + } else if (this.state.loading) { + status = ( + + ); + statusClass = 'status-icon-unknown'; + } else if (chosenJob) { + if (chosenJob.status === JobStatuses.PENDING) { + status = ( + + ); + statusHelp = ( + + ); + statusClass = 'status-icon-warning'; + } else if (chosenJob.status === JobStatuses.IN_PROGRESS) { + status = ( + + ); + statusHelp = ( + + ); + statusClass = 'status-icon-warning'; + } else if (chosenJob.status === JobStatuses.SUCCESS) { + status = ( + + ); + statusHelp = ( + + ); + statusClass = 'status-icon-success'; + } else if (chosenJob.status === JobStatuses.ERROR) { + status = ( + + ); + statusHelp = ( + + ); + statusClass = 'status-icon-error'; + } else if (chosenJob.status === JobStatuses.CANCEL_REQUESTED) { + status = ( + + ); + statusClass = 'status-icon-warning'; + } else if (chosenJob.status === JobStatuses.CANCELED) { + status = ( + + ); + statusClass = 'status-icon-error'; + } + } else { + status = ( + + ); + statusClass = 'status-icon-unknown'; + } + + if (statusHelp !== null) { + statusHelp = ( +
+
+ {statusHelp} +
+
+ ); + } + + statusClass = 'fa fa-circle margin--right ' + statusClass; + + return ( +
+ {indexButton} +
+
+
+ + + {status} +
+
+ {statusHelp} +
+
+ ); + } +} -- cgit v1.2.3-1-g7c22