mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
actions and reducers for search filter
This commit is contained in:
parent
42aaa2b907
commit
50444c32e0
32
public/app/features/alerting/AlertRuleItem.test.tsx
Normal file
32
public/app/features/alerting/AlertRuleItem.test.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import AlertRuleItem, { Props } from './AlertRuleItem';
|
||||||
|
|
||||||
|
const setup = (propOverrides?: object) => {
|
||||||
|
const props: Props = {
|
||||||
|
rule: {
|
||||||
|
id: 1,
|
||||||
|
dashboardId: 1,
|
||||||
|
panelId: 1,
|
||||||
|
name: 'Some rule',
|
||||||
|
state: 'Open',
|
||||||
|
stateText: 'state text',
|
||||||
|
stateIcon: 'icon',
|
||||||
|
stateClass: 'state class',
|
||||||
|
stateAge: 'age',
|
||||||
|
url: 'https://something.something.darkside',
|
||||||
|
},
|
||||||
|
search: '',
|
||||||
|
};
|
||||||
|
Object.assign(props, propOverrides);
|
||||||
|
|
||||||
|
return shallow(<AlertRuleItem {...props} />);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Render', () => {
|
||||||
|
it('should render component', () => {
|
||||||
|
const wrapper = setup();
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
70
public/app/features/alerting/AlertRuleItem.tsx
Normal file
70
public/app/features/alerting/AlertRuleItem.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Highlighter from 'react-highlight-words';
|
||||||
|
import classNames from 'classnames/bind';
|
||||||
|
import { AlertRule } from '../../types';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
rule: AlertRule;
|
||||||
|
search: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class AlertRuleItem extends React.Component<Props, any> {
|
||||||
|
toggleState = () => {
|
||||||
|
// this.props.rule.togglePaused();
|
||||||
|
};
|
||||||
|
|
||||||
|
renderText(text: string) {
|
||||||
|
return (
|
||||||
|
<Highlighter
|
||||||
|
highlightClassName="highlight-search-match"
|
||||||
|
textToHighlight={text}
|
||||||
|
searchWords={[this.props.search]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { rule } = this.props;
|
||||||
|
|
||||||
|
const stateClass = classNames({
|
||||||
|
fa: true,
|
||||||
|
'fa-play': rule.state === 'paused',
|
||||||
|
'fa-pause': rule.state !== 'paused',
|
||||||
|
});
|
||||||
|
|
||||||
|
const ruleUrl = `${rule.url}?panelId=${rule.panelId}&fullscreen=true&edit=true&tab=alert`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<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 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">
|
||||||
|
<button
|
||||||
|
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} />
|
||||||
|
</button>
|
||||||
|
<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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,23 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { hot } from 'react-hot-loader';
|
import { hot } from 'react-hot-loader';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import classNames from 'classnames';
|
|
||||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||||
|
import AlertRuleItem from './AlertRuleItem';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
import Highlighter from 'react-highlight-words';
|
|
||||||
import { updateLocation } from 'app/core/actions';
|
import { updateLocation } from 'app/core/actions';
|
||||||
import { getNavModel } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { NavModel, StoreState, AlertRule } from 'app/types';
|
import { NavModel, StoreState, AlertRule } from 'app/types';
|
||||||
import { getAlertRulesAsync } from './state/actions';
|
import { getAlertRulesAsync, setSearchQuery } from './state/actions';
|
||||||
|
import { getAlertRuleItems, getSearchQuery } from './state/selectors';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
navModel: NavModel;
|
navModel: NavModel;
|
||||||
alertRules: AlertRule[];
|
alertRules: AlertRule[];
|
||||||
updateLocation: typeof updateLocation;
|
updateLocation: typeof updateLocation;
|
||||||
getAlertRulesAsync: typeof getAlertRulesAsync;
|
getAlertRulesAsync: typeof getAlertRulesAsync;
|
||||||
|
setSearchQuery: typeof setSearchQuery;
|
||||||
stateFilter: string;
|
stateFilter: string;
|
||||||
|
search: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@ -32,14 +34,6 @@ export class AlertRuleList extends PureComponent<Props, State> {
|
|||||||
{ text: 'Paused', value: 'paused' },
|
{ text: 'Paused', value: 'paused' },
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
search: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
console.log('did mount');
|
console.log('did mount');
|
||||||
this.fetchRules();
|
this.fetchRules();
|
||||||
@ -77,13 +71,21 @@ export class AlertRuleList extends PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onSearchQueryChange = evt => {
|
onSearchQueryChange = event => {
|
||||||
// this.props.alertList.setSearchQuery(evt.target.value);
|
const { value } = event.target;
|
||||||
|
this.props.setSearchQuery(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
alertStateFilterOption({ text, value }) {
|
||||||
|
return (
|
||||||
|
<option key={value} value={value}>
|
||||||
|
{text}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { navModel, alertRules } = this.props;
|
const { navModel, alertRules, search } = this.props;
|
||||||
const { search } = this.state;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -107,7 +109,7 @@ export class AlertRuleList extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
<div className="gf-form-select-wrapper width-13">
|
<div className="gf-form-select-wrapper width-13">
|
||||||
<select className="gf-form-input" onChange={this.onStateFilterChanged} value={this.getStateFilter()}>
|
<select className="gf-form-input" onChange={this.onStateFilterChanged} value={this.getStateFilter()}>
|
||||||
{this.stateFilters.map(AlertStateFilterOption)}
|
{this.stateFilters.map(this.alertStateFilterOption)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -130,89 +132,17 @@ export class AlertRuleList extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function AlertStateFilterOption({ text, value }) {
|
|
||||||
return (
|
|
||||||
<option key={value} value={value}>
|
|
||||||
{text}
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AlertRuleItemProps {
|
|
||||||
rule: AlertRule;
|
|
||||||
search: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
|
|
||||||
toggleState = () => {
|
|
||||||
// this.props.rule.togglePaused();
|
|
||||||
};
|
|
||||||
|
|
||||||
renderText(text: string) {
|
|
||||||
return (
|
|
||||||
<Highlighter
|
|
||||||
highlightClassName="highlight-search-match"
|
|
||||||
textToHighlight={text}
|
|
||||||
searchWords={[this.props.search]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { rule } = this.props;
|
|
||||||
|
|
||||||
const stateClass = classNames({
|
|
||||||
fa: true,
|
|
||||||
'fa-play': rule.state === 'paused',
|
|
||||||
'fa-pause': rule.state !== 'paused',
|
|
||||||
});
|
|
||||||
|
|
||||||
const ruleUrl = `${rule.url}?panelId=${rule.panelId}&fullscreen=true&edit=true&tab=alert`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<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 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">
|
|
||||||
<button
|
|
||||||
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} />
|
|
||||||
</button>
|
|
||||||
<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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = (state: StoreState) => ({
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
navModel: getNavModel(state.navIndex, 'alert-list'),
|
navModel: getNavModel(state.navIndex, 'alert-list'),
|
||||||
alertRules: state.alertRules,
|
alertRules: getAlertRuleItems(state.alertRules),
|
||||||
stateFilter: state.location.query.state,
|
stateFilter: state.location.query.state,
|
||||||
|
search: getSearchQuery(state.alertRules),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
updateLocation,
|
updateLocation,
|
||||||
getAlertRulesAsync,
|
getAlertRulesAsync,
|
||||||
|
setSearchQuery,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(AlertRuleList));
|
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(AlertRuleList));
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Render should render component 1`] = `
|
||||||
|
<li
|
||||||
|
className="alert-rule-item"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="alert-rule-item__icon state class"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="icon"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
className="alert-rule-item__body"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="alert-rule-item__header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="alert-rule-item__name"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://something.something.darkside?panelId=1&fullscreen=true&edit=true&tab=alert"
|
||||||
|
>
|
||||||
|
<Highlighter
|
||||||
|
highlightClassName="highlight-search-match"
|
||||||
|
searchWords={
|
||||||
|
Array [
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
textToHighlight="Some rule"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="alert-rule-item__text"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="state class"
|
||||||
|
>
|
||||||
|
<Highlighter
|
||||||
|
highlightClassName="highlight-search-match"
|
||||||
|
searchWords={
|
||||||
|
Array [
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
textToHighlight="state text"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="alert-rule-item__time"
|
||||||
|
>
|
||||||
|
for
|
||||||
|
age
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="alert-rule-item__actions"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="btn btn-small btn-inverse alert-list__btn width-2"
|
||||||
|
onClick={[Function]}
|
||||||
|
title="Pausing an alert rule prevents it from executing"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa fa-pause"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
className="btn btn-small btn-inverse alert-list__btn width-2"
|
||||||
|
href="https://something.something.darkside?panelId=1&fullscreen=true&edit=true&tab=alert"
|
||||||
|
title="Edit alert rule"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="icon-gf icon-gf-settings"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
`;
|
@ -2,17 +2,32 @@ import { Dispatch } from 'redux';
|
|||||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||||
import { AlertRule } from 'app/types';
|
import { AlertRule } from 'app/types';
|
||||||
|
|
||||||
|
export enum ActionTypes {
|
||||||
|
LoadAlertRules = 'LOAD_ALERT_RULES',
|
||||||
|
SetSearchQuery = 'SET_SEARCH_QUERY',
|
||||||
|
}
|
||||||
|
|
||||||
export interface LoadAlertRulesAction {
|
export interface LoadAlertRulesAction {
|
||||||
type: 'LOAD_ALERT_RULES';
|
type: ActionTypes.LoadAlertRules;
|
||||||
payload: AlertRule[];
|
payload: AlertRule[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetSearchQueryAction {
|
||||||
|
type: ActionTypes.SetSearchQuery;
|
||||||
|
payload: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const loadAlertRules = (rules: AlertRule[]): LoadAlertRulesAction => ({
|
export const loadAlertRules = (rules: AlertRule[]): LoadAlertRulesAction => ({
|
||||||
type: 'LOAD_ALERT_RULES',
|
type: ActionTypes.LoadAlertRules,
|
||||||
payload: rules,
|
payload: rules,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Action = LoadAlertRulesAction;
|
export const setSearchQuery = (query: string): SetSearchQueryAction => ({
|
||||||
|
type: ActionTypes.SetSearchQuery,
|
||||||
|
payload: query,
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Action = LoadAlertRulesAction | SetSearchQueryAction;
|
||||||
|
|
||||||
export const getAlertRulesAsync = (options: { state: string }) => async (
|
export const getAlertRulesAsync = (options: { state: string }) => async (
|
||||||
dispatch: Dispatch<Action>
|
dispatch: Dispatch<Action>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Action } from './actions';
|
|
||||||
import { AlertRule } from 'app/types';
|
|
||||||
import alertDef from './alertDef';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { AlertRulesState } from 'app/types';
|
||||||
|
import { Action, ActionTypes } from './actions';
|
||||||
|
import alertDef from './alertDef';
|
||||||
|
|
||||||
export const initialState: AlertRule[] = [];
|
export const initialState: AlertRulesState = { items: [], searchQuery: '' };
|
||||||
|
|
||||||
export function setStateFields(rule, state) {
|
export function setStateFields(rule, state) {
|
||||||
const stateModel = alertDef.getStateDisplayModel(state);
|
const stateModel = alertDef.getStateDisplayModel(state);
|
||||||
@ -16,9 +16,9 @@ export function setStateFields(rule, state) {
|
|||||||
.replace(' ago', '');
|
.replace(' ago', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const alertRulesReducer = (state = initialState, action: Action): AlertRule[] => {
|
export const alertRulesReducer = (state = initialState, action: Action): AlertRulesState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'LOAD_ALERT_RULES': {
|
case ActionTypes.LoadAlertRules: {
|
||||||
const alertRules = action.payload;
|
const alertRules = action.payload;
|
||||||
|
|
||||||
for (const rule of alertRules) {
|
for (const rule of alertRules) {
|
||||||
@ -34,8 +34,11 @@ export const alertRulesReducer = (state = initialState, action: Action): AlertRu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return alertRules;
|
return { items: alertRules, searchQuery: state.searchQuery };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ActionTypes.SetSearchQuery:
|
||||||
|
return { items: state.items, searchQuery: action.payload };
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
9
public/app/features/alerting/state/selectors.ts
Normal file
9
public/app/features/alerting/state/selectors.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const getSearchQuery = state => state.searchQuery;
|
||||||
|
|
||||||
|
export const getAlertRuleItems = state => {
|
||||||
|
const regex = new RegExp(state.searchQuery, 'i');
|
||||||
|
|
||||||
|
return state.items.filter(item => {
|
||||||
|
return regex.test(item.name) || regex.test(item.stateText) || regex.test(item.info);
|
||||||
|
});
|
||||||
|
};
|
@ -69,8 +69,13 @@ export type NavIndex = { [s: string]: NavModelItem };
|
|||||||
// Store
|
// Store
|
||||||
//
|
//
|
||||||
|
|
||||||
|
export interface AlertRulesState {
|
||||||
|
items: AlertRule[];
|
||||||
|
searchQuery: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface StoreState {
|
export interface StoreState {
|
||||||
navIndex: NavIndex;
|
navIndex: NavIndex;
|
||||||
location: LocationState;
|
location: LocationState;
|
||||||
alertRules: AlertRule[];
|
alertRules: AlertRulesState;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user