From 20b5c96e29078f3495b8e93d4390f4b677c7d120 Mon Sep 17 00:00:00 2001 From: Will Piers Date: Fri, 4 Nov 2016 16:39:19 -0700 Subject: [PATCH] Refactor KapacitorRulePage to work for new and existing rules, and add new rule button --- ui/src/chronograf/reducers/queryConfigs.js | 4 +- ui/src/index.js | 1 + ui/src/kapacitor/actions/view/index.js | 59 +++++++++++------ ui/src/kapacitor/apis/index.js | 15 +++++ ui/src/kapacitor/constants/index.js | 2 + .../kapacitor/containers/KapacitorRulePage.js | 63 ++++++++++++------- .../containers/KapacitorRulesPage.js | 52 ++++++++------- ui/src/kapacitor/reducers/rules.js | 19 ++++-- ui/src/sources/containers/ManageSources.js | 9 ++- 9 files changed, 150 insertions(+), 74 deletions(-) diff --git a/ui/src/chronograf/reducers/queryConfigs.js b/ui/src/chronograf/reducers/queryConfigs.js index 52bd40bb7c..82fe56c7c1 100644 --- a/ui/src/chronograf/reducers/queryConfigs.js +++ b/ui/src/chronograf/reducers/queryConfigs.js @@ -37,9 +37,9 @@ export default function queryConfigs(state = {}, action) { } case 'LOAD_KAPACITOR_QUERY': { - const {queryID, query} = action.payload; + const {query} = action.payload; const nextState = Object.assign({}, state, { - [queryID]: query, + [query.id]: query, }); return nextState; diff --git a/ui/src/index.js b/ui/src/index.js index fd1ba732fa..12dd3359ab 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -119,6 +119,7 @@ const Root = React.createClass({ + diff --git a/ui/src/kapacitor/actions/view/index.js b/ui/src/kapacitor/actions/view/index.js index fc62d4652d..df3135d344 100644 --- a/ui/src/kapacitor/actions/view/index.js +++ b/ui/src/kapacitor/actions/view/index.js @@ -1,14 +1,38 @@ import uuid from 'node-uuid'; +import {getRules, getRule} from 'src/kapacitor/apis'; +import {getKapacitor} from 'src/shared/apis'; -export function fetchRule() { // ruleID +export function fetchRule(source, ruleID) { + return (dispatch) => { + getKapacitor(source).then((kapacitor) => { + getRule(kapacitor, ruleID).then(({data: rule}) => { + dispatch({ + type: 'LOAD_RULE', + payload: { + rule: Object.assign(rule, {queryID: rule.query.id}), + }, + }); + + dispatch({ + type: 'LOAD_KAPACITOR_QUERY', + payload: { + query: rule.query, + }, + }); + }); + }); + }; +} + +export function loadDefaultRule() { return (dispatch) => { - // do some ajax to get the rule. put it in the payload const queryID = uuid.v4(); dispatch({ - type: 'LOAD_RULE', - payload: {}, + type: 'LOAD_DEFAULT_RULE', + payload: { + queryID, + }, }); - dispatch({ type: 'ADD_KAPACITOR_QUERY', payload: { @@ -18,22 +42,17 @@ export function fetchRule() { // ruleID }; } -export function loadDefaultRule() { +export function fetchRules(source) { return (dispatch) => { - const queryID = uuid.v4(); - const ruleID = uuid.v4(); - dispatch({ - type: 'LOAD_DEFAULT_RULE', - payload: { - queryID, - ruleID, - }, - }); - dispatch({ - type: 'ADD_KAPACITOR_QUERY', - payload: { - queryId: queryID, - }, + getKapacitor(source).then((kapacitor) => { + getRules(kapacitor).then(({data: {rules}}) => { + dispatch({ + type: 'LOAD_RULES', + payload: { + rules, + }, + }); + }); }); }; } diff --git a/ui/src/kapacitor/apis/index.js b/ui/src/kapacitor/apis/index.js index 3b68e95c35..5a9c7ebd23 100644 --- a/ui/src/kapacitor/apis/index.js +++ b/ui/src/kapacitor/apis/index.js @@ -14,3 +14,18 @@ export function getRules(kapacitor) { url: kapacitor.links.rules, }); } + +export function getRule(kapacitor, ruleID) { + return AJAX({ + method: 'GET', + url: `${kapacitor.links.rules}/${ruleID}`, + }); +} + +export function editRule(rule) { + return AJAX({ + method: 'PUT', + url: rule.links.self, + data: rule, + }); +} diff --git a/ui/src/kapacitor/constants/index.js b/ui/src/kapacitor/constants/index.js index b32ec9b34f..f93d7483db 100644 --- a/ui/src/kapacitor/constants/index.js +++ b/ui/src/kapacitor/constants/index.js @@ -24,3 +24,5 @@ export const PERIODS = ['1m', '5m', '10m', '30m', '1h', '2h', '1d']; export const CHANGES = ['change', '% change']; export const SHIFTS = ['1m', '5m', '10m', '30m', '1h', '2h', '1d']; export const ALERTS = ['hipchat', 'opsgenie', 'pagerduty', 'sensu', 'slack', 'smtp', 'talk', 'telegram', 'victorops']; + +export const DEFAULT_RULE_ID = 'DEFAULT_RULE_ID'; diff --git a/ui/src/kapacitor/containers/KapacitorRulePage.js b/ui/src/kapacitor/containers/KapacitorRulePage.js index 07ca5d9495..d15fd480cd 100644 --- a/ui/src/kapacitor/containers/KapacitorRulePage.js +++ b/ui/src/kapacitor/containers/KapacitorRulePage.js @@ -1,4 +1,5 @@ import React, {PropTypes} from 'react'; +import {withRouter} from 'react-router'; import {connect} from 'react-redux'; import _ from 'lodash'; import DataSection from '../components/DataSection'; @@ -12,8 +13,8 @@ import LineGraph from 'shared/components/LineGraph'; const RefreshingLineGraph = AutoRefresh(LineGraph); import {getKapacitor, getKapacitorConfig} from 'shared/apis/index'; import Dropdown from 'shared/components/Dropdown'; -import {ALERTS} from 'src/kapacitor/constants'; -import {createRule} from 'src/kapacitor/apis'; +import {ALERTS, DEFAULT_RULE_ID} from 'src/kapacitor/constants'; +import {createRule, editRule} from 'src/kapacitor/apis'; export const KapacitorRulePage = React.createClass({ propTypes: { @@ -49,10 +50,15 @@ export const KapacitorRulePage = React.createClass({ }; }, + isEditing() { + const {params} = this.props; + return params.ruleID && params.ruleID !== 'new'; + }, + componentDidMount() { - const {ruleID} = false; // this.props.params; - if (ruleID) { - this.props.kapacitorActions.fetchRule(ruleID); + const {ruleID} = this.props.params; + if (this.isEditing()) { + this.props.kapacitorActions.fetchRule(this.props.source, ruleID); } else { this.props.kapacitorActions.loadDefaultRule(); } @@ -64,25 +70,34 @@ export const KapacitorRulePage = React.createClass({ }); this.setState({kapacitor, enabledAlerts}); }).catch(() => { - this.props.addFlashMessage({type: 'failure', message: `There was a problem communicating with Kapacitor`}); + this.props.addFlashMessage({type: 'failure', text: `There was a problem communicating with Kapacitor`}); }).catch(() => { - this.props.addFlashMessage({type: 'failure', message: `We couldn't find a configured Kapacitor for this source`}); + this.props.addFlashMessage({type: 'failure', text: `We couldn't find a configured Kapacitor for this source`}); }); }); }, handleSave() { - const {queryConfigs, rules} = this.props; - const rule = rules[Object.keys(rules)[0]]; // this.props.params.taskID - const newRule = Object.assign({}, rule, { - query: queryConfigs[rule.queryID], - }); - delete newRule.queryID; - createRule(this.state.kapacitor, newRule).then(() => { - // maybe update the default rule in redux state.. and update the URL - }).catch(() => { - this.props.addFlashMessage({type: 'failure', message: `There was a problem creating the rule`}); - }); + const {queryConfigs, rules, params, source} = this.props; + if (this.isEditing()) { // If we are editing updated rule if not, create a new one + editRule(rules[params.ruleID]).then(() => { + this.props.addFlashMessage({type: 'success', text: `Rule successfully updated!`}); + }).catch(() => { + this.props.addFlashMessage({type: 'failure', text: `There was a problem updating the rule`}); + }); + } else { + const rule = rules[DEFAULT_RULE_ID]; + const newRule = Object.assign({}, rule, { + query: queryConfigs[rule.queryID], + }); + delete newRule.queryID; + createRule(this.state.kapacitor, newRule).then(() => { + this.props.router.push(`sources/${source.id}/alert-rules`); + this.props.addFlashMessage({type: 'success', text: `Rule successfully created`}); + }).catch(() => { + this.props.addFlashMessage({type: 'failure', text: `There was a problem creating the rule`}); + }); + } }, handleChooseAlert(item) { @@ -132,13 +147,13 @@ export const KapacitorRulePage = React.createClass({ }, render() { - const {rules, queryConfigs, source} = this.props; - const rule = rules[Object.keys(rules)[0]]; // this.props.params.ruleID + const {rules, queryConfigs, source, params} = this.props; + const rule = this.isEditing() ? rules[params.ruleID] : rules[DEFAULT_RULE_ID]; const query = rule && queryConfigs[rule.queryID]; const autoRefreshMs = 30000; - if (!query) { // or somethin like that - return null; // or a spinner or somethin + if (!query) { + return
; } const queryText = selectStatement({lower: 'now() - 15m'}, query); @@ -218,7 +233,7 @@ export const KapacitorRulePage = React.createClass({ return (

Message

-