From 2a64d19f5b22ca44f6c3d5ecffec75f62b1fba7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 2 Sep 2018 11:36:03 -0700 Subject: [PATCH] wip: load alert rules via redux --- public/app/core/reducers/index.ts | 2 +- public/app/core/reducers/location.ts | 4 +- public/app/core/selectors/navModel.ts | 2 +- .../features/admin/containers/ServerStats.tsx | 4 +- .../app/features/alerting/AlertRuleList.tsx | 27 +++++----- public/app/features/alerting/state/actions.ts | 26 ++++++++++ public/app/features/alerting/state/apis.ts | 52 ------------------- .../app/features/alerting/state/reducers.ts | 46 ++++++++++++++++ public/app/stores/configureStore.ts | 4 +- public/app/types/index.ts | 33 ++++++++++++ 10 files changed, 126 insertions(+), 74 deletions(-) create mode 100644 public/app/features/alerting/state/actions.ts delete mode 100644 public/app/features/alerting/state/apis.ts create mode 100644 public/app/features/alerting/state/reducers.ts diff --git a/public/app/core/reducers/index.ts b/public/app/core/reducers/index.ts index a3f9ca909c9..be13528c91c 100644 --- a/public/app/core/reducers/index.ts +++ b/public/app/core/reducers/index.ts @@ -1,5 +1,5 @@ import { navIndexReducer as navIndex } from './navModel'; -import location from './location'; +import { locationReducer as location } from './location'; export default { navIndex, diff --git a/public/app/core/reducers/location.ts b/public/app/core/reducers/location.ts index 5676c82844a..4591448d082 100644 --- a/public/app/core/reducers/location.ts +++ b/public/app/core/reducers/location.ts @@ -16,7 +16,7 @@ function renderUrl(path: string, query: UrlQueryMap): string { return path; } -const routerReducer = (state = initialState, action: Action): LocationState => { +export const locationReducer = (state = initialState, action: Action): LocationState => { switch (action.type) { case 'UPDATE_LOCATION': { const { path, query, routeParams } = action.payload; @@ -31,5 +31,3 @@ const routerReducer = (state = initialState, action: Action): LocationState => { return state; }; - -export default routerReducer; diff --git a/public/app/core/selectors/navModel.ts b/public/app/core/selectors/navModel.ts index 5f2d0318dff..a7e1c3330bd 100644 --- a/public/app/core/selectors/navModel.ts +++ b/public/app/core/selectors/navModel.ts @@ -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]) { const node = navIndex[id]; const main = { diff --git a/public/app/features/admin/containers/ServerStats.tsx b/public/app/features/admin/containers/ServerStats.tsx index 0b44a9af65e..97419ec9301 100644 --- a/public/app/features/admin/containers/ServerStats.tsx +++ b/public/app/features/admin/containers/ServerStats.tsx @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { hot } from 'react-hot-loader'; import { connect } from 'react-redux'; 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 PageHeader from 'app/core/components/PageHeader/PageHeader'; @@ -66,7 +66,7 @@ function StatItem(stat: ServerStat) { } const mapStateToProps = (state: StoreState) => ({ - navModel: selectNavNode(state.navIndex, 'server-stats'), + navModel: getNavModel(state.navIndex, 'server-stats'), getServerStats: getServerStats, }); diff --git a/public/app/features/alerting/AlertRuleList.tsx b/public/app/features/alerting/AlertRuleList.tsx index 84994555445..faa46945536 100644 --- a/public/app/features/alerting/AlertRuleList.tsx +++ b/public/app/features/alerting/AlertRuleList.tsx @@ -6,13 +6,15 @@ import PageHeader from 'app/core/components/PageHeader/PageHeader'; import appEvents from 'app/core/app_events'; import Highlighter from 'react-highlight-words'; import { updateLocation } from 'app/core/actions'; -import { selectNavNode } from 'app/core/selectors/navModel'; -import { NavModel, StoreState } from 'app/types'; -import { getAlertRules, AlertRule } from './state/apis'; +import { getNavModel } from 'app/core/selectors/navModel'; +import { NavModel, StoreState, AlertRule } from 'app/types'; +import { getAlertRulesAsync } from './state/actions'; interface Props { navModel: NavModel; + alertRules: AlertRule[]; updateLocation: typeof updateLocation; + getAlertRulesAsync: typeof getAlertRulesAsync; } interface State { @@ -49,16 +51,11 @@ export class AlertRuleList extends PureComponent { this.props.updateLocation({ query: { state: evt.target.value }, }); - // this.fetchRules(); + this.fetchRules(); }; async fetchRules() { - try { - const rules = await getAlertRules(); - this.setState({ rules }); - } catch (error) { - console.error(error); - } + await this.props.getAlertRulesAsync(); // this.props.alertList.loadRules({ // state: this.props.view.query.get('state') || 'all', @@ -78,8 +75,8 @@ export class AlertRuleList extends PureComponent { }; render() { - const { navModel } = this.props; - const { rules, search, stateFilter } = this.state; + const { navModel, alertRules } = this.props; + const { search, stateFilter } = this.state; return (
@@ -117,7 +114,7 @@ export class AlertRuleList extends PureComponent {
    - {rules.map(rule => )} + {alertRules.map(rule => )}
@@ -201,11 +198,13 @@ export class AlertRuleItem extends React.Component { } const mapStateToProps = (state: StoreState) => ({ - navModel: selectNavNode(state.navIndex, 'alert-list'), + navModel: getNavModel(state.navIndex, 'alert-list'), + alertRules: state.alertRules, }); const mapDispatchToProps = { updateLocation, + getAlertRulesAsync, }; export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(AlertRuleList)); diff --git a/public/app/features/alerting/state/actions.ts b/public/app/features/alerting/state/actions.ts new file mode 100644 index 00000000000..0f9caa9d47f --- /dev/null +++ b/public/app/features/alerting/state/actions.ts @@ -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): Promise => { + try { + const rules = await getBackendSrv().get('/api/alerts', {}); + dispatch(loadAlertRules(rules)); + return rules; + } catch (error) { + console.error(error); + throw error; + } +}; diff --git a/public/app/features/alerting/state/apis.ts b/public/app/features/alerting/state/apis.ts deleted file mode 100644 index 44cadc05215..00000000000 --- a/public/app/features/alerting/state/apis.ts +++ /dev/null @@ -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 => { - 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; - } -}; diff --git a/public/app/features/alerting/state/reducers.ts b/public/app/features/alerting/state/reducers.ts new file mode 100644 index 00000000000..0718c511106 --- /dev/null +++ b/public/app/features/alerting/state/reducers.ts @@ -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, +}; diff --git a/public/app/stores/configureStore.ts b/public/app/stores/configureStore.ts index 3a7d16da76d..232f2e30cb8 100644 --- a/public/app/stores/configureStore.ts +++ b/public/app/stores/configureStore.ts @@ -2,9 +2,11 @@ import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; import thunk from 'redux-thunk'; import { createLogger } from 'redux-logger'; import sharedReducers from 'app/core/reducers'; +import alertingReducers from 'app/features/alerting/state/reducers'; const rootReducer = combineReducers({ - ...sharedReducers + ...sharedReducers, + ...alertingReducers, }); export let store; diff --git a/public/app/types/index.ts b/public/app/types/index.ts index 930c08c9eb0..a409f586f33 100644 --- a/public/app/types/index.ts +++ b/public/app/types/index.ts @@ -1,3 +1,7 @@ +// +// Location +// + export interface LocationUpdate { path?: string; query?: UrlQueryMap; @@ -14,6 +18,30 @@ export interface LocationState { export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[]; 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 { text: string; url: string; @@ -37,7 +65,12 @@ export interface NavModel { export type NavIndex = { [s: string]: NavModelItem }; +// +// Store +// + export interface StoreState { navIndex: NavIndex; location: LocationState; + alertRules: AlertRule[]; }