diff --git a/pkg/services/ngalert/notifier/available_channels.go b/pkg/services/ngalert/notifier/available_channels.go index 317b59db4bb..7c197f68a72 100644 --- a/pkg/services/ngalert/notifier/available_channels.go +++ b/pkg/services/ngalert/notifier/available_channels.go @@ -562,6 +562,21 @@ func GetAvailableNotifiers() []*alerting.NotifierPlugin { PropertyName: "url", Required: true, }, + { + Label: "Title", + Element: alerting.ElementTypeInput, + InputType: alerting.InputTypeText, + Description: "Templated title of the Teams message.", + PropertyName: "title", + Placeholder: `{{ template "default.title" . }}`, + }, + { + Label: "Section Title", + Element: alerting.ElementTypeInput, + InputType: alerting.InputTypeText, + Description: "Section title for the Teams message. Leave blank for none.", + PropertyName: "sectiontitle", + }, { // New in 8.0. Label: "Message", Element: alerting.ElementTypeTextArea, diff --git a/pkg/services/ngalert/notifier/channels/teams.go b/pkg/services/ngalert/notifier/channels/teams.go index f358084fd1e..0fc0ea9b918 100644 --- a/pkg/services/ngalert/notifier/channels/teams.go +++ b/pkg/services/ngalert/notifier/channels/teams.go @@ -17,17 +17,21 @@ import ( // alert notifications to Microsoft teams. type TeamsNotifier struct { *Base - URL string - Message string - tmpl *template.Template - log log.Logger - ns notifications.WebhookSender + URL string + Message string + Title string + SectionTitle string + tmpl *template.Template + log log.Logger + ns notifications.WebhookSender } type TeamsConfig struct { *NotificationChannelConfig - URL string - Message string + URL string + Message string + Title string + SectionTitle string } func TeamsFactory(fc FactoryConfig) (NotificationChannel, error) { @@ -50,6 +54,8 @@ func NewTeamsConfig(config *NotificationChannelConfig) (*TeamsConfig, error) { NotificationChannelConfig: config, URL: URL, Message: config.Settings.Get("message").MustString(`{{ template "teams.default.message" .}}`), + Title: config.Settings.Get("title").MustString(DefaultMessageTitleEmbed), + SectionTitle: config.Settings.Get("sectiontitle").MustString(""), }, nil } @@ -63,11 +69,13 @@ func NewTeamsNotifier(config *TeamsConfig, ns notifications.WebhookSender, t *te DisableResolveMessage: config.DisableResolveMessage, Settings: config.Settings, }), - URL: config.URL, - Message: config.Message, - log: log.New("alerting.notifier.teams"), - ns: ns, - tmpl: t, + URL: config.URL, + Message: config.Message, + Title: config.Title, + SectionTitle: config.SectionTitle, + log: log.New("alerting.notifier.teams"), + ns: ns, + tmpl: t, } } @@ -78,7 +86,7 @@ func (tn *TeamsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool, ruleURL := joinUrlPath(tn.tmpl.ExternalURL.String(), "/alerting/list", tn.log) - title := tmpl(DefaultMessageTitleEmbed) + title := tmpl(tn.Title) body := map[string]interface{}{ "@type": "MessageCard", "@context": "http://schema.org/extensions", @@ -89,7 +97,7 @@ func (tn *TeamsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool, "themeColor": getAlertStatusColor(types.Alerts(as...).Status()), "sections": []map[string]interface{}{ { - "title": "Details", + "title": tmpl(tn.SectionTitle), "text": tmpl(tn.Message), }, }, diff --git a/pkg/services/ngalert/notifier/channels/teams_test.go b/pkg/services/ngalert/notifier/channels/teams_test.go index f91322c3905..3e0ed242454 100644 --- a/pkg/services/ngalert/notifier/channels/teams_test.go +++ b/pkg/services/ngalert/notifier/channels/teams_test.go @@ -48,7 +48,7 @@ func TestTeamsNotifier(t *testing.T) { "themeColor": "#D63232", "sections": []map[string]interface{}{ { - "title": "Details", + "title": "", "text": "**Firing**\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval1\nDashboard: http://localhost/d/abcd\nPanel: http://localhost/d/abcd?viewPanel=efgh\n", }, }, @@ -66,6 +66,8 @@ func TestTeamsNotifier(t *testing.T) { name: "Custom config with multiple alerts", settings: `{ "url": "http://localhost", + "title": "{{ .CommonLabels.alertname }}", + "sectiontitle": "Details", "message": "{{ len .Alerts.Firing }} alerts are firing, {{ len .Alerts.Resolved }} are resolved" }`, alerts: []*types.Alert{ @@ -84,8 +86,8 @@ func TestTeamsNotifier(t *testing.T) { expMsg: map[string]interface{}{ "@type": "MessageCard", "@context": "http://schema.org/extensions", - "summary": "[FIRING:2] ", - "title": "[FIRING:2] ", + "summary": "alert1", + "title": "alert1", "themeColor": "#D63232", "sections": []map[string]interface{}{ { @@ -107,6 +109,8 @@ func TestTeamsNotifier(t *testing.T) { name: "Missing field in template", settings: `{ "url": "http://localhost", + "title": "{{ .CommonLabels.alertname }}", + "sectiontitle": "Details", "message": "I'm a custom template {{ .NotAField }} bad template" }`, alerts: []*types.Alert{ @@ -125,8 +129,8 @@ func TestTeamsNotifier(t *testing.T) { expMsg: map[string]interface{}{ "@type": "MessageCard", "@context": "http://schema.org/extensions", - "summary": "[FIRING:2] ", - "title": "[FIRING:2] ", + "summary": "alert1", + "title": "alert1", "themeColor": "#D63232", "sections": []map[string]interface{}{ { @@ -148,6 +152,8 @@ func TestTeamsNotifier(t *testing.T) { name: "Invalid template", settings: `{ "url": "http://localhost", + "title": "{{ .CommonLabels.alertname }}", + "sectiontitle": "Details", "message": "I'm a custom template {{ {.NotAField }} bad template" }`, alerts: []*types.Alert{ @@ -166,8 +172,8 @@ func TestTeamsNotifier(t *testing.T) { expMsg: map[string]interface{}{ "@type": "MessageCard", "@context": "http://schema.org/extensions", - "summary": "[FIRING:2] ", - "title": "[FIRING:2] ", + "summary": "alert1", + "title": "alert1", "themeColor": "#D63232", "sections": []map[string]interface{}{ { diff --git a/pkg/tests/api/alerting/api_notification_channel_test.go b/pkg/tests/api/alerting/api_notification_channel_test.go index 796c16a5a58..3938fbae033 100644 --- a/pkg/tests/api/alerting/api_notification_channel_test.go +++ b/pkg/tests/api/alerting/api_notification_channel_test.go @@ -2226,7 +2226,7 @@ var expNonEmailNotifications = map[string][]string{ "sections": [ { "text": "**Firing**\n\nValue: [ var='A' labels={} value=1 ]\nLabels:\n - alertname = TeamsAlert\nAnnotations:\nSource: http://localhost:3000/alerting/grafana/UID_TeamsAlert/view\nSilence: http://localhost:3000/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DTeamsAlert\n", - "title": "Details" + "title": "" } ], "summary": "[FIRING:1] TeamsAlert ",