Browse Source

wip: load alert rules via redux

Torkel Ödegaard 7 years ago
parent
commit
2a64d19f5b

+ 1 - 1
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,

+ 1 - 3
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;

+ 1 - 1
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 = {

+ 2 - 2
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,
 });
 

+ 13 - 14
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<Props, State> {
     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<Props, State> {
   };
 
   render() {
-    const { navModel } = this.props;
-    const { rules, search, stateFilter } = this.state;
+    const { navModel, alertRules } = this.props;
+    const { search, stateFilter } = this.state;
 
     return (
       <div>
@@ -117,7 +114,7 @@ export class AlertRuleList extends PureComponent<Props, State> {
 
           <section>
             <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>
           </section>
         </div>
@@ -201,11 +198,13 @@ export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
 }
 
 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));

+ 26 - 0
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<Action>): Promise<AlertRule[]> => {
+  try {
+    const rules = await getBackendSrv().get('/api/alerts', {});
+    dispatch(loadAlertRules(rules));
+    return rules;
+  } catch (error) {
+    console.error(error);
+    throw error;
+  }
+};

+ 0 - 52
public/app/features/alerting/state/apis.ts

@@ -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 - 0
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,
+};

+ 3 - 1
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;

+ 33 - 0
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[];
 }