Merge pull request #3722 from influxdata/fun/kapacitor-typescript
Convert Kapacitor components to typescriptpull/3662/head^2
commit
508f75da3a
|
@ -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
|
||||
isDeadman: boolean
|
||||
isKapacitorRule: boolean
|
||||
onAddEvery: () => void
|
||||
onAddEvery: (every?: string) => void
|
||||
timeRange: TimeRange
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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 => {
|
||||
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">
|
||||
<p>Send Alert if Data is missing for</p>
|
||||
<Dropdown
|
||||
|
@ -20,15 +31,4 @@ const Deadman = ({rule, onChange}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string, func} = PropTypes
|
||||
|
||||
Deadman.propTypes = {
|
||||
rule: shape({
|
||||
values: shape({
|
||||
period: string,
|
||||
}),
|
||||
}),
|
||||
onChange: func.isRequired,
|
||||
}
|
||||
|
||||
export default Deadman
|
|
@ -1,20 +1,20 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {Component, ChangeEvent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
|
||||
import NameSection from 'src/kapacitor/components/NameSection'
|
||||
import ValuesSection from 'src/kapacitor/components/ValuesSection'
|
||||
import RuleHeader from 'src/kapacitor/components/RuleHeader'
|
||||
import RuleHandlers from 'src/kapacitor/components/RuleHandlers'
|
||||
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 buildInfluxQLQuery from 'utils/influxql'
|
||||
import {timeRanges} from 'shared/data/timeRanges'
|
||||
import buildInfluxQLQuery from 'src/utils/influxql'
|
||||
import {timeRanges} from 'src/shared/data/timeRanges'
|
||||
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 {
|
||||
notifyAlertRuleCreated,
|
||||
|
@ -24,11 +24,52 @@ import {
|
|||
notifyAlertRuleRequiresQuery,
|
||||
notifyAlertRuleRequiresConditionValue,
|
||||
notifyAlertRuleDeadmanInvalid,
|
||||
} from 'shared/copy/notifications'
|
||||
} from 'src/shared/copy/notifications'
|
||||
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
|
||||
class KapacitorRule extends Component {
|
||||
class KapacitorRule extends Component<Props, State> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
@ -36,137 +77,7 @@ class KapacitorRule extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleChooseTimeRange = ({lower}) => {
|
||||
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() {
|
||||
public render() {
|
||||
const {
|
||||
rule,
|
||||
source,
|
||||
|
@ -183,7 +94,7 @@ class KapacitorRule extends Component {
|
|||
<RuleHeader
|
||||
source={source}
|
||||
onSave={this.handleSave}
|
||||
validationError={this.validationError()}
|
||||
validationError={this.validationError}
|
||||
/>
|
||||
<FancyScrollbar className="page-contents fancy-scroll--kapacitor">
|
||||
<div className="container-fluid">
|
||||
|
@ -215,7 +126,7 @@ class KapacitorRule extends Component {
|
|||
ruleActions={ruleActions}
|
||||
handlersFromConfig={handlersFromConfig}
|
||||
onGoToConfig={this.handleSaveToConfig}
|
||||
validationError={this.validationError()}
|
||||
validationError={this.validationError}
|
||||
/>
|
||||
<RuleMessage rule={rule} ruleActions={ruleActions} />
|
||||
</div>
|
||||
|
@ -226,27 +137,138 @@ class KapacitorRule extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {arrayOf, func, shape, string} = PropTypes
|
||||
private handleChooseTimeRange = ({lower}: TimeRange) => {
|
||||
const timeRange = timeRanges.find(range => range.lower === lower)
|
||||
this.setState({timeRange})
|
||||
}
|
||||
|
||||
KapacitorRule.propTypes = {
|
||||
source: shape({}).isRequired,
|
||||
rule: shape({
|
||||
values: shape({}),
|
||||
}).isRequired,
|
||||
query: shape({}).isRequired,
|
||||
queryConfigs: shape({}).isRequired,
|
||||
queryConfigActions: shape({}).isRequired,
|
||||
ruleActions: shape({}).isRequired,
|
||||
notify: func.isRequired,
|
||||
ruleID: string.isRequired,
|
||||
handlersFromConfig: arrayOf(shape({})).isRequired,
|
||||
router: shape({
|
||||
push: func.isRequired,
|
||||
}).isRequired,
|
||||
kapacitor: shape({}).isRequired,
|
||||
configLink: string.isRequired,
|
||||
private handleCreate = (pathname?: string) => {
|
||||
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))
|
||||
})
|
||||
}
|
||||
|
||||
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 => ({
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const LogItemHTTP = ({logItem}) => (
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
const LogItemHTTP: SFC<Props> = ({logItem}) => (
|
||||
<div className="logs-table--row">
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,17 +21,4 @@ const LogItemHTTP = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemHTTP.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
method: string.isRequired,
|
||||
username: string.isRequired,
|
||||
host: string.isRequired,
|
||||
duration: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemHTTP
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const LogItemHTTPError = ({logItem}) => (
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
const LogItemHTTPError: SFC<Props> = ({logItem}) => (
|
||||
<div className="logs-table--row" key={logItem.key}>
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,15 +21,4 @@ const LogItemHTTPError = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemHTTPError.propTypes = {
|
||||
logItem: shape({
|
||||
key: string.isRequired,
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemHTTPError
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const LogItemInfluxDBDebug = ({logItem}) => (
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
const LogItemInfluxDBDebug: SFC<Props> = ({logItem}) => (
|
||||
<div className="logs-table--row">
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -20,15 +25,4 @@ const LogItemInfluxDBDebug = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemInfluxDBDebug.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
cluster: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemInfluxDBDebug
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const LogItemKapacitorDebug = ({logItem}) => (
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
const LogItemKapacitorDebug: SFC<Props> = ({logItem}) => (
|
||||
<div className="logs-table--row">
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,14 +21,4 @@ const LogItemKapacitorDebug = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemKapacitorDebug.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemKapacitorDebug
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const LogItemKapacitorError = ({logItem}) => (
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
const LogItemKapacitorError: SFC<Props> = ({logItem}) => (
|
||||
<div className="logs-table--row">
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,14 +21,4 @@ const LogItemKapacitorError = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemKapacitorError.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemKapacitorError
|
|
@ -1,51 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const renderKeysAndValues = (object, name) => {
|
||||
if (!object) {
|
||||
return <span className="logs-table--empty-cell">--</span>
|
||||
}
|
||||
|
||||
const sortedObjKeys = Object.keys(object).sort()
|
||||
|
||||
return (
|
||||
<div className="logs-table--column">
|
||||
<h1>{`${sortedObjKeys.length} ${name}`}</h1>
|
||||
<div className="logs-table--scrollbox">
|
||||
{sortedObjKeys.map(objKey => (
|
||||
<div key={objKey} className="logs-table--key-value">
|
||||
{objKey}: <span>{object[objKey]}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const LogItemKapacitorPoint = ({logItem}) => (
|
||||
<div className="logs-table--row">
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
<div className="logs-table--timestamp">{logItem.ts}</div>
|
||||
</div>
|
||||
<div className="logs-table--details">
|
||||
<div className="logs-table--service">Kapacitor Point</div>
|
||||
<div className="logs-table--columns">
|
||||
{renderKeysAndValues(logItem.tag, 'Tags')}
|
||||
{renderKeysAndValues(logItem.field, 'Fields')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemKapacitorPoint.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
tag: shape.isRequired,
|
||||
field: shape.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemKapacitorPoint
|
|
@ -0,0 +1,55 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class LogItemKapacitorPoint extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {logItem} = this.props
|
||||
return (
|
||||
<div className="logs-table--row">
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
<div className="logs-table--timestamp">{logItem.ts}</div>
|
||||
</div>
|
||||
<div className="logs-table--details">
|
||||
<div className="logs-table--service">Kapacitor Point</div>
|
||||
<div className="logs-table--columns">
|
||||
{this.renderKeysAndValues(logItem.tag, 'Tags')}
|
||||
{this.renderKeysAndValues(logItem.field, 'Fields')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private renderKeysAndValues = (object: any, name: string) => {
|
||||
if (_.isEmpty(object)) {
|
||||
return <span className="logs-table--empty-cell">--</span>
|
||||
}
|
||||
|
||||
const sortedObjKeys = Object.keys(object).sort()
|
||||
|
||||
return (
|
||||
<div className="logs-table--column">
|
||||
<h1>{`${sortedObjKeys.length} ${name}`}</h1>
|
||||
<div className="logs-table--scrollbox">
|
||||
{sortedObjKeys.map(objKey => (
|
||||
<div key={objKey} className="logs-table--key-value">
|
||||
{objKey}: <span>{object[objKey]}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LogItemKapacitorPoint
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const LogItemSession = ({logItem}) => (
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
const LogItemSession: SFC<Props> = ({logItem}) => (
|
||||
<div className="logs-table--row">
|
||||
<div className="logs-table--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -13,14 +18,4 @@ const LogItemSession = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemSession.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemSession
|
|
@ -1,12 +1,17 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
import LogsTableRow from 'src/kapacitor/components/LogsTableRow'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
const numLogsToRender = 200
|
||||
|
||||
const LogsTable = ({logs}) => (
|
||||
interface Props {
|
||||
logs: LogItem[]
|
||||
}
|
||||
|
||||
const LogsTable: SFC<Props> = ({logs}) => (
|
||||
<div className="logs-table">
|
||||
<div className="logs-table--header">
|
||||
{`${numLogsToRender} Most Recent Logs`}
|
||||
|
@ -22,17 +27,4 @@ const LogsTable = ({logs}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {arrayOf, shape, string} = PropTypes
|
||||
|
||||
LogsTable.propTypes = {
|
||||
logs: arrayOf(
|
||||
shape({
|
||||
key: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
lvl: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
}
|
||||
|
||||
export default LogsTable
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
import LogItemSession from 'src/kapacitor/components/LogItemSession'
|
||||
import LogItemHTTP from 'src/kapacitor/components/LogItemHTTP'
|
||||
|
@ -9,7 +8,13 @@ import LogItemKapacitorError from 'src/kapacitor/components/LogItemKapacitorErro
|
|||
import LogItemKapacitorDebug from 'src/kapacitor/components/LogItemKapacitorDebug'
|
||||
import LogItemInfluxDBDebug from 'src/kapacitor/components/LogItemInfluxDBDebug'
|
||||
|
||||
const LogsTableRow = ({logItem}) => {
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logItem: LogItem
|
||||
}
|
||||
|
||||
const LogsTableRow: SFC<Props> = ({logItem}) => {
|
||||
if (logItem.service === 'sessions') {
|
||||
return <LogItemSession logItem={logItem} />
|
||||
}
|
||||
|
@ -51,15 +56,4 @@ const LogsTableRow = ({logItem}) => {
|
|||
)
|
||||
}
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogsTableRow.propTypes = {
|
||||
logItem: shape({
|
||||
key: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
lvl: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
export default LogsTableRow
|
|
@ -1,11 +1,25 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {Component, ChangeEvent, KeyboardEvent} from 'react'
|
||||
|
||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||
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
|
||||
class NameSection extends Component {
|
||||
constructor(props) {
|
||||
class NameSection extends Component<Props, State> {
|
||||
private inputRef: HTMLInputElement
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
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
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
public handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
this.inputRef.blur()
|
||||
}
|
||||
|
@ -30,15 +52,13 @@ class NameSection extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {rule, defaultName} = this.props
|
||||
public render() {
|
||||
const {defaultName} = this.props
|
||||
const {reset} = this.state
|
||||
|
||||
return (
|
||||
<div className="rule-section">
|
||||
<h3 className="rule-section--heading">
|
||||
{rule.id === DEFAULT_RULE_ID ? 'Name this Alert Rule' : 'Name'}
|
||||
</h3>
|
||||
<h3 className="rule-section--heading">{this.header}</h3>
|
||||
<div className="rule-section--body">
|
||||
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
||||
<input
|
||||
|
@ -55,14 +75,18 @@ class NameSection extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, string, shape} = PropTypes
|
||||
private get header() {
|
||||
const {
|
||||
rule: {id},
|
||||
} = this.props
|
||||
|
||||
NameSection.propTypes = {
|
||||
defaultName: string.isRequired,
|
||||
onRuleRename: func.isRequired,
|
||||
rule: shape({}).isRequired,
|
||||
if (id === DEFAULT_RULE_ID) {
|
||||
return 'Name this Alert Rule'
|
||||
}
|
||||
|
||||
return 'Name'
|
||||
}
|
||||
}
|
||||
|
||||
export default NameSection
|
|
@ -1,14 +1,27 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {CHANGES, RELATIVE_OPERATORS, SHIFTS} from 'src/kapacitor/constants'
|
||||
import Dropdown from 'shared/components/Dropdown'
|
||||
import React, {SFC, ChangeEvent} from 'react'
|
||||
|
||||
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 shifts = mapToItems(SHIFTS, 'shift')
|
||||
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,
|
||||
onDropdownChange,
|
||||
rule: {
|
||||
|
@ -46,7 +59,7 @@ const Relative = ({
|
|||
style={{width: '160px', marginLeft: '6px'}}
|
||||
type="text"
|
||||
name="lower"
|
||||
spellCheck="false"
|
||||
spellCheck={false}
|
||||
value={value}
|
||||
onChange={onRuleTypeInputChange}
|
||||
required={true}
|
||||
|
@ -56,19 +69,4 @@ const Relative = ({
|
|||
</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
|
|
@ -26,7 +26,7 @@ interface Props {
|
|||
rule: AlertRule
|
||||
ruleActions: RuleActions
|
||||
handlersFromConfig: Handler[]
|
||||
onGoToConfig: () => void
|
||||
onGoToConfig: (configName: string) => void
|
||||
validationError: string
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import RuleHeaderSave from 'src/kapacitor/components/RuleHeaderSave'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {Source} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
source: Source
|
||||
onSave: () => void
|
||||
validationError: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class RuleHeader extends Component {
|
||||
constructor(props) {
|
||||
class RuleHeader extends Component<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {source, onSave, validationError} = this.props
|
||||
|
||||
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
|
|
@ -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 PropTypes from 'prop-types'
|
||||
import React, {Component, ChangeEvent} from 'react'
|
||||
|
||||
import RuleMessageText from 'src/kapacitor/components/RuleMessageText'
|
||||
import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates'
|
||||
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
|
||||
class RuleMessage extends Component {
|
||||
class RuleMessage extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
handleChangeMessage = e => {
|
||||
const {ruleActions, rule} = this.props
|
||||
ruleActions.updateMessage(rule.id, e.target.value)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {rule, ruleActions} = this.props
|
||||
|
||||
return (
|
||||
|
@ -35,15 +37,11 @@ class RuleMessage extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, shape} = PropTypes
|
||||
|
||||
RuleMessage.propTypes = {
|
||||
rule: shape().isRequired,
|
||||
ruleActions: shape({
|
||||
updateMessage: func.isRequired,
|
||||
}).isRequired,
|
||||
private handleChangeMessage = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const {ruleActions, rule} = this.props
|
||||
ruleActions.updateMessage(rule.id, e.target.value)
|
||||
}
|
||||
}
|
||||
|
||||
export default RuleMessage
|
|
@ -1,5 +1,5 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import _ from 'lodash'
|
||||
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 {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
|
||||
@ErrorHandling
|
||||
class RuleMessageTemplates extends Component {
|
||||
class RuleMessageTemplates extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
handleClickTemplate = template => () => {
|
||||
const {updateMessage, rule} = this.props
|
||||
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
return (
|
||||
<div className="rule-section--row rule-section--row-last">
|
||||
<p>Templates:</p>
|
||||
|
@ -41,13 +44,11 @@ class RuleMessageTemplates extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, shape} = PropTypes
|
||||
|
||||
RuleMessageTemplates.propTypes = {
|
||||
rule: shape().isRequired,
|
||||
updateMessage: func.isRequired,
|
||||
private handleClickTemplate = (template: RuleMessage) => () => {
|
||||
const {updateMessage, rule} = this.props
|
||||
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
||||
}
|
||||
}
|
||||
|
||||
export default RuleMessageTemplates
|
|
@ -1,7 +1,13 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC, ChangeEvent} from 'react'
|
||||
|
||||
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">
|
||||
<textarea
|
||||
className="form-control input-sm form-malachite monotype"
|
||||
|
@ -13,11 +19,4 @@ const RuleMessageText = ({rule, updateMessage}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {func, shape} = PropTypes
|
||||
|
||||
RuleMessageText.propTypes = {
|
||||
rule: shape().isRequired,
|
||||
updateMessage: func.isRequired,
|
||||
}
|
||||
|
||||
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,89 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import TickscriptHeader from 'src/kapacitor/components/TickscriptHeader'
|
||||
import TickscriptEditor from 'src/kapacitor/components/TickscriptEditor'
|
||||
import TickscriptEditorControls from 'src/kapacitor/components/TickscriptEditorControls'
|
||||
import TickscriptEditorConsole from 'src/kapacitor/components/TickscriptEditorConsole'
|
||||
import LogsTable from 'src/kapacitor/components/LogsTable'
|
||||
|
||||
const Tickscript = ({
|
||||
onSave,
|
||||
onExit,
|
||||
task,
|
||||
logs,
|
||||
consoleMessage,
|
||||
onSelectDbrps,
|
||||
onChangeScript,
|
||||
onChangeType,
|
||||
onChangeID,
|
||||
unsavedChanges,
|
||||
isNewTickscript,
|
||||
areLogsVisible,
|
||||
areLogsEnabled,
|
||||
onToggleLogsVisibility,
|
||||
}) => (
|
||||
<div className="page">
|
||||
<TickscriptHeader
|
||||
task={task}
|
||||
onSave={onSave}
|
||||
onExit={onExit}
|
||||
unsavedChanges={unsavedChanges}
|
||||
areLogsVisible={areLogsVisible}
|
||||
areLogsEnabled={areLogsEnabled}
|
||||
onToggleLogsVisibility={onToggleLogsVisibility}
|
||||
isNewTickscript={isNewTickscript}
|
||||
/>
|
||||
<div className="page-contents--split">
|
||||
<div
|
||||
className="tickscript"
|
||||
style={areLogsVisible ? {maxWidth: '50%'} : null}
|
||||
>
|
||||
<TickscriptEditorControls
|
||||
isNewTickscript={isNewTickscript}
|
||||
onSelectDbrps={onSelectDbrps}
|
||||
onChangeType={onChangeType}
|
||||
onChangeID={onChangeID}
|
||||
task={task}
|
||||
/>
|
||||
<TickscriptEditor
|
||||
script={task.tickscript}
|
||||
onChangeScript={onChangeScript}
|
||||
/>
|
||||
<TickscriptEditorConsole
|
||||
consoleMessage={consoleMessage}
|
||||
unsavedChanges={unsavedChanges}
|
||||
/>
|
||||
</div>
|
||||
{areLogsVisible ? <LogsTable logs={logs} /> : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const {arrayOf, bool, func, shape, string} = PropTypes
|
||||
|
||||
Tickscript.propTypes = {
|
||||
logs: arrayOf(shape()).isRequired,
|
||||
onSave: func.isRequired,
|
||||
onExit: func.isRequired,
|
||||
source: shape({
|
||||
id: string,
|
||||
}),
|
||||
areLogsVisible: bool,
|
||||
areLogsEnabled: bool,
|
||||
onToggleLogsVisibility: func.isRequired,
|
||||
task: shape({
|
||||
id: string,
|
||||
script: string,
|
||||
dbsrps: arrayOf(shape()),
|
||||
}).isRequired,
|
||||
onChangeScript: func.isRequired,
|
||||
onSelectDbrps: func.isRequired,
|
||||
consoleMessage: string,
|
||||
onChangeType: func.isRequired,
|
||||
onChangeID: func.isRequired,
|
||||
isNewTickscript: bool.isRequired,
|
||||
unsavedChanges: bool,
|
||||
}
|
||||
|
||||
export default Tickscript
|
|
@ -0,0 +1,101 @@
|
|||
import React, {PureComponent, MouseEvent, ChangeEvent} from 'react'
|
||||
|
||||
import TickscriptHeader from 'src/kapacitor/components/TickscriptHeader'
|
||||
import TickscriptEditor from 'src/kapacitor/components/TickscriptEditor'
|
||||
import TickscriptEditorControls from 'src/kapacitor/components/TickscriptEditorControls'
|
||||
import TickscriptEditorConsole from 'src/kapacitor/components/TickscriptEditorConsole'
|
||||
import LogsTable from 'src/kapacitor/components/LogsTable'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {Task} from 'src/types'
|
||||
import {LogItem, DBRP} from 'src/types/kapacitor'
|
||||
|
||||
interface Props {
|
||||
logs: LogItem[]
|
||||
onSave: () => void
|
||||
onExit: () => void
|
||||
areLogsVisible: boolean
|
||||
areLogsEnabled: boolean
|
||||
onToggleLogsVisibility: () => void
|
||||
task: Task
|
||||
onChangeScript: (tickscript: string) => void
|
||||
onSelectDbrps: (dbrps: DBRP[]) => void
|
||||
consoleMessage: string
|
||||
onChangeType: (type: string) => (event: MouseEvent<HTMLLIElement>) => void
|
||||
onChangeID: (e: ChangeEvent<HTMLInputElement>) => void
|
||||
isNewTickscript: boolean
|
||||
unsavedChanges: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class Tickscript extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
onSave,
|
||||
onExit,
|
||||
task,
|
||||
consoleMessage,
|
||||
onSelectDbrps,
|
||||
onChangeScript,
|
||||
onChangeType,
|
||||
onChangeID,
|
||||
unsavedChanges,
|
||||
isNewTickscript,
|
||||
areLogsVisible,
|
||||
areLogsEnabled,
|
||||
onToggleLogsVisibility,
|
||||
} = this.props
|
||||
return (
|
||||
<div className="page">
|
||||
<TickscriptHeader
|
||||
task={task}
|
||||
onSave={onSave}
|
||||
onExit={onExit}
|
||||
unsavedChanges={unsavedChanges}
|
||||
areLogsVisible={areLogsVisible}
|
||||
areLogsEnabled={areLogsEnabled}
|
||||
onToggleLogsVisibility={onToggleLogsVisibility}
|
||||
isNewTickscript={isNewTickscript}
|
||||
/>
|
||||
<div className="page-contents--split">
|
||||
<div className="tickscript" style={this.style}>
|
||||
<TickscriptEditorControls
|
||||
isNewTickscript={isNewTickscript}
|
||||
onSelectDbrps={onSelectDbrps}
|
||||
onChangeType={onChangeType}
|
||||
onChangeID={onChangeID}
|
||||
task={task}
|
||||
/>
|
||||
<TickscriptEditor
|
||||
script={task.tickscript}
|
||||
onChangeScript={onChangeScript}
|
||||
/>
|
||||
<TickscriptEditorConsole
|
||||
consoleMessage={consoleMessage}
|
||||
unsavedChanges={unsavedChanges}
|
||||
/>
|
||||
</div>
|
||||
{this.logsTable}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get style() {
|
||||
const {areLogsVisible} = this.props
|
||||
if (areLogsVisible) {
|
||||
return {maxWidth: '50%'}
|
||||
}
|
||||
}
|
||||
|
||||
private get logsTable() {
|
||||
const {areLogsVisible, logs} = this.props
|
||||
|
||||
if (areLogsVisible) {
|
||||
return <LogsTable logs={logs} />
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Tickscript
|
|
@ -1,20 +1,24 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import {Controlled as CodeMirror} from 'react-codemirror2'
|
||||
import 'src/external/codemirror'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
onChangeScript: (tickscript: string) => void
|
||||
script: string
|
||||
}
|
||||
|
||||
const NOOP = () => {}
|
||||
|
||||
@ErrorHandling
|
||||
class TickscriptEditor extends Component {
|
||||
class TickscriptEditor extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
updateCode = (_, __, script) => {
|
||||
this.props.onChangeScript(script)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {script} = this.props
|
||||
|
||||
const options = {
|
||||
|
@ -31,17 +35,15 @@ class TickscriptEditor extends Component {
|
|||
value={script}
|
||||
onBeforeChange={this.updateCode}
|
||||
options={options}
|
||||
onTouchStart={NOOP}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, string} = PropTypes
|
||||
|
||||
TickscriptEditor.propTypes = {
|
||||
onChangeScript: func,
|
||||
script: string,
|
||||
private updateCode = (_, __, script) => {
|
||||
this.props.onChangeScript(script)
|
||||
}
|
||||
}
|
||||
|
||||
export default TickscriptEditor
|
|
@ -1,7 +1,14 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const TickscriptEditorConsole = ({consoleMessage, unsavedChanges}) => {
|
||||
interface Props {
|
||||
consoleMessage: string
|
||||
unsavedChanges: boolean
|
||||
}
|
||||
|
||||
const TickscriptEditorConsole: SFC<Props> = ({
|
||||
consoleMessage,
|
||||
unsavedChanges,
|
||||
}) => {
|
||||
let consoleOutput = 'TICKscript is valid'
|
||||
let consoleClass = 'tickscript-console--valid'
|
||||
|
||||
|
@ -20,11 +27,4 @@ const TickscriptEditorConsole = ({consoleMessage, unsavedChanges}) => {
|
|||
)
|
||||
}
|
||||
|
||||
const {bool, string} = PropTypes
|
||||
|
||||
TickscriptEditorConsole.propTypes = {
|
||||
consoleMessage: string,
|
||||
unsavedChanges: bool,
|
||||
}
|
||||
|
||||
export default TickscriptEditorConsole
|
|
@ -1,48 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import TickscriptType from 'src/kapacitor/components/TickscriptType'
|
||||
import MultiSelectDBDropdown from 'shared/components/MultiSelectDBDropdown'
|
||||
import TickscriptID, {
|
||||
TickscriptStaticID,
|
||||
} from 'src/kapacitor/components/TickscriptID'
|
||||
|
||||
const addName = list => list.map(l => ({...l, name: `${l.db}.${l.rp}`}))
|
||||
|
||||
const TickscriptEditorControls = ({
|
||||
isNewTickscript,
|
||||
onSelectDbrps,
|
||||
onChangeType,
|
||||
onChangeID,
|
||||
task,
|
||||
}) => (
|
||||
<div className="tickscript-controls">
|
||||
{isNewTickscript ? (
|
||||
<TickscriptID onChangeID={onChangeID} id={task.id} />
|
||||
) : (
|
||||
<TickscriptStaticID id={task.name ? task.name : task.id} />
|
||||
)}
|
||||
<div className="tickscript-controls--right">
|
||||
<TickscriptType type={task.type} onChangeType={onChangeType} />
|
||||
<MultiSelectDBDropdown
|
||||
selectedItems={addName(task.dbrps)}
|
||||
onApply={onSelectDbrps}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const {arrayOf, bool, func, shape, string} = PropTypes
|
||||
|
||||
TickscriptEditorControls.propTypes = {
|
||||
isNewTickscript: bool.isRequired,
|
||||
onSelectDbrps: func.isRequired,
|
||||
onChangeType: func.isRequired,
|
||||
onChangeID: func.isRequired,
|
||||
task: shape({
|
||||
id: string,
|
||||
script: string,
|
||||
dbsrps: arrayOf(shape()),
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
export default TickscriptEditorControls
|
|
@ -0,0 +1,67 @@
|
|||
import React, {Component, MouseEvent, ChangeEvent} from 'react'
|
||||
|
||||
import TickscriptType from 'src/kapacitor/components/TickscriptType'
|
||||
import MultiSelectDBDropdown from 'src/shared/components/MultiSelectDBDropdown'
|
||||
import TickscriptID, {
|
||||
TickscriptStaticID,
|
||||
} from 'src/kapacitor/components/TickscriptID'
|
||||
|
||||
import {Task} from 'src/types'
|
||||
import {DBRP} from 'src/types/kapacitor'
|
||||
|
||||
interface DBRPDropdownItem extends DBRP {
|
||||
name: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
isNewTickscript: boolean
|
||||
onSelectDbrps: (dbrps: DBRP[]) => void
|
||||
onChangeType: (type: string) => (event: MouseEvent<HTMLLIElement>) => void
|
||||
onChangeID: (e: ChangeEvent<HTMLInputElement>) => void
|
||||
task: Task
|
||||
}
|
||||
|
||||
class TickscriptEditorControls extends Component<Props> {
|
||||
public render() {
|
||||
const {onSelectDbrps, onChangeType, task} = this.props
|
||||
return (
|
||||
<div className="tickscript-controls">
|
||||
{this.tickscriptID}
|
||||
<div className="tickscript-controls--right">
|
||||
<TickscriptType type={task.type} onChangeType={onChangeType} />
|
||||
<MultiSelectDBDropdown
|
||||
selectedItems={this.addName(task.dbrps)}
|
||||
onApply={onSelectDbrps}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get tickscriptID() {
|
||||
const {isNewTickscript, onChangeID, task} = this.props
|
||||
|
||||
if (isNewTickscript) {
|
||||
return <TickscriptID onChangeID={onChangeID} id={task.id} />
|
||||
}
|
||||
|
||||
return <TickscriptStaticID id={this.taskID} />
|
||||
}
|
||||
|
||||
private get taskID() {
|
||||
const {
|
||||
task: {name, id},
|
||||
} = this.props
|
||||
if (name) {
|
||||
return name
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
private addName = (list: DBRP[]): DBRPDropdownItem[] => {
|
||||
const listWithName = list.map(l => ({...l, name: `${l.db}.${l.rp}`}))
|
||||
return listWithName
|
||||
}
|
||||
}
|
||||
|
||||
export default TickscriptEditorControls
|
|
@ -1,14 +1,18 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {Component, SFC, ChangeEvent} from 'react'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface TickscriptIDProps {
|
||||
onChangeID: (e: ChangeEvent<HTMLInputElement>) => void
|
||||
id: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class TickscriptID extends Component {
|
||||
class TickscriptID extends Component<TickscriptIDProps> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {onChangeID, id} = this.props
|
||||
|
||||
return (
|
||||
|
@ -25,19 +29,11 @@ class TickscriptID extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export const TickscriptStaticID = ({id}) => (
|
||||
interface TickscriptStaticIDProps {
|
||||
id: string
|
||||
}
|
||||
export const TickscriptStaticID: SFC<TickscriptStaticIDProps> = ({id}) => (
|
||||
<h1 className="tickscript-controls--name">{id}</h1>
|
||||
)
|
||||
|
||||
const {func, string} = PropTypes
|
||||
|
||||
TickscriptID.propTypes = {
|
||||
onChangeID: func.isRequired,
|
||||
id: string.isRequired,
|
||||
}
|
||||
|
||||
TickscriptStaticID.propTypes = {
|
||||
id: string.isRequired,
|
||||
}
|
||||
|
||||
export default TickscriptID
|
|
@ -1,30 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
const STREAM = 'stream'
|
||||
const BATCH = 'batch'
|
||||
|
||||
const TickscriptType = ({type, onChangeType}) => (
|
||||
<ul className="nav nav-tablist nav-tablist-sm">
|
||||
<li
|
||||
className={type === STREAM ? 'active' : ''}
|
||||
onClick={onChangeType(STREAM)}
|
||||
>
|
||||
Stream
|
||||
</li>
|
||||
<li
|
||||
className={type === BATCH ? 'active' : ''}
|
||||
onClick={onChangeType(BATCH)}
|
||||
>
|
||||
Batch
|
||||
</li>
|
||||
</ul>
|
||||
)
|
||||
|
||||
const {string, func} = PropTypes
|
||||
|
||||
TickscriptType.propTypes = {
|
||||
type: string,
|
||||
onChangeType: func,
|
||||
}
|
||||
|
||||
export default TickscriptType
|
|
@ -0,0 +1,40 @@
|
|||
import React, {PureComponent, MouseEvent} from 'react'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
type: string
|
||||
onChangeType: (type: string) => (event: MouseEvent<HTMLLIElement>) => void
|
||||
}
|
||||
|
||||
const STREAM = 'stream'
|
||||
const BATCH = 'batch'
|
||||
|
||||
@ErrorHandling
|
||||
class TickscriptType extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {onChangeType} = this.props
|
||||
return (
|
||||
<ul className="nav nav-tablist nav-tablist-sm">
|
||||
<li
|
||||
className={this.getClassName(STREAM)}
|
||||
onClick={onChangeType(STREAM)}
|
||||
>
|
||||
Stream
|
||||
</li>
|
||||
<li className={this.getClassName(BATCH)} onClick={onChangeType(BATCH)}>
|
||||
Batch
|
||||
</li>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
private getClassName(type: string) {
|
||||
if (type === this.props.type) {
|
||||
return 'active'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export default TickscriptType
|
|
@ -1,6 +1,4 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import React, {SFC, ChangeEvent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
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 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']
|
||||
|
||||
|
@ -22,13 +29,36 @@ const handleChooseTrigger = (rule, onChooseTrigger) => triggerIndex => {
|
|||
const initialIndex = rule => TABS.indexOf(_.startCase(rule.trigger))
|
||||
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,
|
||||
query,
|
||||
source,
|
||||
timeRange,
|
||||
onAddEvery,
|
||||
onRemoveEvery,
|
||||
onChooseTrigger,
|
||||
onDeadmanChange,
|
||||
onChooseTimeRange,
|
||||
|
@ -58,7 +88,6 @@ const ValuesSection = ({
|
|||
isKapacitorRule={true}
|
||||
actions={queryConfigActions}
|
||||
onAddEvery={onAddEvery}
|
||||
onRemoveEvery={onRemoveEvery}
|
||||
isDeadman={isDeadman(rule)}
|
||||
/>
|
||||
</div>
|
||||
|
@ -97,24 +126,4 @@ const ValuesSection = ({
|
|||
</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
|
|
@ -1,26 +1,59 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
||||
import * as kapacitorQueryConfigActionCreators from 'src/kapacitor/actions/queryConfigs'
|
||||
|
||||
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 KapacitorRule from 'src/kapacitor/components/KapacitorRule'
|
||||
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 {
|
||||
notifyKapacitorCreateFailed,
|
||||
notifyCouldNotFindKapacitor,
|
||||
} from 'shared/copy/notifications'
|
||||
} from 'src/shared/copy/notifications'
|
||||
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
|
||||
class KapacitorRulePage extends Component {
|
||||
constructor(props) {
|
||||
class KapacitorRulePage extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
@ -29,7 +62,7 @@ class KapacitorRulePage extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
public async componentDidMount() {
|
||||
const {params, source, ruleActions, notify} = this.props
|
||||
|
||||
if (params.ruleID === 'new') {
|
||||
|
@ -54,9 +87,8 @@ class KapacitorRulePage extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {
|
||||
rules,
|
||||
params,
|
||||
source,
|
||||
router,
|
||||
|
@ -65,8 +97,7 @@ class KapacitorRulePage extends Component {
|
|||
queryConfigActions,
|
||||
} = this.props
|
||||
const {handlersFromConfig, kapacitor} = this.state
|
||||
const rule =
|
||||
params.ruleID === 'new' ? rules[DEFAULT_RULE_ID] : rules[params.ruleID]
|
||||
const rule = this.rule
|
||||
const query = rule && queryConfigs[rule.queryID]
|
||||
|
||||
if (!query) {
|
||||
|
@ -84,41 +115,26 @@ class KapacitorRulePage extends Component {
|
|||
ruleID={params.ruleID}
|
||||
router={router}
|
||||
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 = {
|
||||
source: shape({
|
||||
links: shape({
|
||||
proxy: string.isRequired,
|
||||
self: string.isRequired,
|
||||
}),
|
||||
}),
|
||||
notify: func,
|
||||
rules: shape({}).isRequired,
|
||||
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,
|
||||
private get rule(): AlertRule {
|
||||
const {params, rules} = this.props
|
||||
const ruleID = _.get(params, 'ruleID')
|
||||
|
||||
if (ruleID === 'new') {
|
||||
return rules[DEFAULT_RULE_ID]
|
||||
}
|
||||
|
||||
return rules[params.ruleID]
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({rules, kapacitorQueryConfigs: queryConfigs}) => ({
|
|
@ -1,4 +1,4 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import uuid from 'uuid'
|
||||
|
@ -18,7 +18,7 @@ import {
|
|||
Notification,
|
||||
NotificationFunc,
|
||||
} from 'src/types'
|
||||
|
||||
import {LogItem, DBRP} from 'src/types/kapacitor'
|
||||
import {
|
||||
notifyTickscriptLoggingUnavailable,
|
||||
notifyTickscriptLoggingError,
|
||||
|
@ -76,7 +76,7 @@ interface State {
|
|||
task: Task
|
||||
consoleMessage: string
|
||||
isEditingID: boolean
|
||||
logs: object[]
|
||||
logs: LogItem[]
|
||||
areLogsVisible: boolean
|
||||
areLogsEnabled: boolean
|
||||
failStr: string
|
||||
|
@ -247,22 +247,22 @@ export class TickscriptPage extends PureComponent<Props, State> {
|
|||
return router.push(`/sources/${sourceID}/alert-rules`)
|
||||
}
|
||||
|
||||
private handleChangeScript = tickscript => {
|
||||
private handleChangeScript = (tickscript: string) => {
|
||||
this.setState({
|
||||
task: {...this.state.task, tickscript},
|
||||
unsavedChanges: true,
|
||||
})
|
||||
}
|
||||
|
||||
private handleSelectDbrps = dbrps => {
|
||||
private handleSelectDbrps = (dbrps: DBRP[]) => {
|
||||
this.setState({task: {...this.state.task, dbrps}, unsavedChanges: true})
|
||||
}
|
||||
|
||||
private handleChangeType = type => () => {
|
||||
private handleChangeType = (type: string) => () => {
|
||||
this.setState({task: {...this.state.task, type}, unsavedChanges: true})
|
||||
}
|
||||
|
||||
private handleChangeID = e => {
|
||||
private handleChangeID = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
task: {...this.state.task, id: e.target.value},
|
||||
unsavedChanges: true,
|
||||
|
|
|
@ -48,7 +48,7 @@ interface TabListProps {
|
|||
activeIndex?: number
|
||||
onActivate?: (index: number) => void
|
||||
isKapacitorTabs?: string
|
||||
customClass: string
|
||||
customClass?: string
|
||||
}
|
||||
|
||||
export const TabList: SFC<TabListProps> = ({
|
||||
|
@ -97,7 +97,7 @@ TabList.defaultProps = {
|
|||
interface TabPanelsProps {
|
||||
children: JSX.Element[] | JSX.Element
|
||||
activeIndex?: number
|
||||
customClass: string
|
||||
customClass?: string
|
||||
}
|
||||
|
||||
export const TabPanels: SFC<TabPanelsProps> = ({
|
||||
|
@ -120,7 +120,7 @@ export const TabPanel: SFC<TabPanelProps> = ({children}) => (
|
|||
interface TabsProps {
|
||||
children: JSX.Element[] | JSX.Element
|
||||
onSelect?: (activeIndex: number) => void
|
||||
tabContentsClass: string
|
||||
tabContentsClass?: string
|
||||
tabsClass?: string
|
||||
initialIndex?: number
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import * as kapacitorQueryConfigActions from 'src/kapacitor/actions/queryConfigs'
|
||||
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
||||
|
||||
type KapacitorQueryConfigActions = typeof kapacitorQueryConfigActions
|
||||
type KapacitorRuleActions = typeof kapacitorRuleActionCreators
|
||||
|
||||
export {KapacitorQueryConfigActions}
|
||||
export {KapacitorRuleActions}
|
||||
|
|
|
@ -32,6 +32,7 @@ export interface AlertRule {
|
|||
error: string
|
||||
created: string
|
||||
modified: string
|
||||
queryID?: string
|
||||
'last-enabled'?: string
|
||||
}
|
||||
|
||||
|
@ -186,7 +187,7 @@ interface OpsGenie {
|
|||
}
|
||||
|
||||
// Talk sends alerts to Jane Talk (https://jianliao.com/site)
|
||||
interface Talk {} // tslint:disable-line
|
||||
interface Talk { } // tslint:disable-line
|
||||
|
||||
// TriggerValues specifies the alerting logic for a specific trigger type
|
||||
interface TriggerValues {
|
||||
|
@ -224,7 +225,7 @@ export interface RuleMessageTemplate {
|
|||
time: RuleMessage
|
||||
}
|
||||
|
||||
interface RuleMessage {
|
||||
export interface RuleMessage {
|
||||
label: string
|
||||
text: string
|
||||
}
|
||||
|
@ -411,3 +412,20 @@ export interface RuleValues {
|
|||
rangeValue?: string | null
|
||||
operator?: string
|
||||
}
|
||||
|
||||
export interface LogItem {
|
||||
key: string
|
||||
service: string
|
||||
lvl: string
|
||||
ts: string
|
||||
msg: string
|
||||
id: string
|
||||
tags: string
|
||||
method?: string
|
||||
username?: string
|
||||
host?: string
|
||||
duration?: string
|
||||
tag?: object
|
||||
field?: object
|
||||
cluster?: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue