Migration: Edit notification channel (#25980)

* implement edit page

* connectWithCleanup

* remove angular related code

* use loadingindicator

* use the correct loading component

* handle secureFields

* fixed implementation of secure fields

* Keep secureFields after rerendering the form

* CollapsableSection and Page refactor

* use checkbox instead of switch

* fix comment

* add cursor to section

* Fixed issues after PR review

* Fix issue with some settings being undefined

* new reducer and start with test

* algorithm to migrate secure fields

* UX: Minor UI Tweaks

* Added field around checkboxes, and missing required field

* fixed test

* tests for util

* minor tweaks and changes

* define as records

* fix typ error

* forward invalid to textarea and inputcontrol

* merge formdata and redux data in test

* fix issue with creating channel

* do not figure out securefields in migration

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
Peter Holmberg
2020-09-09 12:46:19 +02:00
committed by GitHub
parent 1e2f3ca599
commit 400aafa3b3
45 changed files with 1297 additions and 1059 deletions

View File

@@ -23,14 +23,13 @@ var newImageUploaderProvider = func() (imguploader.ImageUploader, error) {
// NotifierPlugin holds meta information about a notifier.
type NotifierPlugin struct {
Type string `json:"type"`
Name string `json:"name"`
Heading string `json:"heading"`
Description string `json:"description"`
Info string `json:"info"`
OptionsTemplate string `json:"optionsTemplate"`
Factory NotifierFactory `json:"-"`
Options []NotifierOption `json:"options"`
Type string `json:"type"`
Name string `json:"name"`
Heading string `json:"heading"`
Description string `json:"description"`
Info string `json:"info"`
Factory NotifierFactory `json:"-"`
Options []NotifierOption `json:"options"`
}
// NotifierOption holds information about options specific for the NotifierPlugin.
@@ -45,6 +44,7 @@ type NotifierOption struct {
ShowWhen ShowWhen `json:"showWhen"`
Required bool `json:"required"`
ValidationRule string `json:"validationRule"`
Secure bool `json:"secure"`
}
// InputType is the type of input that can be rendered in the frontend.
@@ -65,8 +65,8 @@ const (
ElementTypeInput = "input"
// ElementTypeSelect will render a select
ElementTypeSelect = "select"
// ElementTypeSwitch will render a switch
ElementTypeSwitch = "switch"
// ElementTypeCheckbox will render a checkbox
ElementTypeCheckbox = "checkbox"
// ElementTypeTextArea will render a textarea
ElementTypeTextArea = "textarea"
)

View File

@@ -20,36 +20,6 @@ func init() {
Description: "Sends alert to Prometheus Alertmanager",
Heading: "Alertmanager settings",
Factory: NewAlertmanagerNotifier,
OptionsTemplate: `
<h3 class="page-heading">Alertmanager settings</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Url(s)</span>
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="http://localhost:9093"></input>
<info-popover mode="right-absolute">
As specified in Alertmanager documentation, do not specify a load balancer here. Enter all your Alertmanager URLs comma-separated.
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Basic Auth User</span>
<input type="text" class="gf-form-input max-width-30" ng-model="ctrl.model.settings.basicAuthUser" placeholder=""></input>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Basic Auth Password</span>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.basicAuthPassword">
<input type="text"
class="gf-form-input max-width-30"
ng-init="ctrl.model.secureSettings.basicAuthPassword = ctrl.model.settings.basicAuthPassword || null; ctrl.model.settings.basicAuthPassword = null;"
ng-model="ctrl.model.secureSettings.basicAuthPassword"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.basicAuthPassword">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.basicAuthPassword = false">reset</a>
</div>
</div>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Url",
@@ -71,6 +41,7 @@ func init() {
Element: alerting.ElementTypeInput,
InputType: alerting.InputTypePassword,
PropertyName: "basicAuthPassword",
Secure: true,
},
},
})

View File

@@ -12,26 +12,14 @@ import (
)
const defaultDingdingMsgType = "link"
const dingdingOptionsTemplate = `
<h3 class="page-heading">DingDing settings</h3>
<div class="gf-form">
<span class="gf-form-label width-10">Url</span>
<input type="text" required class="gf-form-input max-width-70" ng-model="ctrl.model.settings.url" placeholder="https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxx"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">MessageType</span>
<select class="gf-form-input max-width-14" ng-model="ctrl.model.settings.msgType" ng-options="s for s in ['link','actionCard']" ng-init="ctrl.model.settings.msgType=ctrl.model.settings.msgType || '` + defaultDingdingMsgType + `'"></select>
</div>
`
func init() {
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "dingding",
Name: "DingDing",
Description: "Sends HTTP POST request to DingDing",
Heading: "DingDing settings",
Factory: newDingDingNotifier,
OptionsTemplate: dingdingOptionsTemplate,
Type: "dingding",
Name: "DingDing",
Description: "Sends HTTP POST request to DingDing",
Heading: "DingDing settings",
Factory: newDingDingNotifier,
Options: []alerting.NotifierOption{
{
Label: "Url",

View File

@@ -23,24 +23,6 @@ func init() {
Description: "Sends notifications to Discord",
Factory: newDiscordNotifier,
Heading: "Discord settings",
OptionsTemplate: `
<h3 class="page-heading">Discord settings</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Message Content</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.content"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Mention a group using @ or a user using <@ID> when notifying in a channel
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-10">Webhook URL</span>
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="Discord webhook URL"></input>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Message Content",

View File

@@ -19,32 +19,11 @@ func init() {
Description: "Sends notifications using Grafana server configured SMTP settings",
Factory: NewEmailNotifier,
Heading: "Email settings",
OptionsTemplate: `
<h3 class="page-heading">Email settings</h3>
<div class="gf-form">
<gf-form-switch
class="gf-form"
label="Single email"
label-class="width-8"
checked="ctrl.model.settings.singleEmail"
tooltip="Send a single email to all recipients">
</gf-form-switch>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">
Addresses
</label>
<textarea rows="7" class="gf-form-input width-27" required ng-model="ctrl.model.settings.addresses"></textarea>
</div>
<div class="gf-form offset-width-8">
<span>You can enter multiple email addresses using a ";" separator</span>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Single email",
Description: "Send a single email to all recipients",
Element: alerting.ElementTypeSwitch,
Element: alerting.ElementTypeCheckbox,
PropertyName: "singleEmail",
},
{

View File

@@ -19,13 +19,6 @@ func init() {
Description: "Sends notifications to Google Hangouts Chat via webhooks based on the official JSON message format",
Factory: newGoogleChatNotifier,
Heading: "Google Hangouts Chat settings",
OptionsTemplate: `
<h3 class="page-heading">Google Hangouts Chat settings</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-6">Url</span>
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="Google Hangouts Chat incoming webhook url"></input>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Url",

View File

@@ -20,25 +20,6 @@ func init() {
Description: "Sends notifications uto a HipChat Room",
Heading: "HipChat settings",
Factory: NewHipChatNotifier,
OptionsTemplate: `
<h3 class="page-heading">HipChat settings</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Hip Chat Url</span>
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="HipChat URL (ex https://grafana.hipchat.com)"></input>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">API Key</span>
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.apikey" placeholder="HipChat API Key"></input>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Room ID</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.roomid"
data-placement="right">
</input>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Hip Chat Url",

View File

@@ -19,17 +19,6 @@ func init() {
Description: "Sends notifications to Kafka Rest Proxy",
Heading: "Kafka settings",
Factory: NewKafkaNotifier,
OptionsTemplate: `
<h3 class="page-heading">Kafka settings</h3>
<div class="gf-form">
<span class="gf-form-label width-14">Kafka REST Proxy</span>
<input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.kafkaRestProxy" placeholder="http://localhost:8082"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-14">Topic</span>
<input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.kafkaTopic" placeholder="topic1"></input>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Kafka REST Proxy",

View File

@@ -17,25 +17,6 @@ func init() {
Description: "Send notifications to LINE notify",
Heading: "LINE notify settings",
Factory: NewLINENotifier,
OptionsTemplate: `
<h3 class="page-heading">LINE notify settings</h3>
<div class="gf-form">
<label class="gf-form-label max-width-14">Token</label>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.token">
<input type="text"
required
class="gf-form-input max-width-22"
ng-init="ctrl.model.secureSettings.token = ctrl.model.settings.token || null; ctrl.model.settings.token = null;"
ng-model="ctrl.model.secureSettings.token"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.token">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.token = false">reset</a>
</div>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Token",
@@ -44,6 +25,7 @@ func init() {
Placeholder: "LINE notify token key",
PropertyName: "token",
Required: true,
Secure: true,
}},
})
}

View File

@@ -18,48 +18,6 @@ func init() {
Description: "Sends notifications to OpsGenie",
Heading: "OpsGenie settings",
Factory: NewOpsGenieNotifier,
OptionsTemplate: `
<h3 class="page-heading">OpsGenie settings</h3>
<div class="gf-form">
<label class="gf-form-label max-width-14">API Key</label>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.apiKey">
<input type="text"
required
class="gf-form-input max-width-22"
ng-init="ctrl.model.secureSettings.apiKey = ctrl.model.settings.apiKey || null; ctrl.model.settings.apiKey = null;"
ng-model="ctrl.model.secureSettings.apiKey"
placeholder="OpsGenie API Key"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.apiKey">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.apiKey = false">reset</a>
</div>
</div>
<div class="gf-form">
<span class="gf-form-label width-14">Alert API Url</span>
<input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.apiUrl" placeholder="https://api.opsgenie.com/v2/alerts"></input>
</div>
<div class="gf-form">
<gf-form-switch
class="gf-form"
label="Auto close incidents"
label-class="width-14"
checked="ctrl.model.settings.autoClose"
tooltip="Automatically close alerts in OpsGenie once the alert goes back to ok.">
</gf-form-switch>
</div>
<div class="gf-form">
<gf-form-switch
class="gf-form"
label="Override priority"
label-class="width-14"
checked="ctrl.model.settings.overridePriority"
tooltip="Allow the alert priority to be set using the og_priority tag">
</gf-form-switch>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "API Key",
@@ -68,6 +26,7 @@ func init() {
Placeholder: "OpsGenie API Key",
PropertyName: "apiKey",
Required: true,
Secure: true,
},
{
Label: "Alert API Url",
@@ -79,12 +38,12 @@ func init() {
},
{
Label: "Auto close incidents",
Element: alerting.ElementTypeSwitch,
Element: alerting.ElementTypeCheckbox,
Description: "Automatically close alerts in OpsGenie once the alert goes back to ok.",
PropertyName: "autoClose",
}, {
Label: "Override priority",
Element: alerting.ElementTypeSwitch,
Element: alerting.ElementTypeCheckbox,
Description: "Allow the alert priority to be set using the og_priority tag",
PropertyName: "overridePriority",
},

View File

@@ -20,53 +20,6 @@ func init() {
Description: "Sends notifications to PagerDuty",
Heading: "PagerDuty settings",
Factory: NewPagerdutyNotifier,
OptionsTemplate: `
<h3 class="page-heading">PagerDuty settings</h3>
<div class="gf-form">
<span class="gf-form-label width-14">Integration Key</span>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.integrationKey">
<input type="text"
class="gf-form-input max-width-22"
ng-init="ctrl.model.secureSettings.integrationKey = ctrl.model.settings.integrationKey || null; ctrl.model.settings.integrationKey = null;"
ng-model="ctrl.model.secureSettings.integrationKey"
placeholder="Pagerduty Integration Key"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.integrationKey">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.integrationKey = false">reset</a>
</div>
</div>
<div class="gf-form">
<span class="gf-form-label width-14">Severity</span>
<div class="gf-form-select-wrapper width-14">
<select
class="gf-form-input"
ng-model="ctrl.model.settings.severity"
ng-options="s for s in ['critical', 'error', 'warning', 'info']">
</select>
</div>
</div>
<div class="gf-form">
<gf-form-switch
class="gf-form"
label="Auto resolve incidents"
label-class="width-14"
checked="ctrl.model.settings.autoResolve"
tooltip="Resolve incidents in pagerduty once the alert goes back to ok.">
</gf-form-switch>
</div>
<div class="gf-form">
<gf-form-switch
class="gf-form"
label="Include message in details"
label-class="width-14"
checked="ctrl.model.settings.messageInDetails"
tooltip="Move the alert message from the PD summary into the custom details. This changes the custom details object and may break event rules you have configured">
</gf-form-switch>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Integration Key",
@@ -101,10 +54,16 @@ func init() {
},
{
Label: "Auto resolve incidents",
Element: alerting.ElementTypeSwitch,
Element: alerting.ElementTypeCheckbox,
Description: "Resolve incidents in pagerduty once the alert goes back to ok.",
PropertyName: "autoResolve",
},
{
Label: "Include message in details",
Element: alerting.ElementTypeCheckbox,
Description: "Move the alert message from the PD summary into the custom details. This changes the custom details object and may break event rules you have configured",
PropertyName: "messageInDetails",
},
},
})
}

View File

@@ -17,31 +17,6 @@ import (
const pushoverEndpoint = "https://api.pushover.net/1/messages.json"
func init() {
sounds := `
'default',
'pushover',
'bike',
'bugle',
'cashregister',
'classical',
'cosmic',
'falling',
'gamelan',
'incoming',
'intermission',
'magic',
'mechanical',
'pianobar',
'siren',
'spacealarm',
'tugboat',
'alien',
'climb',
'persistent',
'echo',
'updown',
'none'`
soundOptions := []alerting.SelectOption{
{
Value: "default",
@@ -122,76 +97,6 @@ func init() {
Description: "Sends HTTP POST request to the Pushover API",
Heading: "Pushover settings",
Factory: NewPushoverNotifier,
OptionsTemplate: `
<h3 class="page-heading">Pushover settings</h3>
<div class="gf-form">
<label class="gf-form-label width-10">API Token</label>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.apiToken">
<input type="text"
required
class="gf-form-input"
ng-init="ctrl.model.secureSettings.apiToken = ctrl.model.settings.apiToken || null; ctrl.model.settings.apiToken = null;"
ng-model="ctrl.model.secureSettings.apiToken"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.apiToken">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.apiToken = false">reset</a>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label max-width-10">User Key(s)</label>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.userKey">
<input type="text"
required
class="gf-form-input"
ng-init="ctrl.model.secureSettings.userKey = ctrl.model.settings.userKey || null; ctrl.model.settings.userKey = null;"
ng-model="ctrl.model.secureSettings.userKey"
placeholder="comma-separated list"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.userKey">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.userKey = false">reset</a>
</div>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">Device(s) (optional)</span>
<input type="text" class="gf-form-input" placeholder="comma-separated list; leave empty to send to all devices" ng-model="ctrl.model.settings.device"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">Priority</span>
<select class="gf-form-input max-width-14" ng-model="ctrl.model.settings.priority" ng-options="v as k for (k, v) in {
Emergency: '2',
High: '1',
Normal: '0',
Low: '-1',
Lowest: '-2'
}" ng-init="ctrl.model.settings.priority=ctrl.model.settings.priority||'0'"></select>
</div>
<div class="gf-form" ng-show="ctrl.model.settings.priority == '2'">
<span class="gf-form-label width-10">Retry</span>
<input type="text" class="gf-form-input max-width-14" ng-required="ctrl.model.settings.priority == '2'" placeholder="minimum 30 seconds" ng-model="ctrl.model.settings.retry" ng-init="ctrl.model.settings.retry=ctrl.model.settings.retry||'60'></input>
</div>
<div class="gf-form" ng-show="ctrl.model.settings.priority == '2'">
<span class="gf-form-label width-10">Expire</span>
<input type="text" class="gf-form-input max-width-14" ng-required="ctrl.model.settings.priority == '2'" placeholder="maximum 86400 seconds" ng-model="ctrl.model.settings.expire" ng-init="ctrl.model.settings.expire=ctrl.model.settings.expire||'3600'"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">Alerting sound</span>
<select class="gf-form-input max-width-14" ng-model="ctrl.model.settings.sound" ng-options="s for s in [
` + sounds + `
]" ng-init="ctrl.model.settings.sound=ctrl.model.settings.sound||'default'"></select>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">OK sound</span>
<select class="gf-form-input max-width-14" ng-model="ctrl.model.settings.okSound" ng-options="s for s in [
` + sounds + `
]" ng-init="ctrl.model.settings.okSound=ctrl.model.settings.okSound||'default'"></select>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "API Token",
@@ -200,6 +105,7 @@ func init() {
Placeholder: "Application token",
PropertyName: "apiToken",
Required: true,
Secure: true,
},
{
Label: "User key(s)",
@@ -208,6 +114,7 @@ func init() {
Placeholder: "comma-separated list",
PropertyName: "userKey",
Required: true,
Secure: true,
},
{
Label: "Device(s) (optional)",

View File

@@ -18,41 +18,6 @@ func init() {
Description: "Sends HTTP POST request to a Sensu API",
Heading: "Sensu settings",
Factory: NewSensuNotifier,
OptionsTemplate: `
<h3 class="page-heading">Sensu settings</h3>
<div class="gf-form">
<span class="gf-form-label width-10">Url</span>
<input type="text" required class="gf-form-input max-width-26" ng-model="ctrl.model.settings.url" placeholder="http://sensu-api.local:4567/results"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">Source</span>
<input type="text" class="gf-form-input max-width-14" ng-model="ctrl.model.settings.source" bs-tooltip="'If empty rule id will be used'" data-placement="right"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">Handler</span>
<input type="text" class="gf-form-input max-width-14" ng-model="ctrl.model.settings.handler" placeholder="default"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">Username</span>
<input type="text" class="gf-form-input max-width-14" ng-model="ctrl.model.settings.username"></input>
</div>
<div class="gf-form">
<label class="gf-form-label width-10">Password</label>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.password">
<input type="text"
required
class="gf-form-input max-width-14"
ng-init="ctrl.model.secureSettings.password = ctrl.model.settings.password || null; ctrl.model.settings.password = null;"
ng-model="ctrl.model.secureSettings.password"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.password">
<input type="text" class="gf-form-input max-width-14" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.password = false">reset</a>
</div>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Url",
@@ -87,6 +52,7 @@ func init() {
Element: alerting.ElementTypeInput,
InputType: alerting.InputTypePassword,
PropertyName: "passsword ",
Secure: true,
},
},
})

View File

@@ -27,123 +27,6 @@ func init() {
Description: "Sends notifications to Slack via Slack Webhooks",
Heading: "Slack settings",
Factory: NewSlackNotifier,
OptionsTemplate: `
<h3 class="page-heading">Slack settings</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Url</span>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.url">
<input type="text"
required
class="gf-form-input max-width-30"
ng-init="ctrl.model.secureSettings.url = ctrl.model.settings.url || null; ctrl.model.settings.url = null;"
ng-model="ctrl.model.secureSettings.url"
placeholder="Slack incoming webhook url">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.url">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.url = false">reset</a>
</div>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Recipient</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.recipient"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Override default channel or user, use #channel-name, @username (has to be all lowercase, no whitespace), or user/channel Slack ID
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Username</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.username"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Set the username for the bot's message
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Icon emoji</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.icon_emoji"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Provide an emoji to use as the icon for the bot's message. Overrides the icon URL
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Icon URL</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.icon_url"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Provide a URL to an image to use as the icon for the bot's message
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Mention Users</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.mentionUsers"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Mention one or more users (comma separated) when notifying in a channel, by ID (you can copy this from the user's Slack profile)
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Mention Groups</span>
<input type="text"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.mentionGroups"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Mention one or more groups (comma separated) when notifying in a channel (you can copy this from the group's Slack profile URL)
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Mention Channel</span>
<select
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.mentionChannel"
data-placement="right">
<option value="">Disabled</option>
<option value="here">Every active channel member</option>
<option value="channel">Every channel member</option>
</select>
<info-popover mode="right-absolute">
Mention whole channel or just active members when notifying
</info-popover>
</div>
<div class="gf-form max-width-30">
<div class="gf-form gf-form--v-stretch"><label class="gf-form-label width-8">Token</label></div>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.token">
<input type="text"
class="gf-form-input max-width-30"
ng-init="ctrl.model.secureSettings.token = ctrl.model.settings.token || null; ctrl.model.settings.token = null;"
ng-model="ctrl.model.secureSettings.token"
data-placement="right">
</input>
<info-popover mode="right-absolute">
Provide a bot token to use the Slack file.upload API (starts with "xoxb"). Specify Recipient for this to work
</info-popover>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.token">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.token = false">reset</a>
</div>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Url",
@@ -152,6 +35,7 @@ func init() {
Placeholder: "Slack incoming webhook url",
PropertyName: "url",
Required: true,
Secure: true,
},
{
Label: "Recipient",
@@ -172,14 +56,14 @@ func init() {
Element: alerting.ElementTypeInput,
InputType: alerting.InputTypeText,
Description: "Provide an emoji to use as the icon for the bot's message. Overrides the icon URL.",
PropertyName: "icon_emoji",
PropertyName: "iconEmoji",
},
{
Label: "Icon URL",
Element: alerting.ElementTypeInput,
InputType: alerting.InputTypeText,
Description: "Provide a URL to an image to use as the icon for the bot's message",
PropertyName: "icon_url",
PropertyName: "iconUrl",
},
{
Label: "Mention Users",
@@ -221,6 +105,7 @@ func init() {
InputType: alerting.InputTypeText,
Description: "Provide a bot token to use the Slack file.upload API (starts with \"xoxb\"). Specify Recipient for this to work",
PropertyName: "token",
Secure: true,
},
},
})

View File

@@ -16,13 +16,6 @@ func init() {
Description: "Sends notifications using Incoming Webhook connector to Microsoft Teams",
Heading: "Teams settings",
Factory: NewTeamsNotifier,
OptionsTemplate: `
<h3 class="page-heading">Teams settings</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-6">Url</span>
<input type="text" InputType class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="Teams incoming webhook url"></input>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "URL",
@@ -30,6 +23,7 @@ func init() {
InputType: alerting.InputTypeText,
Placeholder: "Teams incoming webhook url",
PropertyName: "url",
Required: true,
},
},
})

View File

@@ -28,37 +28,6 @@ func init() {
Description: "Sends notifications to Telegram",
Heading: "Telegram API settings",
Factory: NewTelegramNotifier,
OptionsTemplate: `
<h3 class="page-heading">Telegram API settings</h3>
<div class="gf-form max-width-30">
<label class="gf-form-label width-10">BOT API Token</label>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.bottoken">
<input type="text"
required
class="gf-form-input max-width-30"
ng-init="ctrl.model.secureSettings.bottoken = ctrl.model.settings.bottoken || null; ctrl.model.settings.bottoken = null;"
ng-model="ctrl.model.secureSettings.bottoken"
placeholder="Telegram BOT API Token"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.bottoken">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.bottoken = false">reset</a>
</div>
</div>
<div class="gf-form max-width-30">
<label class="gf-form-label width-10">Chat ID</label>
<input type="text"
required
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.chatid"
placeholder="Telegram Chat ID"
data-placement="right">
</input>
<info-popover mode="right-absolute">Integer Telegram Chat Identifier</info-popover>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "BOT API Token",
@@ -67,6 +36,7 @@ func init() {
Placeholder: "Telegram BOT API Token",
PropertyName: "bottoken",
Required: true,
Secure: true,
},
{
Label: "Chat ID",

View File

@@ -24,55 +24,6 @@ func init() {
Info: "Notifications can be configured for any Threema Gateway ID of type \"Basic\". End-to-End IDs are not currently supported." +
"The Threema Gateway ID can be set up at https://gateway.threema.ch/.",
Factory: NewThreemaNotifier,
OptionsTemplate: `
<h3 class="page-heading">Threema Gateway settings</h3>
<p>
Notifications can be configured for any Threema Gateway ID of type
"Basic". End-to-End IDs are not currently supported.
</p>
<p>
The Threema Gateway ID can be set up at
<a href="https://gateway.threema.ch/" target="_blank" rel="noopener noreferrer">https://gateway.threema.ch/</a>.
</p>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Gateway ID</span>
<input type="text" required maxlength="8" pattern="\*[0-9A-Z]{7}"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.gateway_id"
placeholder="*3MAGWID">
</input>
<info-popover mode="right-absolute">
Your 8 character Threema Gateway ID (starting with a *)
</info-popover>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Recipient ID</span>
<input type="text" required maxlength="8" pattern="[0-9A-Z]{8}"
class="gf-form-input max-width-30"
ng-model="ctrl.model.settings.recipient_id"
placeholder="YOUR3MID">
</input>
<info-popover mode="right-absolute">
The 8 character Threema ID that should receive the alerts
</info-popover>
</div>
<div class="gf-form max-width-30">
<label class="gf-form-label width-8">API Secret</label>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.api_secret">
<input type="text"
required
class="gf-form-input max-width-30"
ng-init="ctrl.model.secureSettings.api_secret = ctrl.model.settings.api_secret || null; ctrl.model.settings.api_secret = null;"
ng-model="ctrl.model.secureSettings.api_secret"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.api_secret">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.api_secret = false">reset</a>
</div>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Gateway ID",
@@ -101,6 +52,7 @@ func init() {
Description: "Your Threema Gateway API secret.",
PropertyName: "api_secret",
Required: true,
Secure: true,
},
},
})

View File

@@ -25,29 +25,6 @@ func init() {
Description: "Sends notifications to VictorOps",
Heading: "VictorOps settings",
Factory: NewVictoropsNotifier,
OptionsTemplate: `
<h3 class="page-heading">VictorOps settings</h3>
<div class="gf-form">
<span class="gf-form-label width-6">Url</span>
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="VictorOps url"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-10">No Data Alert Type</span>
<div class="gf-form-select-wrapper width-14">
<select class="gf-form-input" ng-model="ctrl.model.settings.noDataAlertType" ng-options="t for t in ['CRITICAL', 'WARNING']" ng-init="ctrl.model.settings.noDataAlertType=ctrl.model.settings.noDataAlertType || '` + AlertStateWarning + `'">
</select>
</div>
</div>
<div class="gf-form">
<gf-form-switch
class="gf-form"
label="Auto resolve incidents"
label-class="width-14"
checked="ctrl.model.settings.autoResolve"
tooltip="Resolve incidents in VictorOps once the alert goes back to ok.">
</gf-form-switch>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Url",
@@ -60,7 +37,7 @@ func init() {
{
Label: "Auto resolve incidents",
Description: "Resolve incidents in VictorOps once the alert goes back to ok.",
Element: alerting.ElementTypeSwitch,
Element: alerting.ElementTypeCheckbox,
PropertyName: "autoResolve",
},
},

View File

@@ -15,39 +15,6 @@ func init() {
Description: "Sends HTTP POST request to a URL",
Heading: "Webhook settings",
Factory: NewWebHookNotifier,
OptionsTemplate: `
<h3 class="page-heading">Webhook settings</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Url</span>
<input type="text" required class="gf-form-input max-width-26" ng-model="ctrl.model.settings.url"></input>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Http Method</span>
<div class="gf-form-select-wrapper max-width-30">
<select class="gf-form-input" ng-model="ctrl.model.settings.httpMethod" ng-options="t for t in ['POST', 'PUT']">
</select>
</div>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Username</span>
<input type="text" class="gf-form-input max-width-30" ng-model="ctrl.model.settings.username"></input>
</div>
<div class="gf-form max-width-30">
<div class="gf-form gf-form--v-stretch"><label class="gf-form-label width-8">Password</label></div>
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.password">
<input type="text"
class="gf-form-input max-width-30"
ng-init="ctrl.model.secureSettings.password = ctrl.model.settings.password || null; ctrl.model.settings.password = null;"
ng-model="ctrl.model.secureSettings.password"
data-placement="right">
</input>
</div>
<div class="gf-form" ng-if="ctrl.model.secureFields.password">
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.password = false">reset</a>
</div>
</div>
`,
Options: []alerting.NotifierOption{
{
Label: "Url",
@@ -82,6 +49,7 @@ func init() {
Element: alerting.ElementTypeInput,
InputType: alerting.InputTypePassword,
PropertyName: "password",
Secure: true,
},
},
})