diff --git a/db/knex_migrations/2025-05-11-0000-feat-notification-trigger.js b/db/knex_migrations/2025-05-11-0000-feat-notification-trigger.js
new file mode 100644
index 000000000..53296b54d
--- /dev/null
+++ b/db/knex_migrations/2025-05-11-0000-feat-notification-trigger.js
@@ -0,0 +1,25 @@
+exports.up = async function (knex) {
+ await knex.schema.alterTable("notification", function (table) {
+ table.text("trigger").notNullable().defaultTo("up,down,certificate");
+ });
+
+ await knex("notification").whereNull("trigger").update({
+ trigger: "up,down,certificate",
+ });
+
+ const notifications = await knex("notification").select("*");
+ for (let n of notifications) {
+ await knex("notification").where("id", n.id).update({
+ config: JSON.stringify({
+ ...JSON.parse(n.config),
+ trigger: "up,down,certificate",
+ }),
+ });
+ }
+};
+
+exports.down = function (knex) {
+ return knex.schema.alterTable("notification", function (table) {
+ table.dropColumn("trigger");
+ });
+};
diff --git a/server/model/monitor.js b/server/model/monitor.js
index 08d666b78..095b7997b 100644
--- a/server/model/monitor.js
+++ b/server/model/monitor.js
@@ -1293,6 +1293,7 @@ class Monitor extends BeanModel {
for (let notification of notificationList) {
try {
+ const triggers = notification.trigger.split(",");
const heartbeatJSON = bean.toJSON();
const monitorData = [{ id: monitor.id,
active: monitor.active,
@@ -1309,7 +1310,9 @@ class Monitor extends BeanModel {
heartbeatJSON["timezoneOffset"] = UptimeKumaServer.getInstance().getTimezoneOffset();
heartbeatJSON["localDateTime"] = dayjs.utc(heartbeatJSON["time"]).tz(heartbeatJSON["timezone"]).format(SQL_DATETIME_FORMAT);
- await Notification.send(JSON.parse(notification.config), msg, monitor.toJSON(preloadData, false), heartbeatJSON);
+ if ((bean.status === UP && triggers.includes("up")) || (bean.status === DOWN && triggers.includes("down"))) {
+ await Notification.send(JSON.parse(notification.config), msg, monitor.toJSON(preloadData, false), heartbeatJSON);
+ }
} catch (e) {
log.error("monitor", "Cannot send notification to " + notification.name);
log.error("monitor", e);
@@ -1401,6 +1404,11 @@ class Monitor extends BeanModel {
log.debug("monitor", "Send certificate notification");
for (let notification of notificationList) {
+ const triggers = notification.trigger.split(",");
+ if (!triggers.includes("certificate")) {
+ log.debug("monitor", "Notification does not trigger on certificate");
+ continue;
+ }
try {
log.debug("monitor", "Sending to " + notification.name);
await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] ${certType} certificate ${certCN} will expire in ${daysRemaining} days`);
diff --git a/server/notification.js b/server/notification.js
index fd8c23d67..c66d8564a 100644
--- a/server/notification.js
+++ b/server/notification.js
@@ -229,6 +229,7 @@ class Notification {
bean.user_id = userID;
bean.config = JSON.stringify(notification);
bean.is_default = notification.isDefault || false;
+ bean.trigger = notification.trigger;
await R.store(bean);
if (notification.applyExisting) {
diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue
index acfcde6a2..1d8cd2870 100644
--- a/src/components/NotificationDialog.vue
+++ b/src/components/NotificationDialog.vue
@@ -39,6 +39,56 @@
{{ $t("enableDefaultNotificationDescription") }}
+
+