mirror of
https://github.com/louislam/uptime-kuma.git
synced 2026-01-31 11:03:11 +08:00
feat(discord): add custom message and format presets for notifications (#6843)
Co-authored-by: epifeny <epifeny@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"description": "RDAP bootstrap file for Domain Name System registrations",
|
||||
"publication": "2025-12-11T00:00:01Z",
|
||||
"publication": "2026-01-30T00:00:01Z",
|
||||
"services": [
|
||||
[["kg"], ["http://rdap.cctld.kg/"]],
|
||||
[["mg"], ["http://rdap.nic.mg/"]],
|
||||
[["ng"], ["http://rdap.nic.net.ng/"]],
|
||||
[["xn--kpry57d"], ["https://ccrdap.twnic.tw/taiwan/"]],
|
||||
[["tw"], ["https://ccrdap.twnic.tw/tw/"]],
|
||||
[["na"], ["https://keetmans.omadhina.co.na/"]],
|
||||
|
||||
@@ -34,11 +34,23 @@ class Discord extends NotificationProvider {
|
||||
webhookHasAvatar = true;
|
||||
}
|
||||
|
||||
const messageFormat =
|
||||
notification.discordMessageFormat || (notification.discordUseMessageTemplate ? "custom" : "normal");
|
||||
|
||||
// If heartbeatJSON is null, assume we're testing.
|
||||
if (heartbeatJSON == null) {
|
||||
let content = msg;
|
||||
if (messageFormat === "minimalist") {
|
||||
content = "Test: " + msg;
|
||||
} else if (messageFormat === "custom") {
|
||||
const customMessage = notification.discordMessageTemplate?.trim() || "";
|
||||
if (customMessage !== "") {
|
||||
content = await this.renderTemplate(customMessage, msg, monitorJSON, heartbeatJSON);
|
||||
}
|
||||
}
|
||||
let discordtestdata = {
|
||||
username: discordDisplayName,
|
||||
content: msg,
|
||||
content: content,
|
||||
};
|
||||
if (!webhookHasAvatar) {
|
||||
discordtestdata.avatar_url = "https://github.com/louislam/uptime-kuma/raw/master/public/icon.png";
|
||||
@@ -55,6 +67,57 @@ class Discord extends NotificationProvider {
|
||||
|
||||
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
||||
let addess = this.extractAddress(monitorJSON);
|
||||
|
||||
// Minimalist: status + name only (is down / is up; no "back up" — may be first trigger)
|
||||
if (messageFormat === "minimalist") {
|
||||
const content =
|
||||
heartbeatJSON["status"] === DOWN
|
||||
? "🔴 " + monitorJSON["name"] + " is down."
|
||||
: "🟢 " + monitorJSON["name"] + " is up.";
|
||||
let payload = {
|
||||
username: discordDisplayName,
|
||||
content: content,
|
||||
};
|
||||
if (!webhookHasAvatar) {
|
||||
payload.avatar_url = "https://github.com/louislam/uptime-kuma/raw/master/public/icon.png";
|
||||
}
|
||||
if (notification.discordChannelType === "createNewForumPost") {
|
||||
payload.thread_name = notification.postName;
|
||||
}
|
||||
if (notification.discordSuppressNotifications) {
|
||||
payload.flags = SUPPRESS_NOTIFICATIONS_FLAG;
|
||||
}
|
||||
await axios.post(webhookUrl.toString(), payload, config);
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
// Custom template: send only content (no embeds)
|
||||
const useCustomTemplate =
|
||||
messageFormat === "custom" && (notification.discordMessageTemplate?.trim() || "") !== "";
|
||||
if (useCustomTemplate) {
|
||||
const content = await this.renderTemplate(
|
||||
notification.discordMessageTemplate.trim(),
|
||||
msg,
|
||||
monitorJSON,
|
||||
heartbeatJSON
|
||||
);
|
||||
let payload = {
|
||||
username: discordDisplayName,
|
||||
content: content,
|
||||
};
|
||||
if (!webhookHasAvatar) {
|
||||
payload.avatar_url = "https://github.com/louislam/uptime-kuma/raw/master/public/icon.png";
|
||||
}
|
||||
if (notification.discordChannelType === "createNewForumPost") {
|
||||
payload.thread_name = notification.postName;
|
||||
}
|
||||
if (notification.discordSuppressNotifications) {
|
||||
payload.flags = SUPPRESS_NOTIFICATIONS_FLAG;
|
||||
}
|
||||
await axios.post(webhookUrl.toString(), payload, config);
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
if (heartbeatJSON["status"] === DOWN) {
|
||||
const wentOfflineTimestamp = Math.floor(new Date(heartbeatJSON["time"]).getTime() / 1000);
|
||||
|
||||
|
||||
@@ -38,6 +38,28 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="discord-message-format" class="form-label">{{ $t("discordMessageFormat") }}</label>
|
||||
<select id="discord-message-format" v-model="$parent.notification.discordMessageFormat" class="form-select">
|
||||
<option value="normal">{{ $t("discordMessageFormatNormal") }}</option>
|
||||
<option value="minimalist">{{ $t("discordMessageFormatMinimalist") }}</option>
|
||||
<option value="custom">{{ $t("discordMessageFormatCustom") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div v-show="$parent.notification.discordMessageFormat === 'custom'">
|
||||
<div class="mb-3">
|
||||
<label for="discord-message-template" class="form-label">{{ $t("discordMessageTemplate") }}</label>
|
||||
<TemplatedTextarea
|
||||
id="discord-message-template"
|
||||
v-model="$parent.notification.discordMessageTemplate"
|
||||
:required="false"
|
||||
placeholder=""
|
||||
></TemplatedTextarea>
|
||||
<div class="form-text">{{ $t("discordUseMessageTemplateDescription") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="discord-message-type" class="form-label">{{ $t("Select message type") }}</label>
|
||||
<select id="discord-message-type" v-model="$parent.notification.discordChannelType" class="form-select">
|
||||
@@ -122,7 +144,12 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import TemplatedTextarea from "../TemplatedTextarea.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TemplatedTextarea,
|
||||
},
|
||||
mounted() {
|
||||
if (!this.$parent.notification.discordChannelType) {
|
||||
this.$parent.notification.discordChannelType = "channel";
|
||||
@@ -133,6 +160,13 @@ export default {
|
||||
if (this.$parent.notification.discordSuppressNotifications === undefined) {
|
||||
this.$parent.notification.discordSuppressNotifications = false;
|
||||
}
|
||||
// Message format: default "normal"; migrate from old checkbox
|
||||
if (typeof this.$parent.notification.discordMessageFormat === "undefined") {
|
||||
const hadCustom =
|
||||
this.$parent.notification.discordUseMessageTemplate === true ||
|
||||
!!this.$parent.notification.discordMessageTemplate?.trim();
|
||||
this.$parent.notification.discordMessageFormat = hadCustom ? "custom" : "normal";
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1323,6 +1323,13 @@
|
||||
"Disable URL in Notification": "Disable URL in Notification",
|
||||
"Suppress Notifications": "Suppress Notifications",
|
||||
"discordSuppressNotificationsHelptext": "When enabled, messages will be posted to the channel but won't trigger push or desktop notifications for recipients.",
|
||||
"discordMessageFormat": "Message Format",
|
||||
"discordMessageFormatNormal": "Normal (rich embeds)",
|
||||
"discordMessageFormatMinimalist": "Minimalist (short status)",
|
||||
"discordMessageFormatCustom": "Custom template",
|
||||
"discordUseMessageTemplate": "Use custom message template",
|
||||
"discordUseMessageTemplateDescription": "If enabled, the message will be sent using a custom template (LiquidJS). Leave blank to use the default Uptime Kuma format.",
|
||||
"discordMessageTemplate": "Message Template",
|
||||
"Ip Family": "IP Family",
|
||||
"ipFamilyDescriptionAutoSelect": "Uses the {happyEyeballs} for determining the IP family.",
|
||||
"Happy Eyeballs algorithm": "Happy Eyeballs algorithm",
|
||||
|
||||
Reference in New Issue
Block a user