Convert KapacitorRule tree to typescript
parent
93e72efb08
commit
ae1c4484be
|
@ -1,24 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const CodeData = ({onClickTemplate, template}) => (
|
|
||||||
<code
|
|
||||||
className="rule-builder--message-template"
|
|
||||||
data-tip={template.text}
|
|
||||||
onClick={onClickTemplate}
|
|
||||||
>
|
|
||||||
{template.label}
|
|
||||||
</code>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {func, shape, string} = PropTypes
|
|
||||||
|
|
||||||
CodeData.propTypes = {
|
|
||||||
onClickTemplate: func,
|
|
||||||
template: shape({
|
|
||||||
label: string,
|
|
||||||
text: string,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CodeData
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React, {SFC} from 'react'
|
||||||
|
|
||||||
|
import {RuleMessage} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onClickTemplate: () => void
|
||||||
|
template: RuleMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
const CodeData: SFC<Props> = ({onClickTemplate, template}) => (
|
||||||
|
<code
|
||||||
|
className="rule-builder--message-template"
|
||||||
|
data-tip={template.text}
|
||||||
|
onClick={onClickTemplate}
|
||||||
|
>
|
||||||
|
{template.label}
|
||||||
|
</code>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default CodeData
|
|
@ -24,7 +24,7 @@ interface Props {
|
||||||
query: QueryConfig
|
query: QueryConfig
|
||||||
isDeadman: boolean
|
isDeadman: boolean
|
||||||
isKapacitorRule: boolean
|
isKapacitorRule: boolean
|
||||||
onAddEvery: () => void
|
onAddEvery: (every?: string) => void
|
||||||
timeRange: TimeRange
|
timeRange: TimeRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,24 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {PERIODS} from 'src/kapacitor/constants'
|
import {PERIODS} from 'src/kapacitor/constants'
|
||||||
import Dropdown from 'shared/components/Dropdown'
|
import Dropdown from 'src/shared/components/Dropdown'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
const periods = PERIODS.map(text => {
|
const periods = PERIODS.map(text => {
|
||||||
return {text}
|
return {text}
|
||||||
})
|
})
|
||||||
|
|
||||||
const Deadman = ({rule, onChange}) => (
|
interface Item {
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
onChange: (item: Item) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Deadman: SFC<Props> = ({rule, onChange}) => (
|
||||||
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
||||||
<p>Send Alert if Data is missing for</p>
|
<p>Send Alert if Data is missing for</p>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
@ -20,15 +31,4 @@ const Deadman = ({rule, onChange}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
Deadman.propTypes = {
|
|
||||||
rule: shape({
|
|
||||||
values: shape({
|
|
||||||
period: string,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
onChange: func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Deadman
|
export default Deadman
|
|
@ -1,20 +1,20 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
|
import {InjectedRouter} from 'react-router'
|
||||||
|
|
||||||
import NameSection from 'src/kapacitor/components/NameSection'
|
import NameSection from 'src/kapacitor/components/NameSection'
|
||||||
import ValuesSection from 'src/kapacitor/components/ValuesSection'
|
import ValuesSection from 'src/kapacitor/components/ValuesSection'
|
||||||
import RuleHeader from 'src/kapacitor/components/RuleHeader'
|
import RuleHeader from 'src/kapacitor/components/RuleHeader'
|
||||||
import RuleHandlers from 'src/kapacitor/components/RuleHandlers'
|
import RuleHandlers from 'src/kapacitor/components/RuleHandlers'
|
||||||
import RuleMessage from 'src/kapacitor/components/RuleMessage'
|
import RuleMessage from 'src/kapacitor/components/RuleMessage'
|
||||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
|
|
||||||
import {createRule, editRule} from 'src/kapacitor/apis'
|
import {createRule, editRule} from 'src/kapacitor/apis'
|
||||||
import buildInfluxQLQuery from 'utils/influxql'
|
import buildInfluxQLQuery from 'src/utils/influxql'
|
||||||
import {timeRanges} from 'shared/data/timeRanges'
|
import {timeRanges} from 'src/shared/data/timeRanges'
|
||||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||||
import {notify as notifyAction} from 'shared/actions/notifications'
|
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
notifyAlertRuleCreated,
|
notifyAlertRuleCreated,
|
||||||
|
@ -24,11 +24,52 @@ import {
|
||||||
notifyAlertRuleRequiresQuery,
|
notifyAlertRuleRequiresQuery,
|
||||||
notifyAlertRuleRequiresConditionValue,
|
notifyAlertRuleRequiresConditionValue,
|
||||||
notifyAlertRuleDeadmanInvalid,
|
notifyAlertRuleDeadmanInvalid,
|
||||||
} from 'shared/copy/notifications'
|
} from 'src/shared/copy/notifications'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Source,
|
||||||
|
AlertRule,
|
||||||
|
Notification,
|
||||||
|
Kapacitor,
|
||||||
|
QueryConfig,
|
||||||
|
TimeRange,
|
||||||
|
} from 'src/types'
|
||||||
|
import {Handler} from 'src/types/kapacitor'
|
||||||
|
import {
|
||||||
|
KapacitorQueryConfigActions,
|
||||||
|
KapacitorRuleActions,
|
||||||
|
} from 'src/types/actions'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
source: Source
|
||||||
|
rule: AlertRule
|
||||||
|
query: QueryConfig
|
||||||
|
queryConfigs: QueryConfig[]
|
||||||
|
queryConfigActions: KapacitorQueryConfigActions
|
||||||
|
ruleActions: KapacitorRuleActions
|
||||||
|
notify: (message: Notification) => void
|
||||||
|
ruleID: string
|
||||||
|
handlersFromConfig: Handler[]
|
||||||
|
router: InjectedRouter
|
||||||
|
kapacitor: Kapacitor
|
||||||
|
configLink: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeItem extends Item {
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
timeRange: TimeRange
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class KapacitorRule extends Component {
|
class KapacitorRule extends Component<Props, State> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -36,137 +77,7 @@ class KapacitorRule extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChooseTimeRange = ({lower}) => {
|
public render() {
|
||||||
const timeRange = timeRanges.find(range => range.lower === lower)
|
|
||||||
this.setState({timeRange})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreate = pathname => {
|
|
||||||
const {notify, queryConfigs, rule, source, router, kapacitor} = this.props
|
|
||||||
|
|
||||||
const newRule = Object.assign({}, rule, {
|
|
||||||
query: queryConfigs[rule.queryID],
|
|
||||||
})
|
|
||||||
delete newRule.queryID
|
|
||||||
|
|
||||||
createRule(kapacitor, newRule)
|
|
||||||
.then(() => {
|
|
||||||
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
|
||||||
notify(notifyAlertRuleCreated(newRule.name))
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
notify(notifyAlertRuleCreateFailed(newRule.name, e.data.message))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEdit = pathname => {
|
|
||||||
const {notify, queryConfigs, rule, router, source} = this.props
|
|
||||||
const updatedRule = Object.assign({}, rule, {
|
|
||||||
query: queryConfigs[rule.queryID],
|
|
||||||
})
|
|
||||||
|
|
||||||
editRule(updatedRule)
|
|
||||||
.then(() => {
|
|
||||||
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
|
||||||
notify(notifyAlertRuleUpdated(rule.name))
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
notify(notifyAlertRuleUpdateFailed(rule.name, e.data.message))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSave = () => {
|
|
||||||
const {rule} = this.props
|
|
||||||
if (rule.id === DEFAULT_RULE_ID) {
|
|
||||||
this.handleCreate()
|
|
||||||
} else {
|
|
||||||
this.handleEdit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSaveToConfig = configName => () => {
|
|
||||||
const {rule, configLink, router} = this.props
|
|
||||||
const pathname = `${configLink}#${configName}`
|
|
||||||
if (this.validationError()) {
|
|
||||||
router.push({
|
|
||||||
pathname,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (rule.id === DEFAULT_RULE_ID) {
|
|
||||||
this.handleCreate(pathname)
|
|
||||||
} else {
|
|
||||||
this.handleEdit(pathname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAddEvery = frequency => {
|
|
||||||
const {
|
|
||||||
rule: {id: ruleID},
|
|
||||||
ruleActions: {addEvery},
|
|
||||||
} = this.props
|
|
||||||
addEvery(ruleID, frequency)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRemoveEvery = () => {
|
|
||||||
const {
|
|
||||||
rule: {id: ruleID},
|
|
||||||
ruleActions: {removeEvery},
|
|
||||||
} = this.props
|
|
||||||
removeEvery(ruleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
validationError = () => {
|
|
||||||
const {rule, query} = this.props
|
|
||||||
if (rule.trigger === 'deadman') {
|
|
||||||
return this.deadmanValidation()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!buildInfluxQLQuery({}, query)) {
|
|
||||||
return notifyAlertRuleRequiresQuery()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rule.values.value) {
|
|
||||||
return notifyAlertRuleRequiresConditionValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
deadmanValidation = () => {
|
|
||||||
const {query} = this.props
|
|
||||||
if (query && (!query.database || !query.measurement)) {
|
|
||||||
return notifyAlertRuleDeadmanInvalid()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRuleTypeDropdownChange = ({type, text}) => {
|
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
|
||||||
...this.props.rule.values,
|
|
||||||
[type]: text,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRuleTypeInputChange = e => {
|
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
const {lower, upper} = e.target.form
|
|
||||||
|
|
||||||
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
|
||||||
...this.props.rule.values,
|
|
||||||
value: lower.value,
|
|
||||||
rangeValue: upper ? upper.value : '',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDeadmanChange = ({text}) => {
|
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
ruleActions.updateRuleValues(rule.id, rule.trigger, {period: text})
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
const {
|
||||||
rule,
|
rule,
|
||||||
source,
|
source,
|
||||||
|
@ -183,7 +94,7 @@ class KapacitorRule extends Component {
|
||||||
<RuleHeader
|
<RuleHeader
|
||||||
source={source}
|
source={source}
|
||||||
onSave={this.handleSave}
|
onSave={this.handleSave}
|
||||||
validationError={this.validationError()}
|
validationError={this.validationError}
|
||||||
/>
|
/>
|
||||||
<FancyScrollbar className="page-contents fancy-scroll--kapacitor">
|
<FancyScrollbar className="page-contents fancy-scroll--kapacitor">
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
|
@ -215,7 +126,7 @@ class KapacitorRule extends Component {
|
||||||
ruleActions={ruleActions}
|
ruleActions={ruleActions}
|
||||||
handlersFromConfig={handlersFromConfig}
|
handlersFromConfig={handlersFromConfig}
|
||||||
onGoToConfig={this.handleSaveToConfig}
|
onGoToConfig={this.handleSaveToConfig}
|
||||||
validationError={this.validationError()}
|
validationError={this.validationError}
|
||||||
/>
|
/>
|
||||||
<RuleMessage rule={rule} ruleActions={ruleActions} />
|
<RuleMessage rule={rule} ruleActions={ruleActions} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -226,27 +137,138 @@ class KapacitorRule extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {arrayOf, func, shape, string} = PropTypes
|
private handleChooseTimeRange = ({lower}: TimeRange) => {
|
||||||
|
const timeRange = timeRanges.find(range => range.lower === lower)
|
||||||
|
this.setState({timeRange})
|
||||||
|
}
|
||||||
|
|
||||||
KapacitorRule.propTypes = {
|
private handleCreate = (pathname?: string) => {
|
||||||
source: shape({}).isRequired,
|
const {notify, queryConfigs, rule, source, router, kapacitor} = this.props
|
||||||
rule: shape({
|
|
||||||
values: shape({}),
|
const newRule = Object.assign({}, rule, {
|
||||||
}).isRequired,
|
query: queryConfigs[rule.queryID],
|
||||||
query: shape({}).isRequired,
|
})
|
||||||
queryConfigs: shape({}).isRequired,
|
delete newRule.queryID
|
||||||
queryConfigActions: shape({}).isRequired,
|
|
||||||
ruleActions: shape({}).isRequired,
|
createRule(kapacitor, newRule)
|
||||||
notify: func.isRequired,
|
.then(() => {
|
||||||
ruleID: string.isRequired,
|
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
||||||
handlersFromConfig: arrayOf(shape({})).isRequired,
|
notify(notifyAlertRuleCreated(newRule.name))
|
||||||
router: shape({
|
})
|
||||||
push: func.isRequired,
|
.catch(e => {
|
||||||
}).isRequired,
|
notify(notifyAlertRuleCreateFailed(newRule.name, e.data.message))
|
||||||
kapacitor: shape({}).isRequired,
|
})
|
||||||
configLink: string.isRequired,
|
}
|
||||||
|
|
||||||
|
private handleEdit = (pathname?: string) => {
|
||||||
|
const {notify, queryConfigs, rule, router, source} = this.props
|
||||||
|
const updatedRule = Object.assign({}, rule, {
|
||||||
|
query: queryConfigs[rule.queryID],
|
||||||
|
})
|
||||||
|
|
||||||
|
editRule(updatedRule)
|
||||||
|
.then(() => {
|
||||||
|
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
||||||
|
notify(notifyAlertRuleUpdated(rule.name))
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
notify(notifyAlertRuleUpdateFailed(rule.name, e.data.message))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSave = () => {
|
||||||
|
const {rule} = this.props
|
||||||
|
if (rule.id === DEFAULT_RULE_ID) {
|
||||||
|
this.handleCreate()
|
||||||
|
} else {
|
||||||
|
this.handleEdit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSaveToConfig = (configName: string) => () => {
|
||||||
|
const {rule, configLink, router} = this.props
|
||||||
|
const pathname = `${configLink}#${configName}`
|
||||||
|
|
||||||
|
if (this.validationError) {
|
||||||
|
router.push({
|
||||||
|
pathname,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.id === DEFAULT_RULE_ID) {
|
||||||
|
this.handleCreate(pathname)
|
||||||
|
} else {
|
||||||
|
this.handleEdit(pathname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleAddEvery = (frequency: string) => {
|
||||||
|
const {
|
||||||
|
rule: {id: ruleID},
|
||||||
|
ruleActions: {addEvery},
|
||||||
|
} = this.props
|
||||||
|
addEvery(ruleID, frequency)
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRemoveEvery = () => {
|
||||||
|
const {
|
||||||
|
rule: {id: ruleID},
|
||||||
|
ruleActions: {removeEvery},
|
||||||
|
} = this.props
|
||||||
|
removeEvery(ruleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get validationError(): string {
|
||||||
|
const {rule, query} = this.props
|
||||||
|
if (rule.trigger === 'deadman') {
|
||||||
|
return this.deadmanValidation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buildInfluxQLQuery({lower: ''}, query)) {
|
||||||
|
return notifyAlertRuleRequiresQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rule.values.value) {
|
||||||
|
return notifyAlertRuleRequiresConditionValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
private deadmanValidation = () => {
|
||||||
|
const {query} = this.props
|
||||||
|
if (query && (!query.database || !query.measurement)) {
|
||||||
|
return notifyAlertRuleDeadmanInvalid()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRuleTypeDropdownChange = ({type, text}: TypeItem) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
|
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
||||||
|
...this.props.rule.values,
|
||||||
|
[type]: text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRuleTypeInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
|
const {lower, upper} = e.target.form
|
||||||
|
|
||||||
|
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
||||||
|
...this.props.rule.values,
|
||||||
|
value: lower.value,
|
||||||
|
rangeValue: upper ? upper.value : '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleDeadmanChange = ({text}: Item) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
|
ruleActions.updateRuleValues(rule.id, rule.trigger, {period: text})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
|
@ -1,11 +1,25 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component, ChangeEvent, KeyboardEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
defaultName: string
|
||||||
|
onRuleRename: (id: string, name: string) => void
|
||||||
|
rule: AlertRule
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
reset: boolean
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class NameSection extends Component {
|
class NameSection extends Component<Props, State> {
|
||||||
constructor(props) {
|
private inputRef: HTMLInputElement
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -13,14 +27,22 @@ class NameSection extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInputBlur = reset => e => {
|
public handleInputBlur = (reset: boolean) => (
|
||||||
|
e: ChangeEvent<HTMLInputElement>
|
||||||
|
): void => {
|
||||||
const {defaultName, onRuleRename, rule} = this.props
|
const {defaultName, onRuleRename, rule} = this.props
|
||||||
|
|
||||||
onRuleRename(rule.id, reset ? defaultName : e.target.value)
|
let ruleName: string
|
||||||
|
if (reset) {
|
||||||
|
ruleName = defaultName
|
||||||
|
} else {
|
||||||
|
ruleName = e.target.value
|
||||||
|
}
|
||||||
|
onRuleRename(rule.id, ruleName)
|
||||||
this.setState({reset: false})
|
this.setState({reset: false})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown = e => {
|
public handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
this.inputRef.blur()
|
this.inputRef.blur()
|
||||||
}
|
}
|
||||||
|
@ -30,15 +52,13 @@ class NameSection extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
const {rule, defaultName} = this.props
|
const {defaultName} = this.props
|
||||||
const {reset} = this.state
|
const {reset} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rule-section">
|
<div className="rule-section">
|
||||||
<h3 className="rule-section--heading">
|
<h3 className="rule-section--heading">{this.header}</h3>
|
||||||
{rule.id === DEFAULT_RULE_ID ? 'Name this Alert Rule' : 'Name'}
|
|
||||||
</h3>
|
|
||||||
<div className="rule-section--body">
|
<div className="rule-section--body">
|
||||||
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
||||||
<input
|
<input
|
||||||
|
@ -55,14 +75,18 @@ class NameSection extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, string, shape} = PropTypes
|
private get header() {
|
||||||
|
const {
|
||||||
|
rule: {id},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
NameSection.propTypes = {
|
if (id === DEFAULT_RULE_ID) {
|
||||||
defaultName: string.isRequired,
|
return 'Name this Alert Rule'
|
||||||
onRuleRename: func.isRequired,
|
}
|
||||||
rule: shape({}).isRequired,
|
|
||||||
|
return 'Name'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NameSection
|
export default NameSection
|
|
@ -1,14 +1,27 @@
|
||||||
import React from 'react'
|
import React, {SFC, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {CHANGES, RELATIVE_OPERATORS, SHIFTS} from 'src/kapacitor/constants'
|
|
||||||
import Dropdown from 'shared/components/Dropdown'
|
|
||||||
|
|
||||||
const mapToItems = (arr, type) => arr.map(text => ({text, type}))
|
import {CHANGES, RELATIVE_OPERATORS, SHIFTS} from 'src/kapacitor/constants'
|
||||||
|
import Dropdown from 'src/shared/components/Dropdown'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
const mapToItems = (arr: string[], type: string) =>
|
||||||
|
arr.map(text => ({text, type}))
|
||||||
const changes = mapToItems(CHANGES, 'change')
|
const changes = mapToItems(CHANGES, 'change')
|
||||||
const shifts = mapToItems(SHIFTS, 'shift')
|
const shifts = mapToItems(SHIFTS, 'shift')
|
||||||
const operators = mapToItems(RELATIVE_OPERATORS, 'operator')
|
const operators = mapToItems(RELATIVE_OPERATORS, 'operator')
|
||||||
|
|
||||||
const Relative = ({
|
interface TypeItem {
|
||||||
|
type: string
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
interface Props {
|
||||||
|
onRuleTypeInputChange: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
onDropdownChange: (item: TypeItem) => void
|
||||||
|
rule: AlertRule
|
||||||
|
}
|
||||||
|
|
||||||
|
const Relative: SFC<Props> = ({
|
||||||
onRuleTypeInputChange,
|
onRuleTypeInputChange,
|
||||||
onDropdownChange,
|
onDropdownChange,
|
||||||
rule: {
|
rule: {
|
||||||
|
@ -46,7 +59,7 @@ const Relative = ({
|
||||||
style={{width: '160px', marginLeft: '6px'}}
|
style={{width: '160px', marginLeft: '6px'}}
|
||||||
type="text"
|
type="text"
|
||||||
name="lower"
|
name="lower"
|
||||||
spellCheck="false"
|
spellCheck={false}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onRuleTypeInputChange}
|
onChange={onRuleTypeInputChange}
|
||||||
required={true}
|
required={true}
|
||||||
|
@ -56,19 +69,4 @@ const Relative = ({
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
Relative.propTypes = {
|
|
||||||
onRuleTypeInputChange: func.isRequired,
|
|
||||||
onDropdownChange: func.isRequired,
|
|
||||||
rule: shape({
|
|
||||||
values: shape({
|
|
||||||
change: string,
|
|
||||||
shift: string,
|
|
||||||
operator: string,
|
|
||||||
value: string,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Relative
|
export default Relative
|
|
@ -26,7 +26,7 @@ interface Props {
|
||||||
rule: AlertRule
|
rule: AlertRule
|
||||||
ruleActions: RuleActions
|
ruleActions: RuleActions
|
||||||
handlersFromConfig: Handler[]
|
handlersFromConfig: Handler[]
|
||||||
onGoToConfig: () => void
|
onGoToConfig: (configName: string) => void
|
||||||
validationError: string
|
validationError: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import RuleHeaderSave from 'src/kapacitor/components/RuleHeaderSave'
|
import RuleHeaderSave from 'src/kapacitor/components/RuleHeaderSave'
|
||||||
|
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {Source} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
source: Source
|
||||||
|
onSave: () => void
|
||||||
|
validationError: string
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class RuleHeader extends Component {
|
class RuleHeader extends Component<Props> {
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
const {source, onSave, validationError} = this.props
|
const {source, onSave, validationError} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -29,12 +38,4 @@ class RuleHeader extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const {func, shape, string} = PropTypes
|
|
||||||
|
|
||||||
RuleHeader.propTypes = {
|
|
||||||
source: shape({}).isRequired,
|
|
||||||
onSave: func.isRequired,
|
|
||||||
validationError: string.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RuleHeader
|
export default RuleHeader
|
|
@ -1,39 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import ReactTooltip from 'react-tooltip'
|
|
||||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
|
||||||
|
|
||||||
const RuleHeaderSave = ({onSave, validationError}) => (
|
|
||||||
<div className="page-header__right">
|
|
||||||
<SourceIndicator />
|
|
||||||
{validationError ? (
|
|
||||||
<button
|
|
||||||
className="btn btn-success btn-sm disabled"
|
|
||||||
data-for="save-kapacitor-tooltip"
|
|
||||||
data-tip={validationError}
|
|
||||||
>
|
|
||||||
Save Rule
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<button className="btn btn-success btn-sm" onClick={onSave}>
|
|
||||||
Save Rule
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<ReactTooltip
|
|
||||||
id="save-kapacitor-tooltip"
|
|
||||||
effect="solid"
|
|
||||||
html={true}
|
|
||||||
place="bottom"
|
|
||||||
class="influx-tooltip kapacitor-tooltip"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {func, string} = PropTypes
|
|
||||||
|
|
||||||
RuleHeaderSave.propTypes = {
|
|
||||||
onSave: func.isRequired,
|
|
||||||
validationError: string.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RuleHeaderSave
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import React, {Component} from 'react'
|
||||||
|
|
||||||
|
import ReactTooltip from 'react-tooltip'
|
||||||
|
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||||
|
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {Source} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onSave: () => void
|
||||||
|
validationError: string
|
||||||
|
source: Source
|
||||||
|
}
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class RuleHeaderSave extends Component<Props> {
|
||||||
|
public render() {
|
||||||
|
const {source} = this.props
|
||||||
|
return (
|
||||||
|
<div className="page-header__right">
|
||||||
|
<SourceIndicator sourceOverride={source} />
|
||||||
|
{this.saveRuleButton}
|
||||||
|
<ReactTooltip
|
||||||
|
id="save-kapacitor-tooltip"
|
||||||
|
effect="solid"
|
||||||
|
html={true}
|
||||||
|
place="bottom"
|
||||||
|
class="influx-tooltip kapacitor-tooltip"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get saveRuleButton() {
|
||||||
|
const {onSave, validationError} = this.props
|
||||||
|
if (validationError) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className="btn btn-success btn-sm disabled"
|
||||||
|
data-for="save-kapacitor-tooltip"
|
||||||
|
data-tip={validationError}
|
||||||
|
>
|
||||||
|
Save Rule
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<button className="btn btn-success btn-sm" onClick={onSave}>
|
||||||
|
Save Rule
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RuleHeaderSave
|
|
@ -1,22 +1,24 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import RuleMessageText from 'src/kapacitor/components/RuleMessageText'
|
import RuleMessageText from 'src/kapacitor/components/RuleMessageText'
|
||||||
import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates'
|
import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
import {KapacitorRuleActions} from 'src/types/actions'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
ruleActions: KapacitorRuleActions
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class RuleMessage extends Component {
|
class RuleMessage extends Component<Props> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeMessage = e => {
|
public render() {
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
ruleActions.updateMessage(rule.id, e.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {rule, ruleActions} = this.props
|
const {rule, ruleActions} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -35,15 +37,11 @@ class RuleMessage extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, shape} = PropTypes
|
private handleChangeMessage = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
RuleMessage.propTypes = {
|
ruleActions.updateMessage(rule.id, e.target.value)
|
||||||
rule: shape().isRequired,
|
}
|
||||||
ruleActions: shape({
|
|
||||||
updateMessage: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RuleMessage
|
export default RuleMessage
|
|
@ -1,5 +1,5 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import ReactTooltip from 'react-tooltip'
|
import ReactTooltip from 'react-tooltip'
|
||||||
|
|
||||||
|
@ -8,19 +8,22 @@ import CodeData from 'src/kapacitor/components/CodeData'
|
||||||
import {RULE_MESSAGE_TEMPLATES} from 'src/kapacitor/constants'
|
import {RULE_MESSAGE_TEMPLATES} from 'src/kapacitor/constants'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {RuleMessage} from 'src/types/kapacitor'
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
updateMessage: (id: string, message: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
// needs to be React Component for CodeData click handler to work
|
// needs to be React Component for CodeData click handler to work
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class RuleMessageTemplates extends Component {
|
class RuleMessageTemplates extends Component<Props> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickTemplate = template => () => {
|
public render() {
|
||||||
const {updateMessage, rule} = this.props
|
|
||||||
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<div className="rule-section--row rule-section--row-last">
|
<div className="rule-section--row rule-section--row-last">
|
||||||
<p>Templates:</p>
|
<p>Templates:</p>
|
||||||
|
@ -41,13 +44,11 @@ class RuleMessageTemplates extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, shape} = PropTypes
|
private handleClickTemplate = (template: RuleMessage) => () => {
|
||||||
|
const {updateMessage, rule} = this.props
|
||||||
RuleMessageTemplates.propTypes = {
|
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
||||||
rule: shape().isRequired,
|
}
|
||||||
updateMessage: func.isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RuleMessageTemplates
|
export default RuleMessageTemplates
|
|
@ -1,7 +1,13 @@
|
||||||
import React from 'react'
|
import React, {SFC, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const RuleMessageText = ({rule, updateMessage}) => (
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
updateMessage: (e: ChangeEvent<HTMLTextAreaElement>) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const RuleMessageText: SFC<Props> = ({rule, updateMessage}) => (
|
||||||
<div className="rule-builder--message">
|
<div className="rule-builder--message">
|
||||||
<textarea
|
<textarea
|
||||||
className="form-control input-sm form-malachite monotype"
|
className="form-control input-sm form-malachite monotype"
|
||||||
|
@ -13,11 +19,4 @@ const RuleMessageText = ({rule, updateMessage}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {func, shape} = PropTypes
|
|
||||||
|
|
||||||
RuleMessageText.propTypes = {
|
|
||||||
rule: shape().isRequired,
|
|
||||||
updateMessage: func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RuleMessageText
|
export default RuleMessageText
|
|
@ -1,85 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {THRESHOLD_OPERATORS} from 'src/kapacitor/constants'
|
|
||||||
import Dropdown from 'shared/components/Dropdown'
|
|
||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
const mapToItems = (arr, type) => arr.map(text => ({text, type}))
|
|
||||||
const operators = mapToItems(THRESHOLD_OPERATORS, 'operator')
|
|
||||||
const noopSubmit = e => e.preventDefault()
|
|
||||||
const getField = ({fields}) => {
|
|
||||||
const alias = _.get(fields, ['0', 'alias'], false)
|
|
||||||
if (!alias) {
|
|
||||||
return _.get(fields, ['0', 'value'], 'Select a Time-Series')
|
|
||||||
}
|
|
||||||
|
|
||||||
return alias
|
|
||||||
}
|
|
||||||
|
|
||||||
const Threshold = ({
|
|
||||||
rule: {
|
|
||||||
values: {operator, value, rangeValue},
|
|
||||||
},
|
|
||||||
query,
|
|
||||||
onDropdownChange,
|
|
||||||
onRuleTypeInputChange,
|
|
||||||
}) => (
|
|
||||||
<div className="rule-section--row rule-section--row-first rule-section--border-bottom">
|
|
||||||
<p>Send Alert where</p>
|
|
||||||
<span className="rule-builder--metric">{getField(query)}</span>
|
|
||||||
<p>is</p>
|
|
||||||
<Dropdown
|
|
||||||
className="dropdown-180"
|
|
||||||
menuClass="dropdown-malachite"
|
|
||||||
items={operators}
|
|
||||||
selected={operator}
|
|
||||||
onChoose={onDropdownChange}
|
|
||||||
/>
|
|
||||||
<form style={{display: 'flex'}} onSubmit={noopSubmit}>
|
|
||||||
<input
|
|
||||||
className="form-control input-sm form-malachite monotype"
|
|
||||||
style={{width: '160px', marginLeft: '6px'}}
|
|
||||||
type="text"
|
|
||||||
name="lower"
|
|
||||||
spellCheck="false"
|
|
||||||
value={value}
|
|
||||||
onChange={onRuleTypeInputChange}
|
|
||||||
placeholder={
|
|
||||||
operator === 'inside range' || operator === 'outside range'
|
|
||||||
? 'Lower'
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{(operator === 'inside range' || operator === 'outside range') && (
|
|
||||||
<input
|
|
||||||
className="form-control input-sm form-malachite monotype"
|
|
||||||
name="upper"
|
|
||||||
style={{width: '160px'}}
|
|
||||||
placeholder="Upper"
|
|
||||||
type="text"
|
|
||||||
spellCheck="false"
|
|
||||||
value={rangeValue}
|
|
||||||
onChange={onRuleTypeInputChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
Threshold.propTypes = {
|
|
||||||
rule: shape({
|
|
||||||
values: shape({
|
|
||||||
operator: string,
|
|
||||||
rangeOperator: string,
|
|
||||||
value: string,
|
|
||||||
rangeValue: string,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
onDropdownChange: func.isRequired,
|
|
||||||
onRuleTypeInputChange: func.isRequired,
|
|
||||||
query: shape({}).isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Threshold
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import React, {Component, FormEvent, ChangeEvent} from 'react'
|
||||||
|
|
||||||
|
import {THRESHOLD_OPERATORS} from 'src/kapacitor/constants'
|
||||||
|
import Dropdown from 'src/shared/components/Dropdown'
|
||||||
|
import {getDeep} from 'src/utils/wrappers'
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {AlertRule, QueryConfig} from 'src/types'
|
||||||
|
|
||||||
|
interface TypeItem {
|
||||||
|
type: string
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
onDropdownChange: (item: TypeItem) => void
|
||||||
|
onRuleTypeInputChange: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
query: QueryConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class Threshold extends Component<Props> {
|
||||||
|
public render() {
|
||||||
|
const {
|
||||||
|
rule: {
|
||||||
|
values: {operator, value},
|
||||||
|
},
|
||||||
|
query,
|
||||||
|
onDropdownChange,
|
||||||
|
onRuleTypeInputChange,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rule-section--row rule-section--row-first rule-section--border-bottom">
|
||||||
|
<p>Send Alert where</p>
|
||||||
|
<span className="rule-builder--metric">{this.getField(query)}</span>
|
||||||
|
<p>is</p>
|
||||||
|
<Dropdown
|
||||||
|
className="dropdown-180"
|
||||||
|
menuClass="dropdown-malachite"
|
||||||
|
items={this.operators}
|
||||||
|
selected={operator}
|
||||||
|
onChoose={onDropdownChange}
|
||||||
|
/>
|
||||||
|
<form style={{display: 'flex'}} onSubmit={this.noopSubmit}>
|
||||||
|
<input
|
||||||
|
className="form-control input-sm form-malachite monotype"
|
||||||
|
style={{width: '160px', marginLeft: '6px'}}
|
||||||
|
type="text"
|
||||||
|
name="lower"
|
||||||
|
spellCheck={false}
|
||||||
|
value={value}
|
||||||
|
onChange={onRuleTypeInputChange}
|
||||||
|
placeholder={this.firstInputPlaceholder}
|
||||||
|
/>
|
||||||
|
{this.secondInput}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get operators() {
|
||||||
|
const type = 'operator'
|
||||||
|
return THRESHOLD_OPERATORS.map(text => {
|
||||||
|
return {text, type}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private get isSecondInputRequired() {
|
||||||
|
const {rule} = this.props
|
||||||
|
const operator = getDeep<string>(rule, 'values.operator', '')
|
||||||
|
|
||||||
|
if (operator === 'inside range' || operator === 'outside range') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private get firstInputPlaceholder() {
|
||||||
|
if (this.isSecondInputRequired) {
|
||||||
|
return 'lower'
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private get secondInput() {
|
||||||
|
const {rule, onRuleTypeInputChange} = this.props
|
||||||
|
|
||||||
|
const rangeValue = getDeep<string>(rule, 'values.rangeValue', '')
|
||||||
|
|
||||||
|
if (this.isSecondInputRequired) {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
className="form-control input-sm form-malachite monotype"
|
||||||
|
name="upper"
|
||||||
|
style={{width: '160px'}}
|
||||||
|
placeholder="Upper"
|
||||||
|
type="text"
|
||||||
|
spellCheck={false}
|
||||||
|
value={rangeValue}
|
||||||
|
onChange={onRuleTypeInputChange}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private noopSubmit = (e: FormEvent<HTMLElement>) => e.preventDefault()
|
||||||
|
|
||||||
|
private getField = ({fields}: QueryConfig): string => {
|
||||||
|
const alias = getDeep<string>(fields, '0.alias', '')
|
||||||
|
|
||||||
|
if (!alias) {
|
||||||
|
return getDeep<string>(fields, '0.value', 'Select a Time-Series')
|
||||||
|
}
|
||||||
|
|
||||||
|
return alias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Threshold
|
|
@ -1,6 +1,4 @@
|
||||||
import React from 'react'
|
import React, {SFC, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import Deadman from 'src/kapacitor/components/Deadman'
|
import Deadman from 'src/kapacitor/components/Deadman'
|
||||||
|
@ -9,7 +7,16 @@ import Relative from 'src/kapacitor/components/Relative'
|
||||||
import DataSection from 'src/kapacitor/components/DataSection'
|
import DataSection from 'src/kapacitor/components/DataSection'
|
||||||
import RuleGraph from 'src/kapacitor/components/RuleGraph'
|
import RuleGraph from 'src/kapacitor/components/RuleGraph'
|
||||||
|
|
||||||
import {Tab, TabList, TabPanels, TabPanel, Tabs} from 'shared/components/Tabs'
|
import {
|
||||||
|
Tab,
|
||||||
|
TabList,
|
||||||
|
TabPanels,
|
||||||
|
TabPanel,
|
||||||
|
Tabs,
|
||||||
|
} from 'src/shared/components/Tabs'
|
||||||
|
|
||||||
|
import {AlertRule, QueryConfig, Source, TimeRange} from 'src/types'
|
||||||
|
import {KapacitorQueryConfigActions} from 'src/types/actions'
|
||||||
|
|
||||||
const TABS = ['Threshold', 'Relative', 'Deadman']
|
const TABS = ['Threshold', 'Relative', 'Deadman']
|
||||||
|
|
||||||
|
@ -22,13 +29,36 @@ const handleChooseTrigger = (rule, onChooseTrigger) => triggerIndex => {
|
||||||
const initialIndex = rule => TABS.indexOf(_.startCase(rule.trigger))
|
const initialIndex = rule => TABS.indexOf(_.startCase(rule.trigger))
|
||||||
const isDeadman = rule => rule.trigger === 'deadman'
|
const isDeadman = rule => rule.trigger === 'deadman'
|
||||||
|
|
||||||
const ValuesSection = ({
|
interface Item {
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeItem extends Item {
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
onChooseTrigger: () => void
|
||||||
|
onUpdateValues: () => void
|
||||||
|
query: QueryConfig
|
||||||
|
onDeadmanChange: (item: Item) => void
|
||||||
|
onRuleTypeDropdownChange: (item: TypeItem) => void
|
||||||
|
onRuleTypeInputChange: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
onAddEvery: (frequency: string) => void
|
||||||
|
onRemoveEvery: () => void
|
||||||
|
timeRange: TimeRange
|
||||||
|
queryConfigActions: KapacitorQueryConfigActions
|
||||||
|
source: Source
|
||||||
|
onChooseTimeRange: (timeRange: TimeRange) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const ValuesSection: SFC<Props> = ({
|
||||||
rule,
|
rule,
|
||||||
query,
|
query,
|
||||||
source,
|
source,
|
||||||
timeRange,
|
timeRange,
|
||||||
onAddEvery,
|
onAddEvery,
|
||||||
onRemoveEvery,
|
|
||||||
onChooseTrigger,
|
onChooseTrigger,
|
||||||
onDeadmanChange,
|
onDeadmanChange,
|
||||||
onChooseTimeRange,
|
onChooseTimeRange,
|
||||||
|
@ -58,7 +88,6 @@ const ValuesSection = ({
|
||||||
isKapacitorRule={true}
|
isKapacitorRule={true}
|
||||||
actions={queryConfigActions}
|
actions={queryConfigActions}
|
||||||
onAddEvery={onAddEvery}
|
onAddEvery={onAddEvery}
|
||||||
onRemoveEvery={onRemoveEvery}
|
|
||||||
isDeadman={isDeadman(rule)}
|
isDeadman={isDeadman(rule)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,24 +126,4 @@ const ValuesSection = ({
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
ValuesSection.propTypes = {
|
|
||||||
rule: shape({
|
|
||||||
id: string,
|
|
||||||
}).isRequired,
|
|
||||||
onChooseTrigger: func.isRequired,
|
|
||||||
onUpdateValues: func.isRequired,
|
|
||||||
query: shape({}).isRequired,
|
|
||||||
onDeadmanChange: func.isRequired,
|
|
||||||
onRuleTypeDropdownChange: func.isRequired,
|
|
||||||
onRuleTypeInputChange: func.isRequired,
|
|
||||||
onAddEvery: func.isRequired,
|
|
||||||
onRemoveEvery: func.isRequired,
|
|
||||||
timeRange: shape({}).isRequired,
|
|
||||||
queryConfigActions: shape({}).isRequired,
|
|
||||||
source: shape({}).isRequired,
|
|
||||||
onChooseTimeRange: func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ValuesSection
|
export default ValuesSection
|
|
@ -1,26 +1,59 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import _ from 'lodash'
|
||||||
|
import {InjectedRouter} from 'react-router'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
|
||||||
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
||||||
import * as kapacitorQueryConfigActionCreators from 'src/kapacitor/actions/queryConfigs'
|
import * as kapacitorQueryConfigActionCreators from 'src/kapacitor/actions/queryConfigs'
|
||||||
|
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
import {getActiveKapacitor, getKapacitorConfig} from 'shared/apis/index'
|
import {getActiveKapacitor, getKapacitorConfig} from 'src/shared/apis/index'
|
||||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||||
import KapacitorRule from 'src/kapacitor/components/KapacitorRule'
|
import KapacitorRule from 'src/kapacitor/components/KapacitorRule'
|
||||||
import parseHandlersFromConfig from 'src/shared/parsing/parseHandlersFromConfig'
|
import parseHandlersFromConfig from 'src/shared/parsing/parseHandlersFromConfig'
|
||||||
import {notify as notifyAction} from 'shared/actions/notifications'
|
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
notifyKapacitorCreateFailed,
|
notifyKapacitorCreateFailed,
|
||||||
notifyCouldNotFindKapacitor,
|
notifyCouldNotFindKapacitor,
|
||||||
} from 'shared/copy/notifications'
|
} from 'src/shared/copy/notifications'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Source,
|
||||||
|
Notification,
|
||||||
|
AlertRule,
|
||||||
|
QueryConfig,
|
||||||
|
Kapacitor,
|
||||||
|
} from 'src/types'
|
||||||
|
import {
|
||||||
|
KapacitorQueryConfigActions,
|
||||||
|
KapacitorRuleActions,
|
||||||
|
} from 'src/types/actions'
|
||||||
|
|
||||||
|
interface Params {
|
||||||
|
ruleID: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
source: Source
|
||||||
|
notify: (notification: Notification) => void
|
||||||
|
rules: AlertRule[]
|
||||||
|
queryConfigs: QueryConfig[]
|
||||||
|
ruleActions: KapacitorRuleActions
|
||||||
|
queryConfigActions: KapacitorQueryConfigActions
|
||||||
|
params: Params
|
||||||
|
router: InjectedRouter
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
handlersFromConfig: any[]
|
||||||
|
kapacitor: Kapacitor | {}
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class KapacitorRulePage extends Component {
|
class KapacitorRulePage extends Component<Props, State> {
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -29,7 +62,7 @@ class KapacitorRulePage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
public async componentDidMount() {
|
||||||
const {params, source, ruleActions, notify} = this.props
|
const {params, source, ruleActions, notify} = this.props
|
||||||
|
|
||||||
if (params.ruleID === 'new') {
|
if (params.ruleID === 'new') {
|
||||||
|
@ -54,9 +87,8 @@ class KapacitorRulePage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
rules,
|
|
||||||
params,
|
params,
|
||||||
source,
|
source,
|
||||||
router,
|
router,
|
||||||
|
@ -65,8 +97,7 @@ class KapacitorRulePage extends Component {
|
||||||
queryConfigActions,
|
queryConfigActions,
|
||||||
} = this.props
|
} = this.props
|
||||||
const {handlersFromConfig, kapacitor} = this.state
|
const {handlersFromConfig, kapacitor} = this.state
|
||||||
const rule =
|
const rule = this.rule
|
||||||
params.ruleID === 'new' ? rules[DEFAULT_RULE_ID] : rules[params.ruleID]
|
|
||||||
const query = rule && queryConfigs[rule.queryID]
|
const query = rule && queryConfigs[rule.queryID]
|
||||||
|
|
||||||
if (!query) {
|
if (!query) {
|
||||||
|
@ -84,41 +115,26 @@ class KapacitorRulePage extends Component {
|
||||||
ruleID={params.ruleID}
|
ruleID={params.ruleID}
|
||||||
router={router}
|
router={router}
|
||||||
kapacitor={kapacitor}
|
kapacitor={kapacitor}
|
||||||
configLink={`/sources/${source.id}/kapacitors/${kapacitor.id}/edit`}
|
configLink={`/sources/${source.id}/kapacitors/${this.kapacitorID}/edit`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, shape, string} = PropTypes
|
private get kapacitorID(): string {
|
||||||
|
const {kapacitor} = this.state
|
||||||
|
return _.get(kapacitor, 'id')
|
||||||
|
}
|
||||||
|
|
||||||
KapacitorRulePage.propTypes = {
|
private get rule(): AlertRule {
|
||||||
source: shape({
|
const {params, rules} = this.props
|
||||||
links: shape({
|
const ruleID = _.get(params, 'ruleID')
|
||||||
proxy: string.isRequired,
|
|
||||||
self: string.isRequired,
|
if (ruleID === 'new') {
|
||||||
}),
|
return rules[DEFAULT_RULE_ID]
|
||||||
}),
|
}
|
||||||
notify: func,
|
|
||||||
rules: shape({}).isRequired,
|
return rules[params.ruleID]
|
||||||
queryConfigs: shape({}).isRequired,
|
}
|
||||||
ruleActions: shape({
|
|
||||||
loadDefaultRule: func.isRequired,
|
|
||||||
fetchRule: func.isRequired,
|
|
||||||
chooseTrigger: func.isRequired,
|
|
||||||
addEvery: func.isRequired,
|
|
||||||
removeEvery: func.isRequired,
|
|
||||||
updateRuleValues: func.isRequired,
|
|
||||||
updateMessage: func.isRequired,
|
|
||||||
updateRuleName: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
queryConfigActions: shape({}).isRequired,
|
|
||||||
params: shape({
|
|
||||||
ruleID: string,
|
|
||||||
}).isRequired,
|
|
||||||
router: shape({
|
|
||||||
push: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = ({rules, kapacitorQueryConfigs: queryConfigs}) => ({
|
const mapStateToProps = ({rules, kapacitorQueryConfigs: queryConfigs}) => ({
|
|
@ -48,7 +48,7 @@ interface TabListProps {
|
||||||
activeIndex?: number
|
activeIndex?: number
|
||||||
onActivate?: (index: number) => void
|
onActivate?: (index: number) => void
|
||||||
isKapacitorTabs?: string
|
isKapacitorTabs?: string
|
||||||
customClass: string
|
customClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabList: SFC<TabListProps> = ({
|
export const TabList: SFC<TabListProps> = ({
|
||||||
|
@ -97,7 +97,7 @@ TabList.defaultProps = {
|
||||||
interface TabPanelsProps {
|
interface TabPanelsProps {
|
||||||
children: JSX.Element[] | JSX.Element
|
children: JSX.Element[] | JSX.Element
|
||||||
activeIndex?: number
|
activeIndex?: number
|
||||||
customClass: string
|
customClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabPanels: SFC<TabPanelsProps> = ({
|
export const TabPanels: SFC<TabPanelsProps> = ({
|
||||||
|
@ -120,7 +120,7 @@ export const TabPanel: SFC<TabPanelProps> = ({children}) => (
|
||||||
interface TabsProps {
|
interface TabsProps {
|
||||||
children: JSX.Element[] | JSX.Element
|
children: JSX.Element[] | JSX.Element
|
||||||
onSelect?: (activeIndex: number) => void
|
onSelect?: (activeIndex: number) => void
|
||||||
tabContentsClass: string
|
tabContentsClass?: string
|
||||||
tabsClass?: string
|
tabsClass?: string
|
||||||
initialIndex?: number
|
initialIndex?: number
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
import * as kapacitorQueryConfigActions from 'src/kapacitor/actions/queryConfigs'
|
import * as kapacitorQueryConfigActions from 'src/kapacitor/actions/queryConfigs'
|
||||||
|
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
||||||
|
|
||||||
type KapacitorQueryConfigActions = typeof kapacitorQueryConfigActions
|
type KapacitorQueryConfigActions = typeof kapacitorQueryConfigActions
|
||||||
|
type KapacitorRuleActions = typeof kapacitorRuleActionCreators
|
||||||
|
|
||||||
export {KapacitorQueryConfigActions}
|
export {KapacitorQueryConfigActions}
|
||||||
|
export {KapacitorRuleActions}
|
||||||
|
|
|
@ -32,6 +32,7 @@ export interface AlertRule {
|
||||||
error: string
|
error: string
|
||||||
created: string
|
created: string
|
||||||
modified: string
|
modified: string
|
||||||
|
queryID?: string
|
||||||
'last-enabled'?: string
|
'last-enabled'?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +225,7 @@ export interface RuleMessageTemplate {
|
||||||
time: RuleMessage
|
time: RuleMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RuleMessage {
|
export interface RuleMessage {
|
||||||
label: string
|
label: string
|
||||||
text: string
|
text: string
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue