Refactor parseAlerta spec to test reducer, accessors, and parser separately. Refactor parseAlerta out of rules reducer into its own file in shared/prasing. Update appearance of AlertaConfig. Update appearance of RuleMessage input field. Remove smtp and alerta from default alerts.

pull/864/head
Hunter Trujillo 2017-02-10 13:03:31 -07:00
parent e9d8b77a96
commit d428aaf8c7
7 changed files with 128 additions and 108 deletions

View File

@ -110,58 +110,15 @@ describe('Kapacitor.Reducers.rules', () => {
`;
let newState = reducer(initialState, updateAlertNodes(ruleID, 'alerta', tickScript));
const expectedObj = [
{
"name": "alerta",
"args": [],
"properties": [
{
"name": "resource",
"args": [
"Hostname or service"
]
},
{
"name": "event",
"args": [
"Something went wrong"
]
},
{
"name": "environment",
"args": [
"Development"
]
},
{
"name": "group",
"args": [
"Dev. Servers"
]
},
{
"name": "services",
"args": [
"a",
"b",
"c"
]
}
]
}
];
const expectedStr = `alerta().resource('Hostname or service').event('Something went wrong').environment('Development').group('Dev. Servers').services('a b c')`;
let actualStr = ALERT_NODES_ACCESSORS.alerta(newState[ruleID]);
// Test both data structure and accessor string
expect(newState[ruleID].alertNodes).to.deep.equal(expectedObj);
expect(actualStr).to.equal(expectedStr);
// Test that accessor string is the same if fed back in
newState = reducer(newState, updateAlertNodes(ruleID, 'alerta', actualStr));
actualStr = ALERT_NODES_ACCESSORS.alerta(newState[ruleID]);
expect(newState[ruleID].alertNodes).to.deep.equal(expectedObj);
expect(actualStr).to.equal(expectedStr);
});

View File

@ -0,0 +1,58 @@
import {parseAlerta} from 'src/shared/parsing/parseAlerta';
it('can parse an alerta tick script', () => {
const tickScript = `stream
|alert()
.alerta()
.resource('Hostname or service')
.event('Something went wrong')
.environment('Development')
.group('Dev. Servers')
.services('a b c')
`;
let actualObj = parseAlerta(tickScript);
const expectedObj = [
{
"name": "resource",
"args": [
"Hostname or service"
]
},
{
"name": "event",
"args": [
"Something went wrong"
]
},
{
"name": "environment",
"args": [
"Development"
]
},
{
"name": "group",
"args": [
"Dev. Servers"
]
},
{
"name": "services",
"args": [
"a",
"b",
"c"
]
}
];
// Test data structure
expect(actualObj).to.deep.equal(expectedObj);
// Test that data structure is the same if fed back in
const expectedStr = `alerta().resource('Hostname or service').event('Something went wrong').environment('Development').group('Dev. Servers').services('a b c')`;
actualObj = parseAlerta(expectedStr);
expect(actualObj).to.deep.equal(expectedObj);
});

View File

@ -30,44 +30,37 @@ const AlertaConfig = React.createClass({
const {environment, origin, token, url} = this.props.config.options;
return (
<div className="col-xs-12 col-sm-8 col-sm-offset-2">
<div className="col-xs-12">
<h4 className="text-center">Alerta Alert</h4>
<br/>
<form onSubmit={this.handleSaveAlert}>
<div className="row">
<div className="col-xs-7 col-sm-8 col-sm-offset-2">
<p>
Have alerts sent to Alerta
</p>
<p>
Have alerts sent to Alerta
</p>
<div className="form-group">
<label htmlFor="environment">Environment</label>
<input className="form-control" id="environment" type="text" ref={(r) => this.environment = r} defaultValue={environment || ''}></input>
</div>
<div className="form-group">
<label htmlFor="origin">Origin</label>
<input className="form-control" id="origin" type="text" ref={(r) => this.origin = r} defaultValue={origin || ''}></input>
</div>
<div className="form-group">
<label htmlFor="token">Token</label>
<input className="form-control" id="token" type="text" ref={(r) => this.token = r} defaultValue={token || ''}></input>
<span>Note: a value of <code>true</code> indicates the Alerta Token has been set</span>
</div>
<div className="form-group">
<label htmlFor="url">User</label>
<input className="form-control" id="url" type="text" ref={(r) => this.url = r} defaultValue={url || ''}></input>
</div>
</div>
<div className="form-group col-xs-12">
<label htmlFor="environment">Environment</label>
<input className="form-control" id="environment" type="text" ref={(r) => this.environment = r} defaultValue={environment || ''}></input>
</div>
<hr />
<div className="row">
<div className="form-group col-xs-5 col-sm-3 col-sm-offset-2">
<button className="btn btn-block btn-primary" type="submit">Save</button>
</div>
<div className="form-group col-xs-12">
<label htmlFor="origin">Origin</label>
<input className="form-control" id="origin" type="text" ref={(r) => this.origin = r} defaultValue={origin || ''}></input>
</div>
<div className="form-group col-xs-12">
<label htmlFor="token">Token</label>
<input className="form-control" id="token" type="text" ref={(r) => this.token = r} defaultValue={token || ''}></input>
<span>Note: a value of <code>true</code> indicates the Alerta Token has been set</span>
</div>
<div className="form-group col-xs-12">
<label htmlFor="url">User</label>
<input className="form-control" id="url" type="text" ref={(r) => this.url = r} defaultValue={url || ''}></input>
</div>
<div className="form-group-submit col-xs-12 col-sm-6 col-sm-offset-3">
<button className="btn btn-block btn-primary" type="submit">Save</button>
</div>
</form>
</div>

View File

@ -94,8 +94,10 @@ export const RuleMessage = React.createClass({
/> : null
}
<div className="rule-section--item bottom alert-message--endpoint">
<p>Send this Alert to:</p>
<Dropdown className="size-256 dropdown-kapacitor" selected={selectedAlert || 'Choose an output'} items={alerts} onChoose={this.handleChooseAlert} />
<div>
<p>Send this Alert to:</p>
<Dropdown className="dropdown-kapacitor size-136" selected={selectedAlert || 'Choose an output'} items={alerts} onChoose={this.handleChooseAlert} />
</div>
{this.renderInput(actions.updateAlertNodes, selectedAlert, rule)}
</div>
</div>
@ -104,17 +106,27 @@ export const RuleMessage = React.createClass({
},
renderInput(updateAlertNodes, alert, rule) {
if (!DEFAULT_ALERTS.find((a) => a === alert)) {
if (!Object.keys(DEFAULT_ALERT_PLACEHOLDERS).find((a) => a === alert)) {
return null;
}
return (<input
className="form-control col-xs-6"
type="text"
placeholder={DEFAULT_ALERT_PLACEHOLDERS[alert]}
ref={(r) => this.selectedAlertProperty = r}
onChange={() => updateAlertNodes(rule.id, alert, this.selectedAlertProperty.value)}
value={ALERT_NODES_ACCESSORS[alert](rule)}
/>);
return (
<form className="form-group col-xs-12" style={{marginTop: '8px'}}>
<div>
<label htmlFor="alert-input">{DEFAULT_ALERT_PLACEHOLDERS[alert]}</label>
</div>
<div>
<input
id="alert-input"
className="form-control"
type="text"
placeholder={DEFAULT_ALERT_PLACEHOLDERS[alert]}
ref={(r) => this.selectedAlertProperty = r}
onChange={() => updateAlertNodes(rule.id, alert, this.selectedAlertProperty.value)}
value={ALERT_NODES_ACCESSORS[alert](rule)}
/>
</div>
</form>
);
},
});

View File

@ -39,7 +39,7 @@ export const RULE_MESSAGE_TEMPLATES = {
time: {label: "{{.Time}}", text: "The time of the point that triggered the event"},
};
export const DEFAULT_ALERTS = ['http', 'tcp', 'exec', 'smtp', 'alerta'];
export const DEFAULT_ALERTS = ['http', 'tcp', 'exec'];
export const DEFAULT_ALERT_PLACEHOLDERS = {
http: 'URL',

View File

@ -1,25 +1,6 @@
import {defaultRuleConfigs, DEFAULT_RULE_ID} from 'src/kapacitor/constants';
import _ from 'lodash';
const alertaRegex = /(services)\('(.+?)'\)|(resource)\('(.+?)'\)|(event)\('(.+?)'\)|(environment)\('(.+?)'\)|(group)\('(.+?)'\)|(origin)\('(.+?)'\)|(token)\('(.+?)'\)/gi;
function parseAlerta(string, regex) {
const properties = [];
let match;
while (match = regex.exec(string)) { // eslint-disable-line no-cond-assign
for (let m = 1; m < match.length; m += 2) {
if (match[m]) {
properties.push({
name: match[m],
args: match[m] === 'services' ? match[m + 1].split(' ') : [match[m + 1]],
});
}
}
}
return properties;
}
import {parseAlerta} from 'src/shared/parsing/parseAlerta';
export default function rules(state = {}, action) {
switch (action.type) {
@ -125,7 +106,7 @@ export default function rules(state = {}, action) {
{
name: alertType,
args: [],
properties: parseAlerta(alertNodesText, alertaRegex),
properties: parseAlerta(alertNodesText),
},
];
break;

View File

@ -0,0 +1,19 @@
const alertaRegex = /(services)\('(.+?)'\)|(resource)\('(.+?)'\)|(event)\('(.+?)'\)|(environment)\('(.+?)'\)|(group)\('(.+?)'\)|(origin)\('(.+?)'\)|(token)\('(.+?)'\)/gi;
export function parseAlerta(string) {
const properties = [];
let match;
while (match = alertaRegex.exec(string)) { // eslint-disable-line no-cond-assign
for (let m = 1; m < match.length; m += 2) {
if (match[m]) {
properties.push({
name: match[m],
args: match[m] === 'services' ? match[m + 1].split(' ') : [match[m + 1]],
});
}
}
}
return properties;
}