mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
wip: load alert rules via redux
This commit is contained in:
parent
7b06800295
commit
2a64d19f5b
@ -1,5 +1,5 @@
|
|||||||
import { navIndexReducer as navIndex } from './navModel';
|
import { navIndexReducer as navIndex } from './navModel';
|
||||||
import location from './location';
|
import { locationReducer as location } from './location';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
navIndex,
|
navIndex,
|
||||||
|
@ -16,7 +16,7 @@ function renderUrl(path: string, query: UrlQueryMap): string {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
const routerReducer = (state = initialState, action: Action): LocationState => {
|
export const locationReducer = (state = initialState, action: Action): LocationState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'UPDATE_LOCATION': {
|
case 'UPDATE_LOCATION': {
|
||||||
const { path, query, routeParams } = action.payload;
|
const { path, query, routeParams } = action.payload;
|
||||||
@ -31,5 +31,3 @@ const routerReducer = (state = initialState, action: Action): LocationState => {
|
|||||||
|
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default routerReducer;
|
|
||||||
|
@ -15,7 +15,7 @@ function getNotFoundModel(): NavModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectNavNode(navIndex: NavIndex, id: string): NavModel {
|
export function getNavModel(navIndex: NavIndex, id: string): NavModel {
|
||||||
if (navIndex[id]) {
|
if (navIndex[id]) {
|
||||||
const node = navIndex[id];
|
const node = navIndex[id];
|
||||||
const main = {
|
const main = {
|
||||||
|
@ -2,7 +2,7 @@ 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 { NavModel, StoreState } from 'app/types';
|
import { NavModel, StoreState } from 'app/types';
|
||||||
import { selectNavNode } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { getServerStats, ServerStat } from '../apis';
|
import { getServerStats, ServerStat } from '../apis';
|
||||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ function StatItem(stat: ServerStat) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: StoreState) => ({
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
navModel: selectNavNode(state.navIndex, 'server-stats'),
|
navModel: getNavModel(state.navIndex, 'server-stats'),
|
||||||
getServerStats: getServerStats,
|
getServerStats: getServerStats,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,13 +6,15 @@ import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
|||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
import Highlighter from 'react-highlight-words';
|
import Highlighter from 'react-highlight-words';
|
||||||
import { updateLocation } from 'app/core/actions';
|
import { updateLocation } from 'app/core/actions';
|
||||||
import { selectNavNode } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { NavModel, StoreState } from 'app/types';
|
import { NavModel, StoreState, AlertRule } from 'app/types';
|
||||||
import { getAlertRules, AlertRule } from './state/apis';
|
import { getAlertRulesAsync } from './state/actions';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
navModel: NavModel;
|
navModel: NavModel;
|
||||||
|
alertRules: AlertRule[];
|
||||||
updateLocation: typeof updateLocation;
|
updateLocation: typeof updateLocation;
|
||||||
|
getAlertRulesAsync: typeof getAlertRulesAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@ -49,16 +51,11 @@ export class AlertRuleList extends PureComponent<Props, State> {
|
|||||||
this.props.updateLocation({
|
this.props.updateLocation({
|
||||||
query: { state: evt.target.value },
|
query: { state: evt.target.value },
|
||||||
});
|
});
|
||||||
// this.fetchRules();
|
this.fetchRules();
|
||||||
};
|
};
|
||||||
|
|
||||||
async fetchRules() {
|
async fetchRules() {
|
||||||
try {
|
await this.props.getAlertRulesAsync();
|
||||||
const rules = await getAlertRules();
|
|
||||||
this.setState({ rules });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this.props.alertList.loadRules({
|
// this.props.alertList.loadRules({
|
||||||
// state: this.props.view.query.get('state') || 'all',
|
// state: this.props.view.query.get('state') || 'all',
|
||||||
@ -78,8 +75,8 @@ export class AlertRuleList extends PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { navModel } = this.props;
|
const { navModel, alertRules } = this.props;
|
||||||
const { rules, search, stateFilter } = this.state;
|
const { search, stateFilter } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -117,7 +114,7 @@ export class AlertRuleList extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
<section>
|
<section>
|
||||||
<ol className="alert-rule-list">
|
<ol className="alert-rule-list">
|
||||||
{rules.map(rule => <AlertRuleItem rule={rule} key={rule.id} search={search} />)}
|
{alertRules.map(rule => <AlertRuleItem rule={rule} key={rule.id} search={search} />)}
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -201,11 +198,13 @@ export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: StoreState) => ({
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
navModel: selectNavNode(state.navIndex, 'alert-list'),
|
navModel: getNavModel(state.navIndex, 'alert-list'),
|
||||||
|
alertRules: state.alertRules,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
updateLocation,
|
updateLocation,
|
||||||
|
getAlertRulesAsync,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(AlertRuleList));
|
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(AlertRuleList));
|
||||||
|
26
public/app/features/alerting/state/actions.ts
Normal file
26
public/app/features/alerting/state/actions.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Dispatch } from 'redux';
|
||||||
|
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||||
|
import { AlertRule } from 'app/types';
|
||||||
|
|
||||||
|
export interface LoadAlertRulesAction {
|
||||||
|
type: 'LOAD_ALERT_RULES';
|
||||||
|
payload: AlertRule[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadAlertRules = (rules: AlertRule[]): LoadAlertRulesAction => ({
|
||||||
|
type: 'LOAD_ALERT_RULES',
|
||||||
|
payload: rules,
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Action = LoadAlertRulesAction;
|
||||||
|
|
||||||
|
export const getAlertRulesAsync = () => async (dispatch: Dispatch<Action>): Promise<AlertRule[]> => {
|
||||||
|
try {
|
||||||
|
const rules = await getBackendSrv().get('/api/alerts', {});
|
||||||
|
dispatch(loadAlertRules(rules));
|
||||||
|
return rules;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
@ -1,52 +0,0 @@
|
|||||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
|
||||||
import alertDef from './alertDef';
|
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
export interface AlertRule {
|
|
||||||
id: number;
|
|
||||||
dashboardId: number;
|
|
||||||
panelId: number;
|
|
||||||
name: string;
|
|
||||||
state: string;
|
|
||||||
stateText: string;
|
|
||||||
stateIcon: string;
|
|
||||||
stateClass: string;
|
|
||||||
stateAge: string;
|
|
||||||
info?: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setStateFields(rule, state) {
|
|
||||||
const stateModel = alertDef.getStateDisplayModel(state);
|
|
||||||
rule.state = state;
|
|
||||||
rule.stateText = stateModel.text;
|
|
||||||
rule.stateIcon = stateModel.iconClass;
|
|
||||||
rule.stateClass = stateModel.stateClass;
|
|
||||||
rule.stateAge = moment(rule.newStateDate)
|
|
||||||
.fromNow()
|
|
||||||
.replace(' ago', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAlertRules = async (): Promise<AlertRule[]> => {
|
|
||||||
try {
|
|
||||||
const rules = await getBackendSrv().get('/api/alerts', {});
|
|
||||||
|
|
||||||
for (const rule of rules) {
|
|
||||||
setStateFields(rule, rule.state);
|
|
||||||
|
|
||||||
if (rule.state !== 'paused') {
|
|
||||||
if (rule.executionError) {
|
|
||||||
rule.info = 'Execution Error: ' + rule.executionError;
|
|
||||||
}
|
|
||||||
if (rule.evalData && rule.evalData.noData) {
|
|
||||||
rule.info = 'Query returned no data';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rules;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
46
public/app/features/alerting/state/reducers.ts
Normal file
46
public/app/features/alerting/state/reducers.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { Action } from './actions';
|
||||||
|
import { AlertRule } from 'app/types';
|
||||||
|
import alertDef from './alertDef';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
export const initialState: AlertRule[] = [];
|
||||||
|
|
||||||
|
export function setStateFields(rule, state) {
|
||||||
|
const stateModel = alertDef.getStateDisplayModel(state);
|
||||||
|
rule.state = state;
|
||||||
|
rule.stateText = stateModel.text;
|
||||||
|
rule.stateIcon = stateModel.iconClass;
|
||||||
|
rule.stateClass = stateModel.stateClass;
|
||||||
|
rule.stateAge = moment(rule.newStateDate)
|
||||||
|
.fromNow()
|
||||||
|
.replace(' ago', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export const alertRulesReducer = (state = initialState, action: Action): AlertRule[] => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'LOAD_ALERT_RULES': {
|
||||||
|
const alertRules = action.payload;
|
||||||
|
|
||||||
|
for (const rule of alertRules) {
|
||||||
|
setStateFields(rule, rule.state);
|
||||||
|
|
||||||
|
if (rule.state !== 'paused') {
|
||||||
|
if (rule.executionError) {
|
||||||
|
rule.info = 'Execution Error: ' + rule.executionError;
|
||||||
|
}
|
||||||
|
if (rule.evalData && rule.evalData.noData) {
|
||||||
|
rule.info = 'Query returned no data';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return alertRules;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
alertRules: alertRulesReducer,
|
||||||
|
};
|
@ -2,9 +2,11 @@ import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
|
|||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import { createLogger } from 'redux-logger';
|
import { createLogger } from 'redux-logger';
|
||||||
import sharedReducers from 'app/core/reducers';
|
import sharedReducers from 'app/core/reducers';
|
||||||
|
import alertingReducers from 'app/features/alerting/state/reducers';
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
...sharedReducers
|
...sharedReducers,
|
||||||
|
...alertingReducers,
|
||||||
});
|
});
|
||||||
|
|
||||||
export let store;
|
export let store;
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
//
|
||||||
|
// Location
|
||||||
|
//
|
||||||
|
|
||||||
export interface LocationUpdate {
|
export interface LocationUpdate {
|
||||||
path?: string;
|
path?: string;
|
||||||
query?: UrlQueryMap;
|
query?: UrlQueryMap;
|
||||||
@ -14,6 +18,30 @@ export interface LocationState {
|
|||||||
export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[];
|
export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[];
|
||||||
export type UrlQueryMap = { [s: string]: UrlQueryValue };
|
export type UrlQueryMap = { [s: string]: UrlQueryValue };
|
||||||
|
|
||||||
|
//
|
||||||
|
// Alerting
|
||||||
|
//
|
||||||
|
|
||||||
|
export interface AlertRule {
|
||||||
|
id: number;
|
||||||
|
dashboardId: number;
|
||||||
|
panelId: number;
|
||||||
|
name: string;
|
||||||
|
state: string;
|
||||||
|
stateText: string;
|
||||||
|
stateIcon: string;
|
||||||
|
stateClass: string;
|
||||||
|
stateAge: string;
|
||||||
|
info?: string;
|
||||||
|
url: string;
|
||||||
|
executionError?: string;
|
||||||
|
evalData?: { noData: boolean };
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// NavModel
|
||||||
|
//
|
||||||
|
|
||||||
export interface NavModelItem {
|
export interface NavModelItem {
|
||||||
text: string;
|
text: string;
|
||||||
url: string;
|
url: string;
|
||||||
@ -37,7 +65,12 @@ export interface NavModel {
|
|||||||
|
|
||||||
export type NavIndex = { [s: string]: NavModelItem };
|
export type NavIndex = { [s: string]: NavModelItem };
|
||||||
|
|
||||||
|
//
|
||||||
|
// Store
|
||||||
|
//
|
||||||
|
|
||||||
export interface StoreState {
|
export interface StoreState {
|
||||||
navIndex: NavIndex;
|
navIndex: NavIndex;
|
||||||
location: LocationState;
|
location: LocationState;
|
||||||
|
alertRules: AlertRule[];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user