Add delete button and funcitonality for SlackConfigs

pull/3465/head
Iris Scholten 2018-05-09 18:54:42 -07:00
parent 5330d2c5a7
commit dbd32a9952
5 changed files with 148 additions and 64 deletions

View File

@ -13,6 +13,7 @@ import {
getKapacitorConfig,
updateKapacitorConfigSection,
addKapacitorConfigInSection,
deleteKapacitorConfigInSection,
testAlertOutput,
getAllServices,
} from 'src/shared/apis'
@ -36,6 +37,8 @@ import {
notifyRefreshKapacitorFailed,
notifyAlertEndpointSaved,
notifyAlertEndpointSaveFailed,
notifyAlertEndpointDeleteFailed,
notifyAlertEndpointDeleted,
notifyTestAlertSent,
notifyTestAlertFailed,
notifyCouldNotRetrieveKapacitorServices,
@ -43,7 +46,7 @@ import {
import DeprecationWarning from 'src/admin/components/DeprecationWarning'
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Source, Kapacitor} from 'src/types'
import {Source, Kapacitor, NotificationFunc} from 'src/types'
import SlackConfigs from 'src/kapacitor/components/config/SlackConfigs'
interface Service {
@ -95,6 +98,7 @@ interface Config {
type: string
enabled: boolean
renderComponent: () => JSX.Element
notify?: (message: Notification | NotificationFunc) => void
}
interface SupportedConfig {
@ -171,11 +175,11 @@ class AlertTabs extends PureComponent<Props, State> {
return null
}
const pagerDutyV1Enabled: boolean = this.getEnabled(
const pagerDutyV1Enabled: boolean = this.getConfigEnabled(
configSections,
'pagerduty'
)
const opsGenieV1Enabled: boolean = this.getEnabled(
const opsGenieV1Enabled: boolean = this.getConfigEnabled(
configSections,
'opsgenie'
)
@ -205,31 +209,31 @@ class AlertTabs extends PureComponent<Props, State> {
const supportedConfigs: SupportedConfig = {
alerta: {
type: 'Alerta',
enabled: this.getEnabled(configSections, 'alerta'),
enabled: this.getConfigEnabled(configSections, 'alerta'),
renderComponent: () => (
<AlertaConfig
onSave={this.handleSaveConfig('alerta')}
config={this.getSectionElement(configSections, 'alerta')}
onTest={this.handleTestConfig('alerta')}
enabled={this.getEnabled(configSections, 'alerta')}
enabled={this.getConfigEnabled(configSections, 'alerta')}
/>
),
},
hipchat: {
type: 'HipChat',
enabled: this.getEnabled(configSections, 'hipchat'),
enabled: this.getConfigEnabled(configSections, 'hipchat'),
renderComponent: () => (
<HipChatConfig
onSave={this.handleSaveConfig('hipchat')}
config={this.getSectionElement(configSections, 'hipchat')}
onTest={this.handleTestConfig('hipchat')}
enabled={this.getEnabled(configSections, 'hipchat')}
enabled={this.getConfigEnabled(configSections, 'hipchat')}
/>
),
},
kafka: {
type: 'Kafka',
enabled: this.getEnabled(configSections, 'kafka'),
enabled: this.getConfigEnabled(configSections, 'kafka'),
renderComponent: () => (
<KafkaConfig
onSave={this.handleSaveConfig('kafka')}
@ -237,145 +241,146 @@ class AlertTabs extends PureComponent<Props, State> {
onTest={this.handleTestConfig('kafka', {
cluster: this.getProperty(configSections, 'kafka', 'id'),
})}
enabled={this.getEnabled(configSections, 'kafka')}
enabled={this.getConfigEnabled(configSections, 'kafka')}
notify={this.props.notify}
/>
),
},
opsgenie: {
type: 'OpsGenie',
enabled: this.getEnabled(configSections, 'opsgenie'),
enabled: this.getConfigEnabled(configSections, 'opsgenie'),
renderComponent: () => (
<OpsGenieConfig
onSave={this.handleSaveConfig('opsgenie')}
config={this.getSectionElement(configSections, 'opsgenie')}
onTest={this.handleTestConfig('opsgenie')}
enabled={this.getEnabled(configSections, 'opsgenie')}
enabled={this.getConfigEnabled(configSections, 'opsgenie')}
/>
),
},
opsgenie2: {
type: 'OpsGenie2',
enabled: this.getEnabled(configSections, 'opsgenie2'),
enabled: this.getConfigEnabled(configSections, 'opsgenie2'),
renderComponent: () => (
<OpsGenieConfig
onSave={this.handleSaveConfig('opsgenie2')}
config={this.getSectionElement(configSections, 'opsgenie2')}
onTest={this.handleTestConfig('opsgenie2')}
enabled={this.getEnabled(configSections, 'opsgenie2')}
enabled={this.getConfigEnabled(configSections, 'opsgenie2')}
/>
),
},
pagerduty: {
type: 'PagerDuty',
enabled: this.getEnabled(configSections, 'pagerduty'),
enabled: this.getConfigEnabled(configSections, 'pagerduty'),
renderComponent: () => (
<PagerDutyConfig
onSave={this.handleSaveConfig('pagerduty')}
config={this.getSectionElement(configSections, 'pagerduty')}
onTest={this.handleTestConfig('pagerduty')}
enabled={this.getEnabled(configSections, 'pagerduty')}
enabled={this.getConfigEnabled(configSections, 'pagerduty')}
/>
),
},
pagerduty2: {
type: 'PagerDuty2',
enabled: this.getEnabled(configSections, 'pagerduty2'),
enabled: this.getConfigEnabled(configSections, 'pagerduty2'),
renderComponent: () => (
<PagerDuty2Config
onSave={this.handleSaveConfig('pagerduty2')}
config={this.getSectionElement(configSections, 'pagerduty2')}
onTest={this.handleTestConfig('pagerduty2')}
enabled={this.getEnabled(configSections, 'pagerduty2')}
enabled={this.getConfigEnabled(configSections, 'pagerduty2')}
/>
),
},
pushover: {
type: 'Pushover',
enabled: this.getEnabled(configSections, 'pushover'),
enabled: this.getConfigEnabled(configSections, 'pushover'),
renderComponent: () => (
<PushoverConfig
onSave={this.handleSaveConfig('pushover')}
config={this.getSectionElement(configSections, 'pushover')}
onTest={this.handleTestConfig('pushover')}
enabled={this.getEnabled(configSections, 'pushover')}
enabled={this.getConfigEnabled(configSections, 'pushover')}
/>
),
},
sensu: {
type: 'Sensu',
enabled: this.getEnabled(configSections, 'sensu'),
enabled: this.getConfigEnabled(configSections, 'sensu'),
renderComponent: () => (
<SensuConfig
onSave={this.handleSaveConfig('sensu')}
config={this.getSectionElement(configSections, 'sensu')}
onTest={this.handleTestConfig('sensu')}
enabled={this.getEnabled(configSections, 'sensu')}
enabled={this.getConfigEnabled(configSections, 'sensu')}
/>
),
},
slack: {
type: 'Slack',
enabled: this.getEnabled(configSections, 'slack'),
enabled: this.getConfigEnabled(configSections, 'slack'),
renderComponent: () => (
<SlackConfigs
slackConfigs={this.getSectionElements(configSections, 'slack')}
configs={this.getSectionElements(configSections, 'slack')}
onSave={this.handleSaveConfig('slack')}
config={this.getSectionElement(configSections, 'slack')}
onTest={this.handleTestConfig('slack')}
enabled={this.getEnabled(configSections, 'slack')}
onDelete={this.handleDeleteConfig('slack')}
onEnabled={this.getSpecificConfigEnabled(configSections, 'slack')}
/>
),
},
smtp: {
type: 'SMTP',
enabled: this.getEnabled(configSections, 'smtp'),
enabled: this.getConfigEnabled(configSections, 'smtp'),
renderComponent: () => (
<SMTPConfig
onSave={this.handleSaveConfig('smtp')}
config={this.getSectionElement(configSections, 'smtp')}
onTest={this.handleTestConfig('smtp')}
enabled={this.getEnabled(configSections, 'smtp')}
enabled={this.getConfigEnabled(configSections, 'smtp')}
/>
),
},
talk: {
type: 'Talk',
enabled: this.getEnabled(configSections, 'talk'),
enabled: this.getConfigEnabled(configSections, 'talk'),
renderComponent: () => (
<TalkConfig
onSave={this.handleSaveConfig('talk')}
config={this.getSectionElement(configSections, 'talk')}
onTest={this.handleTestConfig('talk')}
enabled={this.getEnabled(configSections, 'talk')}
enabled={this.getConfigEnabled(configSections, 'talk')}
/>
),
},
telegram: {
type: 'Telegram',
enabled: this.getEnabled(configSections, 'telegram'),
enabled: this.getConfigEnabled(configSections, 'telegram'),
renderComponent: () => (
<TelegramConfig
onSave={this.handleSaveConfig('telegram')}
config={this.getSectionElement(configSections, 'telegram')}
onTest={this.handleTestConfig('telegram')}
enabled={this.getEnabled(configSections, 'telegram')}
enabled={this.getConfigEnabled(configSections, 'telegram')}
/>
),
},
victorops: {
type: 'VictorOps',
enabled: this.getEnabled(configSections, 'victorops'),
enabled: this.getConfigEnabled(configSections, 'victorops'),
renderComponent: () => (
<VictorOpsConfig
onSave={this.handleSaveConfig('victorops')}
config={this.getSectionElement(configSections, 'victorops')}
onTest={this.handleTestConfig('victorops')}
enabled={this.getEnabled(configSections, 'victorops')}
enabled={this.getConfigEnabled(configSections, 'victorops')}
/>
),
},
}
return (
<div className="panel">
<div className="panel-heading">
@ -445,10 +450,9 @@ class AlertTabs extends PureComponent<Props, State> {
private getSectionElement = (
sections: Sections,
section: string,
elementIndex: number = 0
section: string
): Element => {
return _.get(sections, [section, 'elements', elementIndex], null)
return _.get(sections, [section, 'elements', '0'], null)
}
private getSectionElements = (
@ -458,7 +462,7 @@ class AlertTabs extends PureComponent<Props, State> {
return _.get(sections, [section, 'elements'], null)
}
private getEnabled = (sections: Sections, section: string): boolean => {
private getConfigEnabled = (sections: Sections, section: string): boolean => {
return _.get(
sections,
[section, 'elements', '0', 'options', 'enabled'],
@ -478,6 +482,20 @@ class AlertTabs extends PureComponent<Props, State> {
)
}
private getSpecificConfigEnabled = (sections: Sections, section: string) => (
specificConfig: string
): boolean => {
const elements: Element[] = this.getSectionElements(sections, section)
const elementIndex = elements.findIndex(
element => _.get(element, ['options', 'workspace']) === specificConfig
)
return _.get(
sections,
[section, 'elements', elementIndex.toString(), 'options', 'enabled'],
false
)
}
private handleSaveConfig = (section: string) => async (
properties,
isNewConfigInSection?: boolean,
@ -533,6 +551,27 @@ class AlertTabs extends PureComponent<Props, State> {
}
}
private handleDeleteConfig = (section: string) => async (
specificConfig: string
): Promise<void> => {
try {
await deleteKapacitorConfigInSection(
this.props.kapacitor,
section,
specificConfig
)
await this.refreshKapacitorConfig(this.props.kapacitor)
this.props.notify(notifyAlertEndpointDeleted(section, specificConfig))
} catch (error) {
const errorMsg = _.join(_.drop(_.split(error, ': '), 2), ': ')
this.props.notify(
notifyAlertEndpointDeleteFailed(section, specificConfig, errorMsg)
)
}
}
private sanitizeProperties = (section: string, properties: Props): Props => {
const cleanProps = {enabled: true, ...properties}
const {redacted} = this.getSectionElement(

View File

@ -27,6 +27,7 @@ interface Props {
specificConfig: string
) => void
onTest: (event: React.MouseEvent<HTMLButtonElement>) => void
onDelete: (specificConfig: string) => void
enabled: boolean
isNewConfig: boolean
}
@ -60,6 +61,8 @@ class SlackConfig extends PureComponent<Props, State> {
const {testEnabled, enabled} = this.state
const workspaceID = workspace || 'default'
const isNickNameEnabled = isNewConfig && !testEnabled
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group col-xs-12">
@ -70,11 +73,11 @@ class SlackConfig extends PureComponent<Props, State> {
className="form-control"
id={`${workspaceID}-nickname`}
type="text"
placeholder="Optional unless multiple Slack configurations exist"
placeholder="Only for additional Configurations"
ref={r => (this.workspace = r)}
defaultValue={workspace || ''}
onChange={this.disableTest}
disabled={!isNewConfig}
disabled={!isNickNameEnabled}
/>
</div>
<div className="form-group col-xs-12">
@ -140,6 +143,10 @@ class SlackConfig extends PureComponent<Props, State> {
<span className="icon pulse-c" />
Send Test Alert
</button>
<button className="btn btn-danger" onClick={this.handleDelete}>
<span className="icon trash" />
Delete
</button>
</div>
<br />
<br />
@ -173,6 +180,11 @@ class SlackConfig extends PureComponent<Props, State> {
}
}
private handleDelete = async e => {
e.preventDefault()
await this.props.onDelete(this.workspace.value)
}
private disableTest = () => {
this.setState({testEnabled: false})
}

View File

@ -19,19 +19,19 @@ interface Config {
}
interface Props {
slackConfigs: any[]
config: Config
configs: Config[]
onSave: (
properties: Properties,
isNewConfigInSection: boolean,
specificConfig: string
) => void
onDelete: (specificConfig: string) => void
onTest: (event: React.MouseEvent<HTMLButtonElement>) => void
enabled: boolean
onEnabled: (specificConfig: string) => boolean
}
interface State {
slackConfigs: any[]
configs: any[]
}
@ErrorHandling
@ -39,30 +39,32 @@ class SlackConfigs extends PureComponent<Props, State> {
constructor(props) {
super(props)
this.state = {
slackConfigs: this.props.slackConfigs,
configs: this.props.configs,
}
}
public componentWillReceiveProps(nextProps) {
this.setState({configs: nextProps.configs})
}
public render() {
const {slackConfigs} = this.state
const {onSave, onTest, enabled} = this.props
const configNums = slackConfigs.length
const {configs} = this.state
const {onSave, onTest, onDelete, onEnabled} = this.props
return (
<div>
{slackConfigs.map(config => {
const key = _.get(config, ['options', 'workspace'], 'default')
const configEnabled = _.get(config, ['options', 'enabled'], false)
const isFirstConfigNew = configNums === 1 && !configEnabled
const isNewConfig =
isFirstConfigNew || _.get(config, 'isNewConfig', false)
{configs.map(config => {
const workspace = _.get(config, ['options', 'workspace'], 'new')
const isNewConfig = _.get(config, 'isNewConfig', false)
const enabled = onEnabled(workspace)
return (
<SlackConfig
key={key}
key={workspace}
onSave={onSave}
config={config}
onTest={onTest}
onDelete={onDelete}
enabled={enabled}
isNewConfig={isNewConfig}
/>
@ -75,12 +77,12 @@ class SlackConfigs extends PureComponent<Props, State> {
)
}
private get slackConfigs() {
return this.state.slackConfigs
private get configs() {
return this.state.configs
}
private addConfig = () => {
const configs = this.slackConfigs
const configs = this.configs
const newConfig = {
options: {
url: false,
@ -88,7 +90,7 @@ class SlackConfigs extends PureComponent<Props, State> {
},
isNewConfig: true,
}
this.setState({slackConfigs: [...configs, newConfig]})
this.setState({configs: [...configs, newConfig]})
}
}

View File

@ -155,10 +155,6 @@ export const getKapacitorConfigSection = (kapacitor, section) => {
return kapacitorProxy(kapacitor, 'GET', `/kapacitor/v1/config/${section}`, '')
}
<<<<<<< HEAD
export function updateKapacitorConfigSection(kapacitor, section, properties) {
const params = {
=======
export function updateKapacitorConfigSection(
kapacitor,
section,
@ -168,8 +164,7 @@ export function updateKapacitorConfigSection(
const config = specificConfig || ''
const path = `/kapacitor/v1/config/${section}/${config}`
return AJAX({
>>>>>>> Change updateKapacitorConfigSection function so that if a specific config is passed, it updates that specific config and not just the default
const params = {
method: 'POST',
url: kapacitor.links.proxy,
params: {
@ -202,6 +197,28 @@ export function addKapacitorConfigInSection(kapacitor, section, properties) {
})
}
export function deleteKapacitorConfigInSection(
kapacitor,
section,
specificConfig
) {
const path = `/kapacitor/v1/config/${section}`
return AJAX({
method: 'POST',
url: kapacitor.links.proxy,
params: {
path,
},
data: {
remove: [specificConfig],
},
headers: {
'Content-Type': 'application/json',
},
})
}
export const testAlertOutput = async (kapacitor, outputName, options) => {
try {
const {

View File

@ -516,6 +516,20 @@ export const notifyAlertEndpointSaveFailed = (endpoint, errorMessage) => ({
message: `There was an error saving the alert configuration for ${endpoint}: ${errorMessage}`,
})
export const notifyAlertEndpointDeleteFailed = (
endpoint,
config,
errorMessage
) => ({
...defaultErrorNotification,
message: `There was an error deleting the alert configuration for ${endpoint}/${config}: ${errorMessage}`,
})
export const notifyAlertEndpointDeleted = (endpoint, config) => ({
...defaultSuccessNotification,
message: `Alert configuration for ${endpoint}/${config} deleted successfully.`,
})
export const notifyTestAlertSent = endpoint => ({
...defaultSuccessNotification,
duration: TEN_SECONDS,