Merge pull request #3369 from influxdata/feature/opsgenie-v2
Add OpsGenie v2 support to UIpull/10616/head
commit
cd850f5280
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
1. [#3233](https://github.com/influxdata/chronograf/pull/3233): Add default retention policy field as option in source configuration for use in querying hosts from Host List page & Host pages
|
1. [#3233](https://github.com/influxdata/chronograf/pull/3233): Add default retention policy field as option in source configuration for use in querying hosts from Host List page & Host pages
|
||||||
1. [#3290](https://github.com/influxdata/chronograf/pull/3290): Add support for PagerDuty v2 in UI
|
1. [#3290](https://github.com/influxdata/chronograf/pull/3290): Add support for PagerDuty v2 in UI
|
||||||
|
1. [#3369](https://github.com/influxdata/chronograf/pull/3369): Add support for OpsGenie v2 in UI
|
||||||
|
|
||||||
### UI Improvements
|
### UI Improvements
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@
|
||||||
"tick/stateful",
|
"tick/stateful",
|
||||||
"udf/agent"
|
"udf/agent"
|
||||||
]
|
]
|
||||||
revision = "97e77198c3f4a16503110979f066bc3a4f9adc49"
|
revision = "761f380db46c20bb24f9bf3dbdd89c2661dc0c2b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -311,6 +311,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "00da66795f1ffe85f031f7fbd69e5974a72167895057a43ba4187cfa84efe3b5"
|
inputs-digest = "22ca158a5cab9595de1d2604e9cf063e271759528e70b36e1b7e643ec138078e"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -78,4 +78,4 @@ required = ["github.com/kevinburke/go-bindata","github.com/gogo/protobuf/proto",
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/influxdata/kapacitor"
|
name = "github.com/influxdata/kapacitor"
|
||||||
revision = "97e77198c3f4a16503110979f066bc3a4f9adc49"
|
revision = "761f380db46c20bb24f9bf3dbdd89c2661dc0c2b"
|
||||||
|
|
|
@ -21,6 +21,7 @@ type AlertNodes struct {
|
||||||
HipChat []*HipChat `json:"hipChat"` // HipChat will send alert to all HipChat
|
HipChat []*HipChat `json:"hipChat"` // HipChat will send alert to all HipChat
|
||||||
Alerta []*Alerta `json:"alerta"` // Alerta will send alert to all Alerta
|
Alerta []*Alerta `json:"alerta"` // Alerta will send alert to all Alerta
|
||||||
OpsGenie []*OpsGenie `json:"opsGenie"` // OpsGenie will send alert to all OpsGenie
|
OpsGenie []*OpsGenie `json:"opsGenie"` // OpsGenie will send alert to all OpsGenie
|
||||||
|
OpsGenie2 []*OpsGenie `json:"opsGenie2"` // OpsGenie2 will send alert to all OpsGenie v2
|
||||||
Talk []*Talk `json:"talk"` // Talk will send alert to all Talk
|
Talk []*Talk `json:"talk"` // Talk will send alert to all Talk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -429,6 +429,22 @@ func newAlertResponse(task *kapa.Task, srcID, kapaID int) *alertResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if res.AlertNodes.OpsGenie2 == nil {
|
||||||
|
res.AlertNodes.OpsGenie2 = []*chronograf.OpsGenie{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, a := range res.AlertNodes.OpsGenie2 {
|
||||||
|
if a.Teams == nil {
|
||||||
|
a.Teams = []string{}
|
||||||
|
res.AlertNodes.OpsGenie2[i] = a
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Recipients == nil {
|
||||||
|
a.Recipients = []string{}
|
||||||
|
res.AlertNodes.OpsGenie2[i] = a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if res.AlertNodes.PagerDuty == nil {
|
if res.AlertNodes.PagerDuty == nil {
|
||||||
res.AlertNodes.PagerDuty = []*chronograf.PagerDuty{}
|
res.AlertNodes.PagerDuty = []*chronograf.PagerDuty{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,7 @@ func Test_KapacitorRulesGet(t *testing.T) {
|
||||||
HipChat: []*chronograf.HipChat{},
|
HipChat: []*chronograf.HipChat{},
|
||||||
Alerta: []*chronograf.Alerta{},
|
Alerta: []*chronograf.Alerta{},
|
||||||
OpsGenie: []*chronograf.OpsGenie{},
|
OpsGenie: []*chronograf.OpsGenie{},
|
||||||
|
OpsGenie2: []*chronograf.OpsGenie{},
|
||||||
Talk: []*chronograf.Talk{},
|
Talk: []*chronograf.Talk{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
import React, {Component} from 'react'
|
import React, {PureComponent, MouseEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import {Tab, Tabs, TabPanel, TabPanels, TabList} from 'shared/components/Tabs'
|
import {
|
||||||
|
Tab,
|
||||||
|
Tabs,
|
||||||
|
TabPanel,
|
||||||
|
TabPanels,
|
||||||
|
TabList,
|
||||||
|
} from 'src/shared/components/Tabs'
|
||||||
import {
|
import {
|
||||||
getKapacitorConfig,
|
getKapacitorConfig,
|
||||||
updateKapacitorConfigSection,
|
updateKapacitorConfigSection,
|
||||||
testAlertOutput,
|
testAlertOutput,
|
||||||
getAllServices,
|
getAllServices,
|
||||||
} from 'shared/apis'
|
} from 'src/shared/apis'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AlertaConfig,
|
AlertaConfig,
|
||||||
|
@ -32,12 +37,100 @@ import {
|
||||||
notifyTestAlertSent,
|
notifyTestAlertSent,
|
||||||
notifyTestAlertFailed,
|
notifyTestAlertFailed,
|
||||||
notifyCouldNotRetrieveKapacitorServices,
|
notifyCouldNotRetrieveKapacitorServices,
|
||||||
} from 'shared/copy/notifications'
|
} from 'src/shared/copy/notifications'
|
||||||
import DeprecationWarning from 'src/admin/components/DeprecationWarning'
|
import DeprecationWarning from 'src/admin/components/DeprecationWarning'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {Source, Kapacitor} from 'src/types'
|
||||||
|
|
||||||
|
interface Service {
|
||||||
|
link: Link
|
||||||
|
name: string
|
||||||
|
options: {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Link {
|
||||||
|
rel: string
|
||||||
|
href: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Element {
|
||||||
|
link: Link
|
||||||
|
options: any
|
||||||
|
redacted: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Section {
|
||||||
|
link: string
|
||||||
|
elements: Element[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Sections {
|
||||||
|
alerta: Section
|
||||||
|
hipchat: Section
|
||||||
|
httppost: Section
|
||||||
|
influxdb: Section
|
||||||
|
mqtt: Section
|
||||||
|
opsgenie: Section
|
||||||
|
opsgenie2: Section
|
||||||
|
pagerduty: Section
|
||||||
|
pagerduty2: Section
|
||||||
|
pushover: Section
|
||||||
|
sensu: Section
|
||||||
|
slack: Section
|
||||||
|
smtp: Section
|
||||||
|
snmptrap: Section
|
||||||
|
talk: Section
|
||||||
|
telegram: Section
|
||||||
|
victorops: Section
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Config {
|
||||||
|
type: string
|
||||||
|
enabled: boolean
|
||||||
|
renderComponent: () => JSX.Element
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SupportedConfig {
|
||||||
|
alerta: Config
|
||||||
|
hipchat: Config
|
||||||
|
opsgenie: Config
|
||||||
|
opsgenie2: Config
|
||||||
|
pagerduty: Config
|
||||||
|
pagerduty2: Config
|
||||||
|
pushover: Config
|
||||||
|
sensu: Config
|
||||||
|
slack: Config
|
||||||
|
smtp: Config
|
||||||
|
talk: Config
|
||||||
|
telegram: Config
|
||||||
|
victorops: Config
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Notification {
|
||||||
|
id?: string
|
||||||
|
type: string
|
||||||
|
icon: string
|
||||||
|
duration: number
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
source: Source
|
||||||
|
kapacitor: Kapacitor
|
||||||
|
notify: (message: Notification) => void
|
||||||
|
hash: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
configSections: Sections
|
||||||
|
services: Service[]
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class AlertTabs extends Component {
|
class AlertTabs extends PureComponent<Props, State> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
|
@ -47,11 +140,11 @@ class AlertTabs extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
public async componentDidMount() {
|
||||||
const {kapacitor} = this.props
|
const {kapacitor} = this.props
|
||||||
try {
|
try {
|
||||||
this.refreshKapacitorConfig(kapacitor)
|
this.refreshKapacitorConfig(kapacitor)
|
||||||
const services = await getAllServices(kapacitor)
|
const services: Service[] = await getAllServices(kapacitor)
|
||||||
this.setState({services})
|
this.setState({services})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.setState({services: null})
|
this.setState({services: null})
|
||||||
|
@ -59,106 +152,13 @@ class AlertTabs extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
public componentWillReceiveProps(nextProps) {
|
||||||
if (this.props.kapacitor.url !== nextProps.kapacitor.url) {
|
if (this.props.kapacitor.url !== nextProps.kapacitor.url) {
|
||||||
this.refreshKapacitorConfig(nextProps.kapacitor)
|
this.refreshKapacitorConfig(nextProps.kapacitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshKapacitorConfig = async kapacitor => {
|
public render() {
|
||||||
try {
|
|
||||||
const {
|
|
||||||
data: {sections},
|
|
||||||
} = await getKapacitorConfig(kapacitor)
|
|
||||||
this.setState({configSections: sections})
|
|
||||||
} catch (error) {
|
|
||||||
this.setState({configSections: null})
|
|
||||||
this.props.notify(notifyRefreshKapacitorFailed())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSection = (sections, section) => {
|
|
||||||
return _.get(sections, [section, 'elements', '0'], null)
|
|
||||||
}
|
|
||||||
|
|
||||||
getEnabled = (sections, section) => {
|
|
||||||
return _.get(
|
|
||||||
sections,
|
|
||||||
[section, 'elements', '0', 'options', 'enabled'],
|
|
||||||
null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleGetSection = (sections, section) => () => {
|
|
||||||
return this.getSection(sections, section)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSaveConfig = section => async properties => {
|
|
||||||
if (section !== '') {
|
|
||||||
const propsToSend = this.sanitizeProperties(section, properties)
|
|
||||||
try {
|
|
||||||
await updateKapacitorConfigSection(
|
|
||||||
this.props.kapacitor,
|
|
||||||
section,
|
|
||||||
propsToSend
|
|
||||||
)
|
|
||||||
this.refreshKapacitorConfig(this.props.kapacitor)
|
|
||||||
this.props.notify(notifyAlertEndpointSaved(section))
|
|
||||||
return true
|
|
||||||
} catch ({
|
|
||||||
data: {error},
|
|
||||||
}) {
|
|
||||||
const errorMsg = _.join(_.drop(_.split(error, ': '), 2), ': ')
|
|
||||||
this.props.notify(notifyAlertEndpointSaveFailed(section, errorMsg))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTestConfig = section => async e => {
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
try {
|
|
||||||
const {data} = await testAlertOutput(this.props.kapacitor, section)
|
|
||||||
if (data.success) {
|
|
||||||
this.props.notify(notifyTestAlertSent(section))
|
|
||||||
} else {
|
|
||||||
this.props.notify(notifyTestAlertFailed(section, data.message))
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.props.notify(notifyTestAlertFailed(section))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sanitizeProperties = (section, properties) => {
|
|
||||||
const cleanProps = {...properties, enabled: true}
|
|
||||||
const {redacted} = this.getSection(this.state.configSections, section)
|
|
||||||
if (redacted && redacted.length) {
|
|
||||||
redacted.forEach(badProp => {
|
|
||||||
if (properties[badProp] === 'true') {
|
|
||||||
delete cleanProps[badProp]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return cleanProps
|
|
||||||
}
|
|
||||||
|
|
||||||
getInitialIndex = (supportedConfigs, hash) => {
|
|
||||||
const index = _.indexOf(_.keys(supportedConfigs), _.replace(hash, '#', ''))
|
|
||||||
return index >= 0 ? index : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
isSupportedService = config => {
|
|
||||||
return (
|
|
||||||
config &&
|
|
||||||
this.state.services.find(service => {
|
|
||||||
return service.name === _.toLower(config.type)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {configSections} = this.state
|
const {configSections} = this.state
|
||||||
const {hash} = this.props
|
const {hash} = this.props
|
||||||
|
|
||||||
|
@ -166,9 +166,16 @@ class AlertTabs extends Component {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const pagerDutyV1Enabled = this.getEnabled(configSections, 'pagerduty')
|
const pagerDutyV1Enabled: boolean = this.getEnabled(
|
||||||
const showDeprecation = pagerDutyV1Enabled
|
configSections,
|
||||||
const pagerDutyDeprecationMessage = (
|
'pagerduty'
|
||||||
|
)
|
||||||
|
const opsGenieV1Enabled: boolean = this.getEnabled(
|
||||||
|
configSections,
|
||||||
|
'opsgenie'
|
||||||
|
)
|
||||||
|
|
||||||
|
const pagerDutyDeprecationMessage: JSX.Element = (
|
||||||
<div>
|
<div>
|
||||||
PagerDuty v1 is being{' '}
|
PagerDuty v1 is being{' '}
|
||||||
{
|
{
|
||||||
|
@ -183,7 +190,14 @@ class AlertTabs extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const supportedConfigs = {
|
const opsGenieDeprecationMessage: JSX.Element = (
|
||||||
|
<div>
|
||||||
|
OpsGenie v1 is being deprecated. Please update your Kapacitor and
|
||||||
|
configure OpsGenie v2.
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const supportedConfigs: SupportedConfig = {
|
||||||
alerta: {
|
alerta: {
|
||||||
type: 'Alerta',
|
type: 'Alerta',
|
||||||
enabled: this.getEnabled(configSections, 'alerta'),
|
enabled: this.getEnabled(configSections, 'alerta'),
|
||||||
|
@ -220,6 +234,18 @@ class AlertTabs extends Component {
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
opsgenie2: {
|
||||||
|
type: 'OpsGenie2',
|
||||||
|
enabled: this.getEnabled(configSections, 'opsgenie2'),
|
||||||
|
renderComponent: () => (
|
||||||
|
<OpsGenieConfig
|
||||||
|
onSave={this.handleSaveConfig('opsgenie2')}
|
||||||
|
config={this.getSection(configSections, 'opsgenie2')}
|
||||||
|
onTest={this.handleTestConfig('opsgenie2')}
|
||||||
|
enabled={this.getEnabled(configSections, 'opsgenie2')}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
pagerduty: {
|
pagerduty: {
|
||||||
type: 'PagerDuty',
|
type: 'PagerDuty',
|
||||||
enabled: this.getEnabled(configSections, 'pagerduty'),
|
enabled: this.getEnabled(configSections, 'pagerduty'),
|
||||||
|
@ -334,9 +360,12 @@ class AlertTabs extends Component {
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<h2 className="panel-title">Configure Alert Endpoints</h2>
|
<h2 className="panel-title">Configure Alert Endpoints</h2>
|
||||||
</div>
|
</div>
|
||||||
{showDeprecation && (
|
{pagerDutyV1Enabled && (
|
||||||
<DeprecationWarning message={pagerDutyDeprecationMessage} />
|
<DeprecationWarning message={pagerDutyDeprecationMessage} />
|
||||||
)}
|
)}
|
||||||
|
{opsGenieV1Enabled && (
|
||||||
|
<DeprecationWarning message={opsGenieDeprecationMessage} />
|
||||||
|
)}
|
||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
tabContentsClass="config-endpoint"
|
tabContentsClass="config-endpoint"
|
||||||
|
@ -345,7 +374,7 @@ class AlertTabs extends Component {
|
||||||
<TabList customClass="config-endpoint--tabs">
|
<TabList customClass="config-endpoint--tabs">
|
||||||
{_.reduce(
|
{_.reduce(
|
||||||
configSections,
|
configSections,
|
||||||
(acc, _cur, k) => {
|
(acc, __, k) => {
|
||||||
return this.isSupportedService(supportedConfigs[k])
|
return this.isSupportedService(supportedConfigs[k])
|
||||||
? acc.concat(
|
? acc.concat(
|
||||||
<Tab
|
<Tab
|
||||||
|
@ -363,7 +392,7 @@ class AlertTabs extends Component {
|
||||||
<TabPanels customClass="config-endpoint--tab-contents">
|
<TabPanels customClass="config-endpoint--tab-contents">
|
||||||
{_.reduce(
|
{_.reduce(
|
||||||
configSections,
|
configSections,
|
||||||
(acc, _cur, k) =>
|
(acc, __, k) =>
|
||||||
this.isSupportedService(supportedConfigs[k])
|
this.isSupportedService(supportedConfigs[k])
|
||||||
? acc.concat(
|
? acc.concat(
|
||||||
<TabPanel key={supportedConfigs[k].type}>
|
<TabPanel key={supportedConfigs[k].type}>
|
||||||
|
@ -378,22 +407,103 @@ class AlertTabs extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, shape, string} = PropTypes
|
private refreshKapacitorConfig = async (
|
||||||
|
kapacitor: Kapacitor
|
||||||
|
): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
data: {sections},
|
||||||
|
} = await getKapacitorConfig(kapacitor)
|
||||||
|
this.setState({configSections: sections})
|
||||||
|
} catch (error) {
|
||||||
|
this.setState({configSections: null})
|
||||||
|
this.props.notify(notifyRefreshKapacitorFailed())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AlertTabs.propTypes = {
|
private getSection = (sections: Sections, section: string): Element => {
|
||||||
source: shape({
|
return _.get(sections, [section, 'elements', '0'], null)
|
||||||
id: string.isRequired,
|
}
|
||||||
}).isRequired,
|
|
||||||
kapacitor: shape({
|
private getEnabled = (sections: Sections, section: string): boolean => {
|
||||||
url: string.isRequired,
|
return _.get(
|
||||||
links: shape({
|
sections,
|
||||||
proxy: string.isRequired,
|
[section, 'elements', '0', 'options', 'enabled'],
|
||||||
}).isRequired,
|
null
|
||||||
}),
|
)
|
||||||
notify: func.isRequired,
|
}
|
||||||
hash: string.isRequired,
|
|
||||||
|
private handleSaveConfig = (section: string) => async (
|
||||||
|
properties
|
||||||
|
): Promise<boolean> => {
|
||||||
|
if (section !== '') {
|
||||||
|
const propsToSend = this.sanitizeProperties(section, properties)
|
||||||
|
try {
|
||||||
|
await updateKapacitorConfigSection(
|
||||||
|
this.props.kapacitor,
|
||||||
|
section,
|
||||||
|
propsToSend
|
||||||
|
)
|
||||||
|
this.refreshKapacitorConfig(this.props.kapacitor)
|
||||||
|
this.props.notify(notifyAlertEndpointSaved(section))
|
||||||
|
return true
|
||||||
|
} catch ({
|
||||||
|
data: {error},
|
||||||
|
}) {
|
||||||
|
const errorMsg = _.join(_.drop(_.split(error, ': '), 2), ': ')
|
||||||
|
this.props.notify(notifyAlertEndpointSaveFailed(section, errorMsg))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private handleTestConfig = (section: string) => async (
|
||||||
|
e: MouseEvent<HTMLButtonElement>
|
||||||
|
): Promise<void> => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {data} = await testAlertOutput(this.props.kapacitor, section)
|
||||||
|
if (data.success) {
|
||||||
|
this.props.notify(notifyTestAlertSent(section))
|
||||||
|
} else {
|
||||||
|
this.props.notify(notifyTestAlertFailed(section, data.message))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.props.notify(notifyTestAlertFailed(section))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sanitizeProperties = (section: string, properties: Props): Props => {
|
||||||
|
const cleanProps = {...properties, enabled: true}
|
||||||
|
const {redacted} = this.getSection(this.state.configSections, section)
|
||||||
|
if (redacted && redacted.length) {
|
||||||
|
redacted.forEach(badProp => {
|
||||||
|
if (properties[badProp] === 'true') {
|
||||||
|
delete cleanProps[badProp]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleanProps
|
||||||
|
}
|
||||||
|
|
||||||
|
private getInitialIndex = (
|
||||||
|
supportedConfigs: SupportedConfig,
|
||||||
|
hash: string
|
||||||
|
): number => {
|
||||||
|
const index = _.indexOf(_.keys(supportedConfigs), _.replace(hash, '#', ''))
|
||||||
|
return index >= 0 ? index : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSupportedService = config => {
|
||||||
|
return (
|
||||||
|
config &&
|
||||||
|
this.state.services.find(service => {
|
||||||
|
return service.name === _.toLower(config.type)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AlertTabs
|
export default AlertTabs
|
|
@ -101,6 +101,15 @@ class HandlerOptions extends Component {
|
||||||
validationError={validationError}
|
validationError={validationError}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
case 'opsGenie2':
|
||||||
|
return (
|
||||||
|
<OpsgenieHandler
|
||||||
|
selectedHandler={selectedHandler}
|
||||||
|
handleModifyHandler={handleModifyHandler}
|
||||||
|
onGoToConfig={onGoToConfig('opsgenie2')}
|
||||||
|
validationError={validationError}
|
||||||
|
/>
|
||||||
|
)
|
||||||
case 'pagerDuty':
|
case 'pagerDuty':
|
||||||
return (
|
return (
|
||||||
<PagerdutyHandler
|
<PagerdutyHandler
|
||||||
|
|
|
@ -46,6 +46,7 @@ class AlertaConfig extends PureComponent<Props, State> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {environment, origin, token, url} = this.props.config.options
|
const {environment, origin, token, url} = this.props.config.options
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
@ -80,6 +81,7 @@ class AlertaConfig extends PureComponent<Props, State> {
|
||||||
id="token"
|
id="token"
|
||||||
refFunc={this.handleTokenRef}
|
refFunc={this.handleTokenRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ class HipchatConfig extends PureComponent<Props, State> {
|
||||||
public render() {
|
public render() {
|
||||||
const {options} = this.props.config
|
const {options} = this.props.config
|
||||||
const {url, room, token} = options
|
const {url, room, token} = options
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
const subdomain = url
|
const subdomain = url
|
||||||
.replace('https://', '')
|
.replace('https://', '')
|
||||||
|
@ -89,6 +90,7 @@ class HipchatConfig extends PureComponent<Props, State> {
|
||||||
id="token"
|
id="token"
|
||||||
refFunc={this.handleTokenRef}
|
refFunc={this.handleTokenRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ class OpsGenieConfig extends PureComponent<Props, State> {
|
||||||
public render() {
|
public render() {
|
||||||
const {options} = this.props.config
|
const {options} = this.props.config
|
||||||
const apiKey = options['api-key']
|
const apiKey = options['api-key']
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
@ -64,6 +65,7 @@ class OpsGenieConfig extends PureComponent<Props, State> {
|
||||||
id="api-key"
|
id="api-key"
|
||||||
refFunc={this.handleApiKeyRef}
|
refFunc={this.handleApiKeyRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ class PagerDutyConfig extends PureComponent<Props, State> {
|
||||||
const {options} = this.props.config
|
const {options} = this.props.config
|
||||||
const {url} = options
|
const {url} = options
|
||||||
const serviceKey = options['service-key']
|
const serviceKey = options['service-key']
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
<div className="form-group col-xs-12">
|
<div className="form-group col-xs-12">
|
||||||
|
@ -50,6 +52,7 @@ class PagerDutyConfig extends PureComponent<Props, State> {
|
||||||
id="service-key"
|
id="service-key"
|
||||||
refFunc={this.handleServiceKeyRef}
|
refFunc={this.handleServiceKeyRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ class PushoverConfig extends PureComponent<Props, State> {
|
||||||
const {options} = this.props.config
|
const {options} = this.props.config
|
||||||
const {token, url} = options
|
const {token, url} = options
|
||||||
const userKey = options['user-key']
|
const userKey = options['user-key']
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
@ -64,6 +65,7 @@ class PushoverConfig extends PureComponent<Props, State> {
|
||||||
id="user-key"
|
id="user-key"
|
||||||
refFunc={this.handleUserKeyRef}
|
refFunc={this.handleUserKeyRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -80,6 +82,7 @@ class PushoverConfig extends PureComponent<Props, State> {
|
||||||
id="token"
|
id="token"
|
||||||
refFunc={this.handleTokenRef}
|
refFunc={this.handleTokenRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ interface Props {
|
||||||
defaultValue?: boolean
|
defaultValue?: boolean
|
||||||
refFunc: (r: any) => void
|
refFunc: (r: any) => void
|
||||||
disableTest?: () => void
|
disableTest?: () => void
|
||||||
|
isFormEditing: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
@ -21,6 +22,12 @@ class RedactedInput extends PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public componentWillReceiveProps(nextProps) {
|
||||||
|
if (!nextProps.isFormEditing) {
|
||||||
|
this.setState({editing: false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {defaultValue, id, refFunc, disableTest} = this.props
|
const {defaultValue, id, refFunc, disableTest} = this.props
|
||||||
const {editing} = this.state
|
const {editing} = this.state
|
||||||
|
@ -31,9 +38,9 @@ class RedactedInput extends PureComponent<Props, State> {
|
||||||
<span className="alert-value-set">
|
<span className="alert-value-set">
|
||||||
<span className="icon checkmark" /> Value set
|
<span className="icon checkmark" /> Value set
|
||||||
</span>
|
</span>
|
||||||
<button className="btn btn-xs btn-link" onClick={this.handleClick}>
|
<div className="btn btn-xs btn-link" onClick={this.handleClick}>
|
||||||
Change
|
Change
|
||||||
</button>
|
</div>
|
||||||
<input
|
<input
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id={id}
|
id={id}
|
||||||
|
|
|
@ -39,6 +39,7 @@ class SlackConfig extends PureComponent<Props, State> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {url, channel} = this.props.config.options
|
const {url, channel} = this.props.config.options
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
@ -55,6 +56,7 @@ class SlackConfig extends PureComponent<Props, State> {
|
||||||
id="url"
|
id="url"
|
||||||
refFunc={this.handleUrlRef}
|
refFunc={this.handleUrlRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ class TalkConfig extends PureComponent<Props, State> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {url, author_name: author} = this.props.config.options
|
const {url, author_name: author} = this.props.config.options
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
@ -50,6 +51,7 @@ class TalkConfig extends PureComponent<Props, State> {
|
||||||
id="url"
|
id="url"
|
||||||
refFunc={this.handleUrlRef}
|
refFunc={this.handleUrlRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ class TelegramConfig extends PureComponent<Props, State> {
|
||||||
const disableNotification = options['disable-notification']
|
const disableNotification = options['disable-notification']
|
||||||
const disableWebPagePreview = options['disable-web-page-preview']
|
const disableWebPagePreview = options['disable-web-page-preview']
|
||||||
const parseMode = options['parse-mode']
|
const parseMode = options['parse-mode']
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
@ -88,6 +89,7 @@ class TelegramConfig extends PureComponent<Props, State> {
|
||||||
id="token"
|
id="token"
|
||||||
refFunc={this.handleTokenRef}
|
refFunc={this.handleTokenRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ class VictorOpsConfig extends PureComponent<Props, State> {
|
||||||
const apiKey = options['api-key']
|
const apiKey = options['api-key']
|
||||||
const routingKey = options['routing-key']
|
const routingKey = options['routing-key']
|
||||||
const {url} = options
|
const {url} = options
|
||||||
|
const {testEnabled} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
@ -56,6 +57,7 @@ class VictorOpsConfig extends PureComponent<Props, State> {
|
||||||
id="api-key"
|
id="api-key"
|
||||||
refFunc={this.handleApiRef}
|
refFunc={this.handleApiRef}
|
||||||
disableTest={this.disableTest}
|
disableTest={this.disableTest}
|
||||||
|
isFormEditing={!testEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ export const DEFAULT_HANDLERS = [
|
||||||
export const MAP_KEYS_FROM_CONFIG = {
|
export const MAP_KEYS_FROM_CONFIG = {
|
||||||
hipchat: 'hipChat',
|
hipchat: 'hipChat',
|
||||||
opsgenie: 'opsGenie',
|
opsgenie: 'opsGenie',
|
||||||
|
opsgenie2: 'opsGenie2',
|
||||||
pagerduty: 'pagerDuty',
|
pagerduty: 'pagerDuty',
|
||||||
pagerduty2: 'pagerDuty2',
|
pagerduty2: 'pagerDuty2',
|
||||||
smtp: 'email',
|
smtp: 'email',
|
||||||
|
@ -114,6 +115,7 @@ export const ALERTS_FROM_CONFIG = {
|
||||||
alerta: ['environment', 'origin', 'token'], // token = bool
|
alerta: ['environment', 'origin', 'token'], // token = bool
|
||||||
hipChat: ['url', 'room', 'token'], // token = bool
|
hipChat: ['url', 'room', 'token'], // token = bool
|
||||||
opsGenie: ['api-key', 'teams', 'recipients'], // api-key = bool
|
opsGenie: ['api-key', 'teams', 'recipients'], // api-key = bool
|
||||||
|
opsGenie2: ['api-key', 'teams', 'recipients'], // api-key = bool
|
||||||
pagerDuty: ['service-key'], // service-key = bool
|
pagerDuty: ['service-key'], // service-key = bool
|
||||||
pagerDuty2: ['service-key'], // service-key = bool
|
pagerDuty2: ['service-key'], // service-key = bool
|
||||||
pushover: ['token', 'user-key'], // token = bool, user-key = bool
|
pushover: ['token', 'user-key'], // token = bool, user-key = bool
|
||||||
|
@ -138,6 +140,7 @@ export const MAP_FIELD_KEYS_FROM_CONFIG = {
|
||||||
alerta: {},
|
alerta: {},
|
||||||
hipChat: {},
|
hipChat: {},
|
||||||
opsGenie: {},
|
opsGenie: {},
|
||||||
|
opsGenie2: {},
|
||||||
pagerDuty: {'service-key': 'serviceKey'},
|
pagerDuty: {'service-key': 'serviceKey'},
|
||||||
pagerDuty2: {'service-key': 'serviceKey'},
|
pagerDuty2: {'service-key': 'serviceKey'},
|
||||||
pushover: {'user-key': 'userKey'},
|
pushover: {'user-key': 'userKey'},
|
||||||
|
@ -170,6 +173,7 @@ export const HANDLERS_TO_RULE = {
|
||||||
],
|
],
|
||||||
hipChat: ['room'],
|
hipChat: ['room'],
|
||||||
opsGenie: ['teams', 'recipients'],
|
opsGenie: ['teams', 'recipients'],
|
||||||
|
opsGenie2: ['teams', 'recipients'],
|
||||||
pagerDuty: [],
|
pagerDuty: [],
|
||||||
pagerDuty2: [],
|
pagerDuty2: [],
|
||||||
pushover: ['device', 'title', 'sound', 'url', 'urlTitle'],
|
pushover: ['device', 'title', 'sound', 'url', 'urlTitle'],
|
||||||
|
|
|
@ -96,7 +96,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ interface AlertNodes {
|
||||||
hipChat: HipChat[]
|
hipChat: HipChat[]
|
||||||
alerta: Alerta[]
|
alerta: Alerta[]
|
||||||
opsGenie: OpsGenie[]
|
opsGenie: OpsGenie[]
|
||||||
|
opsGenie2?: OpsGenie[]
|
||||||
talk: Talk[]
|
talk: Talk[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue