2018-08-31 11:42:32 -05:00
|
|
|
import React, { PureComponent } from 'react';
|
2018-04-18 08:01:36 -05:00
|
|
|
import { hot } from 'react-hot-loader';
|
2018-08-31 11:42:32 -05:00
|
|
|
import { connect } from 'react-redux';
|
2017-12-28 11:49:33 -06:00
|
|
|
import classNames from 'classnames';
|
|
|
|
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
2017-12-31 07:16:19 -06:00
|
|
|
import appEvents from 'app/core/app_events';
|
2018-01-08 10:22:44 -06:00
|
|
|
import Highlighter from 'react-highlight-words';
|
2018-08-31 15:16:20 -05:00
|
|
|
import { initNav, updateLocation } from 'app/core/actions';
|
2018-08-31 11:42:32 -05:00
|
|
|
import { ContainerProps } from 'app/types';
|
2018-09-02 09:11:21 -05:00
|
|
|
import { getAlertRules, AlertRule } from './state/apis';
|
2017-12-28 11:49:33 -06:00
|
|
|
|
2018-08-31 15:16:20 -05:00
|
|
|
interface Props extends ContainerProps {
|
|
|
|
updateLocation: typeof updateLocation;
|
|
|
|
}
|
2018-08-31 11:42:32 -05:00
|
|
|
|
|
|
|
interface State {
|
|
|
|
rules: AlertRule[];
|
|
|
|
search: string;
|
|
|
|
stateFilter: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class AlertRuleList extends PureComponent<Props, State> {
|
2017-12-31 07:16:19 -06:00
|
|
|
stateFilters = [
|
|
|
|
{ text: 'All', value: 'all' },
|
|
|
|
{ text: 'OK', value: 'ok' },
|
|
|
|
{ text: 'Not OK', value: 'not_ok' },
|
|
|
|
{ text: 'Alerting', value: 'alerting' },
|
|
|
|
{ text: 'No Data', value: 'no_data' },
|
|
|
|
{ text: 'Paused', value: 'paused' },
|
|
|
|
];
|
|
|
|
|
2017-12-28 11:49:33 -06:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
2018-08-31 11:42:32 -05:00
|
|
|
this.state = {
|
|
|
|
rules: [],
|
|
|
|
search: '',
|
|
|
|
stateFilter: '',
|
|
|
|
};
|
|
|
|
|
|
|
|
this.props.initNav('alerting', 'alert-list');
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
2018-01-01 08:39:26 -06:00
|
|
|
this.fetchRules();
|
2017-12-28 11:49:33 -06:00
|
|
|
}
|
|
|
|
|
2017-12-31 07:16:19 -06:00
|
|
|
onStateFilterChanged = evt => {
|
2018-08-31 15:16:20 -05:00
|
|
|
this.props.updateLocation({
|
|
|
|
query: { state: evt.target.value },
|
|
|
|
});
|
2018-08-31 11:42:32 -05:00
|
|
|
// this.fetchRules();
|
2017-12-31 07:16:19 -06:00
|
|
|
};
|
|
|
|
|
2018-08-31 11:42:32 -05:00
|
|
|
async fetchRules() {
|
|
|
|
try {
|
|
|
|
const rules = await getAlertRules();
|
|
|
|
this.setState({ rules });
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
// this.props.alertList.loadRules({
|
|
|
|
// state: this.props.view.query.get('state') || 'all',
|
|
|
|
// });
|
2018-01-01 08:39:26 -06:00
|
|
|
}
|
|
|
|
|
2017-12-31 07:16:19 -06:00
|
|
|
onOpenHowTo = () => {
|
|
|
|
appEvents.emit('show-modal', {
|
|
|
|
src: 'public/app/features/alerting/partials/alert_howto.html',
|
|
|
|
modalClass: 'confirm-modal',
|
|
|
|
model: {},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2018-01-09 08:16:55 -06:00
|
|
|
onSearchQueryChange = evt => {
|
2018-08-31 11:42:32 -05:00
|
|
|
// this.props.alertList.setSearchQuery(evt.target.value);
|
2018-01-09 06:05:50 -06:00
|
|
|
};
|
2018-01-04 08:27:09 -06:00
|
|
|
|
2017-12-28 11:49:33 -06:00
|
|
|
render() {
|
2018-08-31 11:42:32 -05:00
|
|
|
const { navModel } = this.props;
|
|
|
|
const { rules, search, stateFilter } = this.state;
|
2017-12-31 07:16:19 -06:00
|
|
|
|
2017-12-28 11:49:33 -06:00
|
|
|
return (
|
|
|
|
<div>
|
2018-08-31 11:42:32 -05:00
|
|
|
<PageHeader model={navModel} />
|
2017-12-28 11:49:33 -06:00
|
|
|
<div className="page-container page-body">
|
|
|
|
<div className="page-action-bar">
|
2018-01-10 04:54:47 -06:00
|
|
|
<div className="gf-form gf-form--grow">
|
|
|
|
<label className="gf-form--has-input-icon gf-form--grow">
|
2018-01-04 06:08:49 -06:00
|
|
|
<input
|
|
|
|
type="text"
|
2018-01-10 04:54:47 -06:00
|
|
|
className="gf-form-input"
|
2018-01-10 06:17:43 -06:00
|
|
|
placeholder="Search alerts"
|
2018-08-31 11:42:32 -05:00
|
|
|
value={search}
|
2018-01-09 08:16:55 -06:00
|
|
|
onChange={this.onSearchQueryChange}
|
2018-01-04 06:08:49 -06:00
|
|
|
/>
|
|
|
|
<i className="gf-form-input-icon fa fa-search" />
|
|
|
|
</label>
|
|
|
|
</div>
|
2017-12-28 11:49:33 -06:00
|
|
|
<div className="gf-form">
|
2018-01-10 04:54:47 -06:00
|
|
|
<label className="gf-form-label">States</label>
|
2017-12-28 11:49:33 -06:00
|
|
|
|
|
|
|
<div className="gf-form-select-wrapper width-13">
|
2018-08-31 11:42:32 -05:00
|
|
|
<select className="gf-form-input" onChange={this.onStateFilterChanged} value={stateFilter}>
|
2017-12-31 07:16:19 -06:00
|
|
|
{this.stateFilters.map(AlertStateFilterOption)}
|
|
|
|
</select>
|
2017-12-28 11:49:33 -06:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="page-action-bar__spacer" />
|
|
|
|
|
2017-12-31 07:16:19 -06:00
|
|
|
<a className="btn btn-secondary" onClick={this.onOpenHowTo}>
|
2017-12-28 11:49:33 -06:00
|
|
|
<i className="fa fa-info-circle" /> How to add an alert
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
|
2018-01-04 06:08:49 -06:00
|
|
|
<section>
|
|
|
|
<ol className="alert-rule-list">
|
2018-08-31 15:16:20 -05:00
|
|
|
{rules.map(rule => <AlertRuleItem rule={rule} key={rule.id} search={search} />)}
|
2018-01-04 06:08:49 -06:00
|
|
|
</ol>
|
2017-12-28 11:49:33 -06:00
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-31 07:16:19 -06:00
|
|
|
function AlertStateFilterOption({ text, value }) {
|
|
|
|
return (
|
|
|
|
<option key={value} value={value}>
|
|
|
|
{text}
|
|
|
|
</option>
|
|
|
|
);
|
|
|
|
}
|
2017-12-28 11:49:33 -06:00
|
|
|
|
2017-12-31 07:16:19 -06:00
|
|
|
export interface AlertRuleItemProps {
|
2018-08-24 09:48:47 -05:00
|
|
|
rule: AlertRule;
|
2018-01-08 10:22:44 -06:00
|
|
|
search: string;
|
2017-12-31 07:16:19 -06:00
|
|
|
}
|
2017-12-28 11:49:33 -06:00
|
|
|
|
2017-12-31 07:16:19 -06:00
|
|
|
export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
|
|
|
|
toggleState = () => {
|
2018-08-31 11:42:32 -05:00
|
|
|
// this.props.rule.togglePaused();
|
2017-12-31 07:16:19 -06:00
|
|
|
};
|
|
|
|
|
2018-01-09 06:18:16 -06:00
|
|
|
renderText(text: string) {
|
2018-01-10 04:54:47 -06:00
|
|
|
return (
|
|
|
|
<Highlighter
|
|
|
|
highlightClassName="highlight-search-match"
|
|
|
|
textToHighlight={text}
|
|
|
|
searchWords={[this.props.search]}
|
|
|
|
/>
|
|
|
|
);
|
2018-01-08 10:22:44 -06:00
|
|
|
}
|
|
|
|
|
2017-12-31 07:16:19 -06:00
|
|
|
render() {
|
|
|
|
const { rule } = this.props;
|
|
|
|
|
2018-08-26 10:14:40 -05:00
|
|
|
const stateClass = classNames({
|
2017-12-31 07:16:19 -06:00
|
|
|
fa: true,
|
2018-08-31 11:42:32 -05:00
|
|
|
'fa-play': rule.state === 'paused',
|
|
|
|
'fa-pause': rule.state !== 'paused',
|
2017-12-31 07:16:19 -06:00
|
|
|
});
|
|
|
|
|
2018-08-26 10:14:40 -05:00
|
|
|
const ruleUrl = `${rule.url}?panelId=${rule.panelId}&fullscreen=true&edit=true&tab=alert`;
|
2017-12-31 07:16:19 -06:00
|
|
|
|
|
|
|
return (
|
2018-01-04 06:08:49 -06:00
|
|
|
<li className="alert-rule-item">
|
2018-01-10 04:54:47 -06:00
|
|
|
<span className={`alert-rule-item__icon ${rule.stateClass}`}>
|
|
|
|
<i className={rule.stateIcon} />
|
|
|
|
</span>
|
2018-01-04 06:08:49 -06:00
|
|
|
<div className="alert-rule-item__body">
|
|
|
|
<div className="alert-rule-item__header">
|
|
|
|
<div className="alert-rule-item__name">
|
2018-02-16 06:56:04 -06:00
|
|
|
<a href={ruleUrl}>{this.renderText(rule.name)}</a>
|
2017-12-28 11:49:33 -06:00
|
|
|
</div>
|
2018-01-04 06:08:49 -06:00
|
|
|
<div className="alert-rule-item__text">
|
2018-01-09 06:18:16 -06:00
|
|
|
<span className={`${rule.stateClass}`}>{this.renderText(rule.stateText)}</span>
|
2018-01-04 06:08:49 -06:00
|
|
|
<span className="alert-rule-item__time"> for {rule.stateAge}</span>
|
2017-12-28 11:49:33 -06:00
|
|
|
</div>
|
|
|
|
</div>
|
2018-01-09 06:18:16 -06:00
|
|
|
{rule.info && <div className="small muted alert-rule-item__info">{this.renderText(rule.info)}</div>}
|
2018-01-04 06:08:49 -06:00
|
|
|
</div>
|
2018-01-30 16:31:02 -06:00
|
|
|
|
2018-01-10 04:54:47 -06:00
|
|
|
<div className="alert-rule-item__actions">
|
2018-01-30 16:31:02 -06:00
|
|
|
<button
|
2018-01-04 06:08:49 -06:00
|
|
|
className="btn btn-small btn-inverse alert-list__btn width-2"
|
|
|
|
title="Pausing an alert rule prevents it from executing"
|
|
|
|
onClick={this.toggleState}
|
|
|
|
>
|
|
|
|
<i className={stateClass} />
|
2018-01-30 16:31:02 -06:00
|
|
|
</button>
|
2018-02-16 06:56:04 -06:00
|
|
|
<a className="btn btn-small btn-inverse alert-list__btn width-2" href={ruleUrl} title="Edit alert rule">
|
|
|
|
<i className="icon-gf icon-gf-settings" />
|
|
|
|
</a>
|
2017-12-28 11:49:33 -06:00
|
|
|
</div>
|
2017-12-31 07:16:19 -06:00
|
|
|
</li>
|
|
|
|
);
|
|
|
|
}
|
2017-12-28 11:49:33 -06:00
|
|
|
}
|
2018-04-18 08:01:36 -05:00
|
|
|
|
2018-08-31 11:42:32 -05:00
|
|
|
const mapStateToProps = state => ({
|
|
|
|
navModel: state.navModel,
|
|
|
|
});
|
|
|
|
|
|
|
|
const mapDispatchToProps = {
|
|
|
|
initNav,
|
2018-08-31 15:16:20 -05:00
|
|
|
updateLocation,
|
2018-08-31 11:42:32 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(AlertRuleList));
|