|
|
@@ -5,6 +5,7 @@ import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
|
|
import { IAlertRule } from 'app/stores/AlertListStore/AlertListStore';
|
|
|
import appEvents from 'app/core/app_events';
|
|
|
import IContainerProps from 'app/containers/IContainerProps';
|
|
|
+import Highlighter from 'react-highlight-words';
|
|
|
|
|
|
@inject('view', 'nav', 'alertList')
|
|
|
@observer
|
|
|
@@ -23,11 +24,6 @@ export class AlertRuleList extends React.Component<IContainerProps, any> {
|
|
|
|
|
|
this.props.nav.load('alerting', 'alert-list');
|
|
|
this.fetchRules();
|
|
|
- this.handleTooltipPositionChange = this.handleTooltipPositionChange.bind(this);
|
|
|
-
|
|
|
- this.state = {
|
|
|
- tooltipPosition: 'auto',
|
|
|
- };
|
|
|
}
|
|
|
|
|
|
onStateFilterChanged = evt => {
|
|
|
@@ -49,12 +45,10 @@ export class AlertRuleList extends React.Component<IContainerProps, any> {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
- handleTooltipPositionChange(evt) {
|
|
|
- evt.preventDefault();
|
|
|
- this.setState({
|
|
|
- tooltipPosition: evt.target.value,
|
|
|
- });
|
|
|
- }
|
|
|
+ onSearchQueryChange = evt => {
|
|
|
+ this.props.alertList.setSearchQuery(evt.target.value);
|
|
|
+ };
|
|
|
+
|
|
|
render() {
|
|
|
const { nav, alertList } = this.props;
|
|
|
|
|
|
@@ -63,8 +57,20 @@ export class AlertRuleList extends React.Component<IContainerProps, any> {
|
|
|
<PageHeader model={nav as any} />
|
|
|
<div className="page-container page-body">
|
|
|
<div className="page-action-bar">
|
|
|
+ <div className="gf-form gf-form--grow">
|
|
|
+ <label className="gf-form--has-input-icon gf-form--grow">
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ className="gf-form-input"
|
|
|
+ placeholder="Search alert"
|
|
|
+ value={alertList.search}
|
|
|
+ onChange={this.onSearchQueryChange}
|
|
|
+ />
|
|
|
+ <i className="gf-form-input-icon fa fa-search" />
|
|
|
+ </label>
|
|
|
+ </div>
|
|
|
<div className="gf-form">
|
|
|
- <label className="gf-form-label">Filter by state</label>
|
|
|
+ <label className="gf-form-label">States</label>
|
|
|
|
|
|
<div className="gf-form-select-wrapper width-13">
|
|
|
<select className="gf-form-input" onChange={this.onStateFilterChanged} value={alertList.stateFilter}>
|
|
|
@@ -80,8 +86,12 @@ export class AlertRuleList extends React.Component<IContainerProps, any> {
|
|
|
</a>
|
|
|
</div>
|
|
|
|
|
|
- <section className="card-section card-list-layout-list">
|
|
|
- <ol className="card-list">{alertList.rules.map(rule => <AlertRuleItem rule={rule} key={rule.id} />)}</ol>
|
|
|
+ <section>
|
|
|
+ <ol className="alert-rule-list">
|
|
|
+ {alertList.filteredRules.map(rule => (
|
|
|
+ <AlertRuleItem rule={rule} key={rule.id} search={alertList.search} />
|
|
|
+ ))}
|
|
|
+ </ol>
|
|
|
</section>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -99,6 +109,7 @@ function AlertStateFilterOption({ text, value }) {
|
|
|
|
|
|
export interface AlertRuleItemProps {
|
|
|
rule: IAlertRule;
|
|
|
+ search: string;
|
|
|
}
|
|
|
|
|
|
@observer
|
|
|
@@ -107,6 +118,16 @@ export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
|
|
|
this.props.rule.togglePaused();
|
|
|
};
|
|
|
|
|
|
+ renderText(text: string) {
|
|
|
+ return (
|
|
|
+ <Highlighter
|
|
|
+ highlightClassName="highlight-search-match"
|
|
|
+ textToHighlight={text}
|
|
|
+ searchWords={[this.props.search]}
|
|
|
+ />
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
render() {
|
|
|
const { rule } = this.props;
|
|
|
|
|
|
@@ -119,36 +140,33 @@ export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
|
|
|
let ruleUrl = `dashboard/${rule.dashboardUri}?panelId=${rule.panelId}&fullscreen&edit&tab=alert`;
|
|
|
|
|
|
return (
|
|
|
- <li className="card-item-wrapper">
|
|
|
- <div className="card-item card-item--alert">
|
|
|
- <div className="card-item-header">
|
|
|
- <div className="card-item-type">
|
|
|
- <a
|
|
|
- className="card-item-cog"
|
|
|
- title="Pausing an alert rule prevents it from executing"
|
|
|
- onClick={this.toggleState}
|
|
|
- >
|
|
|
- <i className={stateClass} />
|
|
|
- </a>
|
|
|
- <a className="card-item-cog" href={ruleUrl} title="Edit alert rule">
|
|
|
- <i className="icon-gf icon-gf-settings" />
|
|
|
- </a>
|
|
|
+ <li className="alert-rule-item">
|
|
|
+ <span className={`alert-rule-item__icon ${rule.stateClass}`}>
|
|
|
+ <i className={rule.stateIcon} />
|
|
|
+ </span>
|
|
|
+ <div className="alert-rule-item__body">
|
|
|
+ <div className="alert-rule-item__header">
|
|
|
+ <div className="alert-rule-item__name">
|
|
|
+ <a href={ruleUrl}>{this.renderText(rule.name)}</a>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div className="card-item-body">
|
|
|
- <div className="card-item-details">
|
|
|
- <div className="card-item-name">
|
|
|
- <a href={ruleUrl}>{rule.name}</a>
|
|
|
- </div>
|
|
|
- <div className="card-item-sub-name">
|
|
|
- <span className={`alert-list-item-state ${rule.stateClass}`}>
|
|
|
- <i className={rule.stateIcon} /> {rule.stateText}
|
|
|
- </span>
|
|
|
- <span> for {rule.stateAge}</span>
|
|
|
- </div>
|
|
|
- {rule.info && <div className="small muted">{rule.info}</div>}
|
|
|
+ <div className="alert-rule-item__text">
|
|
|
+ <span className={`${rule.stateClass}`}>{this.renderText(rule.stateText)}</span>
|
|
|
+ <span className="alert-rule-item__time"> for {rule.stateAge}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ {rule.info && <div className="small muted alert-rule-item__info">{this.renderText(rule.info)}</div>}
|
|
|
+ </div>
|
|
|
+ <div className="alert-rule-item__actions">
|
|
|
+ <a
|
|
|
+ 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} />
|
|
|
+ </a>
|
|
|
+ <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>
|
|
|
</div>
|
|
|
</li>
|
|
|
);
|