influxdb/archive/queries/containers/QueriesPage.js

188 lines
5.8 KiB
JavaScript
Raw Normal View History

import React, {PropTypes} from 'react';
import flatten from 'lodash/flatten';
import reject from 'lodash/reject';
import uniqBy from 'lodash/uniqBy';
import {
showDatabases,
showQueries,
killQuery,
} from 'shared/apis/metaQuery';
import showDatabasesParser from 'shared/parsing/showDatabases';
import showQueriesParser from 'shared/parsing/showQueries';
const times = [
{test: /ns/, magnitude: 0},
{test: /^\d*u/, magnitude: 1},
{test: /^\d*ms/, magnitude: 2},
{test: /^\d*s/, magnitude: 3},
{test: /^\d*m\d*s/, magnitude: 4},
{test: /^\d*h\d*m\d*s/, magnitude: 5},
];
export const QueriesPage = React.createClass({
propTypes: {
dataNodes: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
addFlashMessage: PropTypes.func,
params: PropTypes.shape({
clusterID: PropTypes.string.isRequired,
}),
},
getInitialState() {
return {
queries: [],
queryIDToKill: null,
};
},
componentDidMount() {
this.updateQueries();
const updateInterval = 5000;
this.intervalID = setInterval(this.updateQueries, updateInterval);
},
componentWillUnmount() {
clearInterval(this.intervalID);
},
updateQueries() {
const {dataNodes, addFlashMessage, params} = this.props;
showDatabases(dataNodes, params.clusterID).then((resp) => {
const {databases, errors} = showDatabasesParser(resp.data);
if (errors.length) {
errors.forEach((message) => addFlashMessage({type: 'error', text: message}));
return;
}
const fetches = databases.map((db) => showQueries(dataNodes, db, params.clusterID));
Promise.all(fetches).then((queryResponses) => {
const allQueries = [];
queryResponses.forEach((queryResponse) => {
const result = showQueriesParser(queryResponse.data);
if (result.errors.length) {
result.erorrs.forEach((message) => this.props.addFlashMessage({type: 'error', text: message}));
}
allQueries.push(...result.queries);
});
const queries = uniqBy(flatten(allQueries), (q) => q.id);
// sorting queries by magnitude, so generally longer queries will appear atop the list
const sortedQueries = queries.sort((a, b) => {
const aTime = times.find((t) => a.duration.match(t.test));
const bTime = times.find((t) => b.duration.match(t.test));
return +aTime.magnitude <= +bTime.magnitude;
});
this.setState({
queries: sortedQueries,
});
});
});
},
render() {
const {queries} = this.state;
return (
<div>
<div className="enterprise-header">
<div className="enterprise-header__container">
<div className="enterprise-header__left">
<h1>
Queries
</h1>
</div>
</div>
</div>
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
<div className="panel panel-minimal">
<div className="panel-body">
<table className="table v-center">
<thead>
<tr>
<th>Database</th>
<th>Query</th>
<th>Running</th>
<th></th>
</tr>
</thead>
<tbody>
{queries.map((q) => {
return (
<tr key={q.id}>
<td>{q.database}</td>
<td><code>{q.query}</code></td>
<td>{q.duration}</td>
<td className="text-right">
<button className="btn btn-xs btn-link-danger" onClick={this.handleKillQuery} data-toggle="modal" data-query-id={q.id} data-target="#killModal">
Kill
</button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div className="modal fade" id="killModal" tabIndex="-1" role="dialog" aria-labelledby="myModalLabel">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 className="modal-title" id="myModalLabel">Are you sure you want to kill this query?</h4>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">No</button>
<button type="button" className="btn btn-danger" data-dismiss="modal" onClick={this.handleConfirmKillQuery}>Yes, kill it!</button>
</div>
</div>
</div>
</div>
</div>
);
},
handleKillQuery(e) {
e.stopPropagation();
const id = e.target.dataset.queryId;
this.setState({
queryIDToKill: id,
});
},
handleConfirmKillQuery() {
const {queryIDToKill} = this.state;
if (queryIDToKill === null) {
return;
}
// optimitstic update
const {queries} = this.state;
this.setState({
queries: reject(queries, (q) => +q.id === +queryIDToKill),
});
// kill the query over http
const {dataNodes, params} = this.props;
killQuery(dataNodes, queryIDToKill, params.clusterID).then(() => {
this.setState({
queryIDToKill: null,
});
});
},
});
2016-10-20 16:50:55 +00:00
export default QueriesPage;