pull/10616/head
Kevin Fitzpatrick 2016-10-12 16:37:03 -07:00 committed by Jade McGough
parent 6780f7995a
commit a01b787881
4 changed files with 182 additions and 0 deletions

View File

@ -0,0 +1,126 @@
import React, {PropTypes} from 'react';
import _ from 'lodash';
const AlertsTable = React.createClass({
propTypes: {
hosts: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string,
cpu: PropTypes.number,
load: PropTypes.number,
})),
source: PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
}).isRequired,
},
getInitialState() {
return {
searchTerm: '',
filteredHosts: this.props.hosts,
sortDirection: null,
sortKey: null,
};
},
componentWillReceiveProps(newProps) {
this.filterHosts(newProps.hosts, this.state.searchTerm);
},
filterHosts(allHosts, searchTerm) {
const hosts = allHosts.filter((h) => h.name.search(searchTerm) !== -1);
this.setState({searchTerm, filteredHosts: hosts});
},
changeSort(key) {
// if we're using the key, reverse order; otherwise, set it with ascending
if (this.state.sortKey === key) {
const reverseDirection = (this.state.sortDirection === 'asc' ? 'desc' : 'asc');
this.setState({sortDirection: reverseDirection});
} else {
this.setState({sortKey: key, sortDirection: 'asc'});
}
},
sort(hosts, key, direction) {
switch (direction) {
case 'asc':
return _.sortBy(hosts, (e) => e[key]);
case 'desc':
return _.sortBy(hosts, (e) => e[key]).reverse();
default:
return hosts;
}
},
render() {
const hosts = this.sort(this.state.filteredHosts, this.state.sortKey, this.state.sortDirection);
const {source} = this.props;
return (
<div className="panel panel-minimal">
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
<h2 className="panel-title">{this.props.hosts.length} Hosts</h2>
<SearchBar onSearch={_.wrap(this.props.hosts, this.filterHosts)} />
</div>
<div className="panel-body">
<table className="table v-center">
<thead>
<tr>
<th onClick={() => this.changeSort('name')} className="sortable-header">Hostname</th>
<th className="text-center">Status</th>
<th onClick={() => this.changeSort('cpu')} className="sortable-header">CPU</th>
<th onClick={() => this.changeSort('load')} className="sortable-header">Load</th>
<th>Apps</th>
</tr>
</thead>
<tbody>
{
hosts.map(({name, cpu, load}) => {
return (
<tr key={name}>
<td className="monotype"><a href={`/sources/${source.id}/hosts/${name}`}>{name}</a></td>
<td className="text-center"><div className="table-dot dot-success"></div></td>
<td className="monotype">{`${cpu.toFixed(2)}%`}</td>
<td className="monotype">{`${load.toFixed(2)}`}</td>
<td className="monotype">influxdb, ntp, system</td>
</tr>
);
})
}
</tbody>
</table>
</div>
</div>
);
},
});
const SearchBar = React.createClass({
propTypes: {
onSearch: PropTypes.func.isRequired,
},
handleChange() {
this.props.onSearch(this.refs.searchInput.value);
},
render() {
return (
<div className="users__search-widget input-group">
<input
type="text"
className="form-control"
placeholder="Filter Hosts"
ref="searchInput"
onChange={this.handleChange}
/>
<div className="input-group-addon">
<span className="icon search" aria-hidden="true"></span>
</div>
</div>
);
},
});
export default AlertsTable;

View File

@ -0,0 +1,52 @@
import React, {PropTypes} from 'react';
import AlertsTable from '../components/AlertsTable';
const AlertsApp = React.createClass({
propTypes: {
source: PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
type: PropTypes.string, // 'influx-enterprise'
links: PropTypes.shape({
proxy: PropTypes.string.isRequired,
}).isRequired,
}).isRequired,
addFlashMessage: PropTypes.func.isRequired,
},
getInitialState() {
return {
alerts: [],
hosts: [],
};
},
render() {
return (
// I stole this from the Hosts page.
// Perhaps we should create an abstraction?
<div className="hosts hosts-page">
<div className="enterprise-header">
<div className="enterprise-header__container">
<div className="enterprise-header__left">
<h1>
Alerts
</h1>
</div>
</div>
</div>
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
<AlertsTable source={this.props.source} hosts={this.state.hosts} />
</div>
</div>
</div>
</div>
);
},
});
export default AlertsApp;

2
ui/src/alerts/index.js Normal file
View File

@ -0,0 +1,2 @@
import AlertsApp from './containers/AlertsApp';
export default AlertsApp;

View File

@ -4,6 +4,7 @@ import {Provider} from 'react-redux';
import {Router, Route, browserHistory} from 'react-router';
import App from 'src/App';
import AlertsApp from 'src/alerts';
import CheckDataNodes from 'src/CheckDataNodes';
import {HostsPage, HostPage} from 'src/hosts';
import {KapacitorPage, KapacitorTasksPage} from 'src/kapacitor';
@ -115,6 +116,7 @@ const Root = React.createClass({
<Route path="hosts/:hostID" component={HostPage} />
<Route path="kapacitor-config" component={KapacitorPage} />
<Route path="kapacitor-tasks" component={KapacitorTasksPage} />
<Route path="alerts" component={AlertsApp} />
</Route>
<Route path="tasks" component={TasksPage} />
<Route path="*" component={NotFound} />