mirror of https://github.com/grafana/grafana.git
				
				
				
			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 location from './location'; | ||||
| import { locationReducer as location } from './location'; | ||||
| 
 | ||||
| export default { | ||||
|   navIndex, | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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,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, | ||||
| }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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)); | ||||
|  |  | |||
|  | @ -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; | ||||
|   } | ||||
| }; | ||||
|  | @ -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 { 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; | ||||
|  |  | |||
|  | @ -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[]; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue