Skip to content

Commit d189c42

Browse files
feat(slack): Add option to include monitor group name in notifications (#6835)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 247bbdf commit d189c42

File tree

3 files changed

+114
-14
lines changed

3 files changed

+114
-14
lines changed

server/notification-providers/slack.js

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,10 @@ class Slack extends NotificationProvider {
7575
* @param {object} heartbeatJSON The heartbeat object
7676
* @param {string} title The message title
7777
* @param {string} msg The message body
78+
* @param {boolean} includeGroupName Whether to include group name in the message
7879
* @returns {Array<object>} The rich content blocks for the Slack message
7980
*/
80-
buildBlocks(baseURL, monitorJSON, heartbeatJSON, title, msg) {
81+
buildBlocks(baseURL, monitorJSON, heartbeatJSON, title, msg, includeGroupName) {
8182
//create an array to dynamically add blocks
8283
const blocks = [];
8384

@@ -91,17 +92,19 @@ class Slack extends NotificationProvider {
9192
});
9293

9394
// Optional context line for monitor group path (excluding monitor name)
94-
const groupPath = monitorJSON?.path?.length > 1 ? monitorJSON.path.slice(0, -1).join(" / ") : "";
95-
if (groupPath) {
96-
blocks.push({
97-
type: "context",
98-
elements: [
99-
{
100-
type: "mrkdwn",
101-
text: `_${groupPath}_`,
102-
},
103-
],
104-
});
95+
if (includeGroupName) {
96+
const groupPath = monitorJSON?.path?.length > 1 ? monitorJSON.path.slice(0, -1).join(" / ") : "";
97+
if (groupPath) {
98+
blocks.push({
99+
type: "context",
100+
elements: [
101+
{
102+
type: "mrkdwn",
103+
text: `_${groupPath}_`,
104+
},
105+
],
106+
});
107+
}
105108
}
106109

107110
// the body block, containing the details
@@ -156,6 +159,31 @@ class Slack extends NotificationProvider {
156159

157160
const baseURL = await setting("primaryBaseURL");
158161

162+
// Check if templating is enabled
163+
if (notification.slackUseTemplate) {
164+
const renderedText = await this.renderTemplate(
165+
notification.slackTemplate,
166+
msg,
167+
monitorJSON,
168+
heartbeatJSON
169+
);
170+
171+
let data = {
172+
text: renderedText,
173+
channel: notification.slackchannel,
174+
username: notification.slackusername,
175+
icon_emoji: notification.slackiconemo,
176+
};
177+
178+
await axios.post(notification.slackwebhookURL, data, config);
179+
return okMsg;
180+
}
181+
182+
const includeGroupName = notification.slackIncludeGroupName ?? true;
183+
184+
const groupPath =
185+
includeGroupName && monitorJSON?.path?.length > 1 ? monitorJSON.path.slice(0, -1).join(" / ") : "";
186+
159187
const title = monitorJSON?.name || "Uptime Kuma Alert";
160188
let data = {
161189
text: msg,
@@ -168,10 +196,15 @@ class Slack extends NotificationProvider {
168196
if (notification.slackrichmessage) {
169197
data.attachments.push({
170198
color: heartbeatJSON["status"] === UP ? "#2eb886" : "#e01e5a",
171-
blocks: this.buildBlocks(baseURL, monitorJSON, heartbeatJSON, title, msg),
199+
blocks: this.buildBlocks(baseURL, monitorJSON, heartbeatJSON, title, msg, includeGroupName),
172200
});
173201
} else {
174-
data.text = `${title}\n${msg}`;
202+
// Include group name in plain text messages if enabled
203+
if (includeGroupName && groupPath) {
204+
data.text = `_${groupPath}_\n${title}\n${msg}`;
205+
} else {
206+
data.text = `${title}\n${msg}`;
207+
}
175208
}
176209

177210
if (notification.slackbutton) {

src/components/notifications/Slack.vue

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,43 @@
3232
<label for="slack-text-message" class="form-label">{{ $t("Send rich messages") }}</label>
3333
</div>
3434

35+
<div class="mb-3">
36+
<div class="form-check form-switch">
37+
<input
38+
id="slack-include-group-name"
39+
v-model="$parent.notification.slackIncludeGroupName"
40+
type="checkbox"
41+
class="form-check-input"
42+
/>
43+
<label for="slack-include-group-name" class="form-check-label">{{ $t("slackIncludeGroupName") }}</label>
44+
</div>
45+
<div class="form-text">
46+
{{ $t("slackIncludeGroupNameDescription") }}
47+
</div>
48+
</div>
49+
50+
<div class="mb-3">
51+
<div class="form-check form-switch">
52+
<input v-model="$parent.notification.slackUseTemplate" class="form-check-input" type="checkbox" />
53+
<label class="form-check-label">{{ $t("slackUseTemplate") }}</label>
54+
</div>
55+
<div class="form-text">
56+
{{ $t("slackUseTemplateDescription") }}
57+
</div>
58+
</div>
59+
60+
<template v-if="$parent.notification.slackUseTemplate">
61+
<div class="mb-3">
62+
<label class="form-label" for="slack-message-template">{{ $t("Message Template") }}</label>
63+
<TemplatedTextarea
64+
id="slack-message-template"
65+
v-model="$parent.notification.slackTemplate"
66+
:required="true"
67+
:placeholder="slackTemplatedTextareaPlaceholder"
68+
></TemplatedTextarea>
69+
</div>
70+
</template>
71+
3572
<div class="form-text">
3673
<span style="color: red"><sup>*</sup></span>
3774
{{ $t("Required") }}
@@ -67,3 +104,29 @@
67104
</div>
68105
</div>
69106
</template>
107+
108+
<script>
109+
import TemplatedTextarea from "../TemplatedTextarea.vue";
110+
111+
export default {
112+
components: {
113+
TemplatedTextarea,
114+
},
115+
computed: {
116+
slackTemplatedTextareaPlaceholder() {
117+
return this.$t("Example:", [
118+
`
119+
Uptime Kuma Alert{% if monitorJSON %} - {{ monitorJSON['name'] }}{% endif %}
120+
{% if monitorJSON and monitorJSON.path and monitorJSON.path.length > 1 %}_{{ monitorJSON.path.slice(0, -1).join(' / ') }}_\n{% endif %}
121+
{{ msg }}
122+
`,
123+
]);
124+
},
125+
},
126+
mounted() {
127+
if (typeof this.$parent.notification.slackIncludeGroupName === "undefined") {
128+
this.$parent.notification.slackIncludeGroupName = true;
129+
}
130+
},
131+
};
132+
</script>

src/lang/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,10 @@
863863
"see Jira Cloud Docs": "see Jira Cloud Docs",
864864
"Jira Service Management": "Jira Service Management",
865865
"aboutSlackUsername": "Changes the display name of the message sender. If you want to mention someone, include it in the friendly name instead.",
866+
"slackIncludeGroupName": "Include monitor group name",
867+
"slackIncludeGroupNameDescription": "If enabled, the monitor group path will be included in notifications to help distinguish monitors with the same name across different groups.",
868+
"slackUseTemplate": "Use custom message template",
869+
"slackUseTemplateDescription": "If enabled, the message will be sent using a custom template. You can use Liquid templating to include monitor group information via monitorJSON.path or monitorJSON.pathName.",
866870
"aboutChannelName": "Enter the channel name on {0} Channel Name field if you want to bypass the Webhook channel. Ex: #other-channel",
867871
"aboutKumaURL": "If you leave the Uptime Kuma URL field blank, it will default to the Project GitHub page.",
868872
"smtpDkimSettings": "DKIM Settings",

0 commit comments

Comments
 (0)