From 52a73125f997d7ea506df83aa2ac75cbcccd948d Mon Sep 17 00:00:00 2001 From: Tim <56877639+Tim-orius@users.noreply.github.com> Date: Wed, 20 Nov 2024 02:24:17 +0100 Subject: [PATCH] feat(alerting): Update Adaptive Cards design for teams-workflows (#903) Update adaptive cards design for msteams Co-authored-by: Tim-orius --- .../provider/teamsworkflows/teamsworkflows.go | 57 +++++++++++++------ .../teamsworkflows/teamsworkflows_test.go | 6 +- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/alerting/provider/teamsworkflows/teamsworkflows.go b/alerting/provider/teamsworkflows/teamsworkflows.go index 104e2d26..792ef749 100644 --- a/alerting/provider/teamsworkflows/teamsworkflows.go +++ b/alerting/provider/teamsworkflows/teamsworkflows.go @@ -68,9 +68,10 @@ func (provider *AlertProvider) Send(ep *endpoint.Endpoint, alert *alert.Alert, r // AdaptiveCardBody represents the structure of an Adaptive Card type AdaptiveCardBody struct { - Type string `json:"type"` - Version string `json:"version"` - Body []CardBody `json:"body"` + Type string `json:"type"` + Version string `json:"version"` + Body []CardBody `json:"body"` + MSTeams MSTeamsBody `json:"msteams"` } // CardBody represents the body of the Adaptive Card @@ -84,6 +85,12 @@ type CardBody struct { Items []CardBody `json:"items,omitempty"` Facts []Fact `json:"facts,omitempty"` FactSet *FactSetBody `json:"factSet,omitempty"` + Style string `json:"style,omitempty"` +} + +// MSTeamsBody represents the msteams options +type MSTeamsBody struct { + Width string `json:"width"` } // FactSetBody represents the FactSet in the Adaptive Card @@ -101,10 +108,13 @@ type Fact struct { // buildRequestBody builds the request body for the provider func (provider *AlertProvider) buildRequestBody(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) []byte { var message string + var themeColor string if resolved { message = fmt.Sprintf("An alert for **%s** has been resolved after passing successfully %d time(s) in a row.", ep.DisplayName(), alert.SuccessThreshold) + themeColor = "Good" // green } else { message = fmt.Sprintf("An alert for **%s** has been triggered due to having failed %d time(s) in a row.", ep.DisplayName(), alert.FailureThreshold) + themeColor = "Attention" // red } // Configure default title if it's not provided @@ -133,21 +143,36 @@ func (provider *AlertProvider) buildRequestBody(ep *endpoint.Endpoint, alert *al Version: "1.4", // Version 1.5 and 1.6 doesn't seem to be supported by Teams as of 27/08/2024 Body: []CardBody{ { - Type: "TextBlock", - Text: title, - Size: "Medium", - Weight: "Bolder", - }, - { - Type: "TextBlock", - Text: message, - Wrap: true, - }, - { - Type: "FactSet", - Facts: facts, + Type: "Container", + Style: themeColor, + Items: []CardBody{ + { + Type: "Container", + Style: "Default", + Items: []CardBody{ + { + Type: "TextBlock", + Text: title, + Size: "Medium", + Weight: "Bolder", + }, + { + Type: "TextBlock", + Text: message, + Wrap: true, + }, + { + Type: "FactSet", + Facts: facts, + }, + }, + }, + }, }, }, + MSTeams: MSTeamsBody{ + Width: "Full", + }, } attachment := map[string]interface{}{ diff --git a/alerting/provider/teamsworkflows/teamsworkflows_test.go b/alerting/provider/teamsworkflows/teamsworkflows_test.go index 6e4a9940..c6221ef1 100644 --- a/alerting/provider/teamsworkflows/teamsworkflows_test.go +++ b/alerting/provider/teamsworkflows/teamsworkflows_test.go @@ -152,14 +152,14 @@ func TestAlertProvider_buildRequestBody(t *testing.T) { Provider: AlertProvider{}, Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3}, Resolved: false, - ExpectedBody: "{\"attachments\":[{\"content\":{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"TextBlock\",\"text\":\"\\u0026#x26D1; Gatus\",\"wrap\":false,\"size\":\"Medium\",\"weight\":\"Bolder\"},{\"type\":\"TextBlock\",\"text\":\"An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row.\",\"wrap\":true},{\"type\":\"FactSet\",\"wrap\":false,\"facts\":[{\"title\":\"\\u0026#x274C;\",\"value\":\"[CONNECTED] == true\"},{\"title\":\"\\u0026#x274C;\",\"value\":\"[STATUS] == 200\"}]}]},\"contentType\":\"application/vnd.microsoft.card.adaptive\"}],\"type\":\"message\"}", + ExpectedBody: "{\"attachments\":[{\"content\":{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"Container\",\"wrap\":false,\"items\":[{\"type\":\"Container\",\"wrap\":false,\"items\":[{\"type\":\"TextBlock\",\"text\":\"\\u0026#x26D1; Gatus\",\"wrap\":false,\"size\":\"Medium\",\"weight\":\"Bolder\"},{\"type\":\"TextBlock\",\"text\":\"An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row.\",\"wrap\":true},{\"type\":\"FactSet\",\"wrap\":false,\"facts\":[{\"title\":\"\\u0026#x274C;\",\"value\":\"[CONNECTED] == true\"},{\"title\":\"\\u0026#x274C;\",\"value\":\"[STATUS] == 200\"}]}],\"style\":\"Default\"}],\"style\":\"Attention\"}],\"msteams\":{\"width\":\"Full\"}},\"contentType\":\"application/vnd.microsoft.card.adaptive\"}],\"type\":\"message\"}", }, { Name: "resolved", Provider: AlertProvider{}, Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3}, Resolved: true, - ExpectedBody: "{\"attachments\":[{\"content\":{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"TextBlock\",\"text\":\"\\u0026#x26D1; Gatus\",\"wrap\":false,\"size\":\"Medium\",\"weight\":\"Bolder\"},{\"type\":\"TextBlock\",\"text\":\"An alert for **endpoint-name** has been resolved after passing successfully 5 time(s) in a row.\",\"wrap\":true},{\"type\":\"FactSet\",\"wrap\":false,\"facts\":[{\"title\":\"\\u0026#x2705;\",\"value\":\"[CONNECTED] == true\"},{\"title\":\"\\u0026#x2705;\",\"value\":\"[STATUS] == 200\"}]}]},\"contentType\":\"application/vnd.microsoft.card.adaptive\"}],\"type\":\"message\"}", + ExpectedBody: "{\"attachments\":[{\"content\":{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"Container\",\"wrap\":false,\"items\":[{\"type\":\"Container\",\"wrap\":false,\"items\":[{\"type\":\"TextBlock\",\"text\":\"\\u0026#x26D1; Gatus\",\"wrap\":false,\"size\":\"Medium\",\"weight\":\"Bolder\"},{\"type\":\"TextBlock\",\"text\":\"An alert for **endpoint-name** has been resolved after passing successfully 5 time(s) in a row.\",\"wrap\":true},{\"type\":\"FactSet\",\"wrap\":false,\"facts\":[{\"title\":\"\\u0026#x2705;\",\"value\":\"[CONNECTED] == true\"},{\"title\":\"\\u0026#x2705;\",\"value\":\"[STATUS] == 200\"}]}],\"style\":\"Default\"}],\"style\":\"Good\"}],\"msteams\":{\"width\":\"Full\"}},\"contentType\":\"application/vnd.microsoft.card.adaptive\"}],\"type\":\"message\"}", }, { Name: "resolved-with-no-conditions", @@ -167,7 +167,7 @@ func TestAlertProvider_buildRequestBody(t *testing.T) { Provider: AlertProvider{}, Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3}, Resolved: true, - ExpectedBody: "{\"attachments\":[{\"content\":{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"TextBlock\",\"text\":\"\\u0026#x26D1; Gatus\",\"wrap\":false,\"size\":\"Medium\",\"weight\":\"Bolder\"},{\"type\":\"TextBlock\",\"text\":\"An alert for **endpoint-name** has been resolved after passing successfully 5 time(s) in a row.\",\"wrap\":true},{\"type\":\"FactSet\",\"wrap\":false}]},\"contentType\":\"application/vnd.microsoft.card.adaptive\"}],\"type\":\"message\"}", + ExpectedBody: "{\"attachments\":[{\"content\":{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"Container\",\"wrap\":false,\"items\":[{\"type\":\"Container\",\"wrap\":false,\"items\":[{\"type\":\"TextBlock\",\"text\":\"\\u0026#x26D1; Gatus\",\"wrap\":false,\"size\":\"Medium\",\"weight\":\"Bolder\"},{\"type\":\"TextBlock\",\"text\":\"An alert for **endpoint-name** has been resolved after passing successfully 5 time(s) in a row.\",\"wrap\":true},{\"type\":\"FactSet\",\"wrap\":false}],\"style\":\"Default\"}],\"style\":\"Good\"}],\"msteams\":{\"width\":\"Full\"}},\"contentType\":\"application/vnd.microsoft.card.adaptive\"}],\"type\":\"message\"}", }, } for _, scenario := range scenarios {