Refactor HostsTable for fun and SPEED
parent
e06f1c5cf4
commit
9dc8e02b1d
|
@ -19,24 +19,14 @@ const HostsTable = React.createClass({
|
|||
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) => {
|
||||
let apps = null;
|
||||
if (h.apps) {
|
||||
apps = h.apps.join(', ');
|
||||
} else {
|
||||
apps = '';
|
||||
}
|
||||
filter(allHosts, searchTerm) {
|
||||
return allHosts.filter((h) => {
|
||||
const apps = h.apps ? h.apps.join(', ') : '';
|
||||
// search each tag for the presence of the search term
|
||||
let tagResult = false;
|
||||
if (h.tags) {
|
||||
|
@ -52,17 +42,6 @@ const HostsTable = React.createClass({
|
|||
tagResult
|
||||
);
|
||||
});
|
||||
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) {
|
||||
|
@ -76,6 +55,20 @@ const HostsTable = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
updateSearchTerm(term) {
|
||||
this.setState({searchTerm: term});
|
||||
},
|
||||
|
||||
updateSort(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'});
|
||||
}
|
||||
},
|
||||
|
||||
sortableClasses(key) {
|
||||
if (this.state.sortKey === key) {
|
||||
if (this.state.sortDirection === 'asc') {
|
||||
|
@ -87,52 +80,32 @@ const HostsTable = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
const hosts = this.sort(this.state.filteredHosts, this.state.sortKey, this.state.sortDirection);
|
||||
const hostCount = hosts.length;
|
||||
const {source} = this.props;
|
||||
const {searchTerm, sortKey, sortDirection} = this.state;
|
||||
const {hosts, source} = this.props;
|
||||
const sortedHosts = this.sort(this.filter(hosts, searchTerm), sortKey, sortDirection);
|
||||
const hostCount = sortedHosts.length;
|
||||
|
||||
return (
|
||||
<div className="panel panel-minimal">
|
||||
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
|
||||
<h2 className="panel-title">{hostCount ? `${hostCount} Hosts` : ''}</h2>
|
||||
<SearchBar onSearch={_.wrap(this.props.hosts, this.filterHosts)} />
|
||||
<SearchBar onSearch={this.updateSearchTerm} />
|
||||
</div>
|
||||
<div className="panel-body">
|
||||
<table className="table v-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th onClick={() => this.changeSort('name')} className={this.sortableClasses('name')}>Hostname</th>
|
||||
<th onClick={() => this.updateSort('name')} className={this.sortableClasses('name')}>Hostname</th>
|
||||
<th className="text-center">Status</th>
|
||||
<th onClick={() => this.changeSort('cpu')} className={this.sortableClasses('cpu')}>CPU</th>
|
||||
<th onClick={() => this.changeSort('load')} className={this.sortableClasses('load')}>Load</th>
|
||||
<th onClick={() => this.updateSort('cpu')} className={this.sortableClasses('cpu')}>CPU</th>
|
||||
<th onClick={() => this.updateSort('load')} className={this.sortableClasses('load')}>Load</th>
|
||||
<th>Apps</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
hosts.map(({name, cpu, load, apps = []}) => {
|
||||
return (
|
||||
<tr key={name}>
|
||||
<td className="monotype"><Link to={`/sources/${source.id}/hosts/${name}`}>{name}</Link></td>
|
||||
<td className="text-center"><div className="table-dot dot-success"></div></td>
|
||||
<td className="monotype">{isNaN(cpu) ? 'N/A' : `${cpu.toFixed(2)}%`}</td>
|
||||
<td className="monotype">{isNaN(load) ? 'N/A' : `${load.toFixed(2)}`}</td>
|
||||
<td className="monotype">
|
||||
{apps.map((app, index) => {
|
||||
return (
|
||||
<span key={app}>
|
||||
<Link
|
||||
style={{marginLeft: "2px"}}
|
||||
to={{pathname: `/sources/${source.id}/hosts/${name}`, query: {app}}}>
|
||||
{app}
|
||||
</Link>
|
||||
{index === apps.length - 1 ? null : ', '}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
sortedHosts.map((h) => {
|
||||
return <HostRow key={h.name} host={h} source={source} />;
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
|
@ -143,13 +116,74 @@ const HostsTable = React.createClass({
|
|||
},
|
||||
});
|
||||
|
||||
const HostRow = React.createClass({
|
||||
propTypes: {
|
||||
source: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
host: PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
cpu: PropTypes.number,
|
||||
load: PropTypes.number,
|
||||
apps: PropTypes.arrayOf(PropTypes.string.isRequired),
|
||||
}),
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.host !== nextProps.host;
|
||||
},
|
||||
|
||||
render() {
|
||||
const {host, source} = this.props;
|
||||
const {name, cpu, load, apps = []} = host;
|
||||
return (
|
||||
<tr>
|
||||
<td className="monotype"><Link to={`/sources/${source.id}/hosts/${name}`}>{name}</Link></td>
|
||||
<td className="text-center"><div className="table-dot dot-success"></div></td>
|
||||
<td className="monotype">{isNaN(cpu) ? 'N/A' : `${cpu.toFixed(2)}%`}</td>
|
||||
<td className="monotype">{isNaN(load) ? 'N/A' : `${load.toFixed(2)}`}</td>
|
||||
<td className="monotype">
|
||||
{apps.map((app, index) => {
|
||||
return (
|
||||
<span key={app}>
|
||||
<Link
|
||||
style={{marginLeft: "2px"}}
|
||||
to={{pathname: `/sources/${source.id}/hosts/${name}`, query: {app}}}>
|
||||
{app}
|
||||
</Link>
|
||||
{index === apps.length - 1 ? null : ', '}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const SearchBar = React.createClass({
|
||||
propTypes: {
|
||||
onSearch: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
searchTerm: '',
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount() {
|
||||
const waitPeriod = 300;
|
||||
this.handleSearch = _.debounce(this.handleSearch, waitPeriod);
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
this.props.onSearch(this.state.searchTerm);
|
||||
},
|
||||
|
||||
handleChange() {
|
||||
this.props.onSearch(this.refs.searchInput.value);
|
||||
this.setState({searchTerm: this.refs.searchInput.value}, this.handleSearch);
|
||||
},
|
||||
|
||||
render() {
|
||||
|
|
Loading…
Reference in New Issue