Create EndpointTabs SFC and fix actions and reducers for adding and removing new endpoints

pull/2252/head
deniz kusefoglu 2017-11-07 16:25:29 -08:00
parent 3487055fd0
commit 3d859a095f
5 changed files with 162 additions and 120 deletions

View File

@ -163,16 +163,22 @@ export function updateAlerts(ruleID, alerts) {
}
}
export function updateAlertNodes(ruleID, alertNodeName, alertNodesText) {
export function updateAlertNodes(ruleID, alerts) {
return {
type: 'UPDATE_RULE_ALERT_NODES',
payload: {
ruleID,
alertNodeName,
alertNodesText,
},
payload: {ruleID, alerts},
}
}
// export function updateAlertNodes(ruleID, alertNodeName, alertNodesText) {
// return {
// type: 'UPDATE_RULE_ALERT_NODES',
// payload: {
// ruleID,
// alertNodeName,
// alertNodesText,
// },
// }
// }
export function updateRuleName(ruleID, name) {
return {

View File

@ -0,0 +1,46 @@
import React, {PropTypes} from 'react'
import _ from 'lodash'
import classnames from 'classnames'
import uuid from 'node-uuid'
import {RULE_ALERT_OPTIONS} from 'src/kapacitor/constants'
const EndpointTabs = ({
endpointsOnThisAlert,
selectedEndpoint,
handleChooseAlert,
handleRemoveEndpoint,
}) => {
return endpointsOnThisAlert.length
? <ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite">
{endpointsOnThisAlert
.filter(alert => _.get(RULE_ALERT_OPTIONS, alert.type, false))
.map(alert =>
<li
key={uuid.v4()}
className={classnames({
active:
alert.alias === (selectedEndpoint && selectedEndpoint.alias),
})}
onClick={handleChooseAlert(alert)}
>
{alert.alias}
<div
className="nav-tab--delete"
onClick={handleRemoveEndpoint(alert)}
/>
</li>
)}
</ul>
: null
}
const {shape, func, array} = PropTypes
EndpointTabs.propTypes = {
endpointsOnThisAlert: array,
selectedEndpoint: shape({}),
handleChooseAlert: func.isRequired,
handleRemoveEndpoint: func.isRequired,
}
export default EndpointTabs

View File

@ -1,14 +1,13 @@
import React, {Component, PropTypes} from 'react'
import _ from 'lodash'
import classnames from 'classnames'
import uuid from 'node-uuid'
import RuleMessageOptions from 'src/kapacitor/components/RuleMessageOptions'
import RuleMessageText from 'src/kapacitor/components/RuleMessageText'
import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates'
import EndpointTabs from 'src/kapacitor/components/EndpointTabs'
import Dropdown from 'shared/components/Dropdown'
import {DEFAULT_ALERTS, RULE_ALERT_OPTIONS} from 'src/kapacitor/constants'
import {DEFAULT_ALERTS} from 'src/kapacitor/constants'
const alertNodesToEndpoints = rule => {
const endpointsOfKind = {}
@ -17,9 +16,12 @@ const alertNodesToEndpoints = rule => {
const count = _.get(endpointsOfKind, ep.name, 0) + 1
endpointsOfKind[ep.name] = count
endpointsOnThisAlert.push({
text: ep.name + count,
kind: ep.name,
alias: ep.name + count,
type: ep.name,
text: ep.name,
ruleID: rule.id,
args: ep.args,
properties: ep.properties,
})
})
const selectedEndpoint = endpointsOnThisAlert.length
@ -50,61 +52,74 @@ class RuleMessage extends Component {
}
handleChooseAlert = item => () => {
const {actions} = this.props
actions.updateAlerts(item.ruleID, [item.text])
actions.updateAlertNodes(item.ruleID, item.text, '')
this.setState({selectedEndpoint: item})
}
handleAddEndpoint = selectedItem => {
const {endpointsOnThisAlert, endpointsOfKind} = this.state
const newItemNumbering = _.get(endpointsOfKind, selectedItem.text, 0) + 1
const newItemName = selectedItem.text + newItemNumbering
const newItemNumbering = _.get(endpointsOfKind, selectedItem.alias, 0) + 1
const newItemName = selectedItem.alias + newItemNumbering
const newEndpoint = {
text: newItemName,
kind: selectedItem.text,
alias: newItemName,
type: selectedItem.alias,
ruleID: selectedItem.ruleID,
}
this.setState({
endpointsOnThisAlert: [...endpointsOnThisAlert, newEndpoint],
endpointsOfKind: {
...endpointsOfKind,
[selectedItem.text]: newItemNumbering,
this.setState(
{
endpointsOnThisAlert: [...endpointsOnThisAlert, newEndpoint],
endpointsOfKind: {
...endpointsOfKind,
[selectedItem.alias]: newItemNumbering,
},
selectedEndpoint: newEndpoint,
},
selectedEndpoint: newEndpoint,
})
this.handleUpdateAllAlerts
)
}
handleRemoveEndpoint = alert => e => {
e.stopPropagation()
const {endpointsOnThisAlert, selectedEndpoint} = this.state
const removedIndex = _.findIndex(endpointsOnThisAlert, ['text', alert.text])
const remainingEndpoints = _.reject(endpointsOnThisAlert, [
'text',
alert.text,
const removedIndex = _.findIndex(endpointsOnThisAlert, [
'alias',
alert.alias,
])
if (selectedEndpoint.text === alert.text) {
const remainingEndpoints = _.reject(endpointsOnThisAlert, [
'alias',
alert.alias,
])
if (selectedEndpoint.alias === alert.alias) {
const selectedIndex = removedIndex > 0 ? removedIndex - 1 : 0
const newSelected = remainingEndpoints.length
? remainingEndpoints[selectedIndex]
: null
this.setState({selectedEndpoint: newSelected})
}
this.setState({
endpointsOnThisAlert: remainingEndpoints,
})
this.setState(
{
endpointsOnThisAlert: remainingEndpoints,
},
this.handleUpdateAllAlerts
)
}
handleUpdateAllAlerts = () => {
const {rule, actions} = this.props
const {endpointsOnThisAlert} = this.state
actions.updateAlertNodes(rule.id, endpointsOnThisAlert)
actions.updateAlerts(rule.id, endpointsOnThisAlert)
}
render() {
const {rule, actions, enabledAlerts} = this.props
const {endpointsOnThisAlert, selectedEndpoint} = this.state
const defaultAlertEndpoints = DEFAULT_ALERTS.map(text => {
return {text, kind: text, ruleID: rule.id}
const defaultAlertEndpoints = DEFAULT_ALERTS.map(alias => {
return {alias, text: alias, type: alias, ruleID: rule.id}
})
const alerts = [
...defaultAlertEndpoints,
...enabledAlerts.map(text => {
return {text, kind: text, ruleID: rule.id}
...enabledAlerts.map(alias => {
return {text: alias, type: alias, ruleID: rule.id}
}),
]
return (
@ -113,31 +128,12 @@ class RuleMessage extends Component {
<div className="rule-section--body">
<div className="rule-section--row rule-section--row-first rule-section--border-bottom">
<p>Send this Alert to:</p>
{endpointsOnThisAlert.length
? <ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite">
{endpointsOnThisAlert
.filter(alert =>
_.get(RULE_ALERT_OPTIONS, alert.kind, false)
)
.map(alert =>
<li
key={uuid.v4()}
className={classnames({
active:
alert.text ===
(selectedEndpoint && selectedEndpoint.text),
})}
onClick={this.handleChooseAlert(alert)}
>
{alert.text}
<div
className="nav-tab--delete"
onClick={this.handleRemoveEndpoint(alert)}
/>
</li>
)}
</ul>
: null}
<EndpointTabs
endpointsOnThisAlert={endpointsOnThisAlert}
selectedEndpoint={selectedEndpoint}
handleChooseAlert={this.handleChooseAlert}
handleRemoveEndpoint={this.handleRemoveEndpoint}
/>
<Dropdown
items={alerts}
menuClass="dropdown-malachite"
@ -151,9 +147,12 @@ class RuleMessage extends Component {
<RuleMessageOptions
rule={rule}
alertNode={selectedEndpoint}
selectedEndpoint={selectedEndpoint}
updateAlertNodes={actions.updateAlertNodes}
updateDetails={actions.updateDetails}
updateAlertProperty={actions.updateAlertProperty}
handleEditAlert={this.handleEditAlert}
handleUpdateArg={this.handleUpdateArg}
/>
<RuleMessageText
rule={rule}

View File

@ -1,9 +1,6 @@
import React, {Component, PropTypes} from 'react'
import {
RULE_ALERT_OPTIONS,
ALERT_NODES_ACCESSORS,
} from 'src/kapacitor/constants'
import {RULE_ALERT_OPTIONS} from 'src/kapacitor/constants'
class RuleMessageOptions extends Component {
constructor(props) {
@ -31,8 +28,8 @@ class RuleMessageOptions extends Component {
}
handleUpdateAlertNodes = e => {
const {updateAlertNodes, alertNode, rule} = this.props
updateAlertNodes(rule.id, alertNode, e.target.value)
const {handleUpdateArg, selectedEndpoint} = this.props
handleUpdateArg(selectedEndpoint, e.target.value)
}
handleUpdateAlertProperty = propertyName => e => {
@ -44,8 +41,10 @@ class RuleMessageOptions extends Component {
}
render() {
const {rule, alertNode} = this.props
const {args, details, properties} = RULE_ALERT_OPTIONS[alertNode.kind]
const {rule, selectedEndpoint, handleEditAlert} = this.props
const {args, details, properties} = RULE_ALERT_OPTIONS[
selectedEndpoint.type
]
return (
<div>
@ -61,7 +60,7 @@ class RuleMessageOptions extends Component {
type="text"
placeholder={args.placeholder}
onChange={this.handleUpdateAlertNodes}
value={ALERT_NODES_ACCESSORS[alertNode.kind](rule)}
value={selectedEndpoint.args}
autoComplete="off"
spellCheck="false"
/>
@ -116,7 +115,7 @@ const {func, shape} = PropTypes
RuleMessageOptions.propTypes = {
rule: shape({}).isRequired,
alertNode: shape({}),
selectedEndpoint: shape({}),
updateAlertNodes: func.isRequired,
updateDetails: func.isRequired,
updateAlertProperty: func.isRequired,

View File

@ -76,65 +76,57 @@ export default function rules(state = {}, action) {
case 'UPDATE_RULE_ALERTS': {
const {ruleID, alerts} = action.payload
const culledalerts = alerts.map(a => a.type)
return Object.assign({}, state, {
[ruleID]: Object.assign({}, state[ruleID], {
alerts,
alerts: culledalerts,
}),
})
}
case 'UPDATE_RULE_ALERT_NODES': {
const {ruleID, alertNodeName, alertNodesText} = action.payload
let alertNodesByType
switch (alertNodeName) {
case 'http':
case 'tcp':
case 'log':
alertNodesByType = [
{
name: alertNodeName,
args: [alertNodesText],
const {ruleID, alerts} = action.payload
const alertNodesByType = alerts.map(alert => {
const {type, alias} = alert
switch (type) {
case 'http':
case 'tcp':
case 'log':
return {
name: type,
args: [alias],
properties: [],
},
]
break
case 'exec':
case 'smtp':
alertNodesByType = [
{
name: alertNodeName,
args: alertNodesText.split(' '),
properties: [],
},
]
break
case 'alerta':
alertNodesByType = [
{
name: alertNodeName,
}
case 'exec':
case 'smtp':
return [
{
name: type,
args: alias.split(' '),
properties: [],
},
]
case 'alerta':
return {
name: type,
args: [],
properties: parseAlerta(alertNodesText),
},
]
break
case 'hipchat':
case 'opsgenie':
case 'pagerduty':
case 'slack':
case 'telegram':
case 'victorops':
case 'pushover':
default:
alertNodesByType = [
{
name: alertNodeName,
properties: parseAlerta(alias),
}
case 'hipchat':
case 'opsgenie':
case 'pagerduty':
case 'slack':
case 'telegram':
case 'victorops':
case 'pushover':
default:
return {
name: type,
args: [],
properties: [],
},
]
}
}
}
})
return Object.assign({}, state, {
[ruleID]: Object.assign({}, state[ruleID], {
alertNodes: alertNodesByType,