Merge pull request #3369 from influxdata/feature/opsgenie-v2

Add OpsGenie v2 support to UI
pull/10616/head
Jared Scheib 2018-05-04 17:00:35 -07:00 committed by GitHub
commit cd850f5280
21 changed files with 300 additions and 130 deletions

View File

@ -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

4
Gopkg.lock generated
View File

@ -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

View File

@ -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"

View File

@ -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
} }

View File

@ -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{}
} }

View File

@ -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{},
}, },
}, },

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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'],

View File

@ -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
} }

View File

@ -64,6 +64,7 @@ interface AlertNodes {
hipChat: HipChat[] hipChat: HipChat[]
alerta: Alerta[] alerta: Alerta[]
opsGenie: OpsGenie[] opsGenie: OpsGenie[]
opsGenie2?: OpsGenie[]
talk: Talk[] talk: Talk[]
} }