From 9442c3fa05c197e6f2d5af6632abae4b1ad68351 Mon Sep 17 00:00:00 2001 From: Nelson Chan Date: Tue, 24 Aug 2021 23:34:48 +0800 Subject: [PATCH 1/4] Fix: Fix chart bars to be full width --- src/components/PingChart.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue index 53a8379..584664b 100644 --- a/src/components/PingChart.vue +++ b/src/components/PingChart.vue @@ -57,9 +57,6 @@ export default { point: { radius: 0, }, - bar: { - barThickness: "flex", - } }, scales: { x: { @@ -77,9 +74,9 @@ export default { maxRotation: 0, autoSkipPadding: 30, }, - bounds: "ticks", grid: { color: this.$root.theme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)", + offset: false, }, }, y: { @@ -163,6 +160,9 @@ export default { borderColor: "#00000000", backgroundColor: "#DC354568", yAxisID: "y1", + barThickness: "flex", + barPercentage: 1, + categoryPercentage: 1, }, ], }; From 2d20634738365881dfd0409d2b39230be9b34473 Mon Sep 17 00:00:00 2001 From: Nelson Chan Date: Wed, 25 Aug 2021 00:54:52 +0800 Subject: [PATCH 2/4] Chore: Add comments, improve performance & styling --- src/components/PingChart.vue | 38 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue index 584664b..8f53ea7 100644 --- a/src/components/PingChart.vue +++ b/src/components/PingChart.vue @@ -24,6 +24,7 @@ export default { }, data() { return { + // Configurable filtering on top of the returned data chartPeriodHrs: 6, }; }, @@ -55,7 +56,9 @@ export default { elements: { point: { + // Hide points on chart unless mouse-over radius: 0, + hitRadius: 100, }, }, scales: { @@ -106,8 +109,11 @@ export default { mode: "nearest", intersect: false, padding: 10, + backgroundColor: this.$root.theme === "light" ? "rgba(212,232,222,1.0)" : "rgba(32,42,38,1.0)", + bodyColor: this.$root.theme === "light" ? "rgba(12,12,18,1.0)" : "rgba(220,220,220,1.0)", + titleColor: this.$root.theme === "light" ? "rgba(12,12,18,1.0)" : "rgba(220,220,220,1.0)", filter: function (tooltipItem) { - return tooltipItem.datasetIndex === 0; + return tooltipItem.datasetIndex === 0; // Hide tooltip on Bar Chart }, callbacks: { label: (context) => { @@ -122,32 +128,29 @@ export default { } }, chartData() { - let ping_data = []; - let down_data = []; + let pingData = []; // Ping Data for Line Chart, y-axis contains ping time + let downData = []; // Down Data for Bar Chart, y-axis is 1 if target is down, 0 if target is up if (this.monitorId in this.$root.heartbeatList) { - ping_data = this.$root.heartbeatList[this.monitorId] + this.$root.heartbeatList[this.monitorId] .filter( (beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter(dayjs().subtract(this.chartPeriodHrs, "hours"))) .map((beat) => { - return { - x: dayjs.utc(beat.time).tz(this.$root.timezone).format("YYYY-MM-DD HH:mm:ss"), + const x = this.$root.datetime(beat.time); + pingData.push({ + x, y: beat.ping, - }; - }); - down_data = this.$root.heartbeatList[this.monitorId] - .filter( - (beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter(dayjs().subtract(this.chartPeriodHrs, "hours"))) - .map((beat) => { - return { - x: dayjs.utc(beat.time).tz(this.$root.timezone).format("YYYY-MM-DD HH:mm:ss"), + }); + downData.push({ + x, y: beat.status === 0 ? 1 : 0, - }; + }) }); } return { datasets: [ { - data: ping_data, + // Line Chart + data: pingData, fill: "origin", tension: 0.2, borderColor: "#5CDD8B", @@ -155,8 +158,9 @@ export default { yAxisID: "y", }, { + // Bar Chart type: "bar", - data: down_data, + data: downData, borderColor: "#00000000", backgroundColor: "#DC354568", yAxisID: "y1", From 23851ef539bc716868ccc96af26f45ce927ad529 Mon Sep 17 00:00:00 2001 From: Rashad <-> Date: Tue, 24 Aug 2021 21:19:21 +0300 Subject: [PATCH 3/4] added mattermost notification support --- server/notification.js | 110 ++++++++++++++++++++++++++ src/components/NotificationDialog.vue | 34 ++++++++ 2 files changed, 144 insertions(+) diff --git a/server/notification.js b/server/notification.js index 446753e..cb77a61 100644 --- a/server/notification.js +++ b/server/notification.js @@ -279,6 +279,116 @@ class Notification { throwGeneralAxiosError(error) } + } else if (notification.type === "mattermost") { + try { + const mattermostUserName = notification.mattermostusername || "Uptime Kuma"; + // If heartbeatJSON is null, assume we're testing. + if (heartbeatJSON == null) { + let mattermostTestData = { + username: mattermostUserName, + text: msg, + } + await axios.post(notification.mattermostWebhookUrl, mattermostTestData) + return okMsg; + } + + const mattermostChannel = notification.mattermostchannel; + const mattermostIconEmoji = notification.mattermosticonemo; + const mattermostIconUrl = notification.mattermosticonurl; + + if (heartbeatJSON["status"] == 0) { + let mattermostdowndata = { + username: mattermostUserName, + text: "Uptime Kuma Alert", + channel: mattermostChannel, + icon_emoji: mattermostIconEmoji, + icon_url: mattermostIconUrl, + attachments: [ + { + fallback: + "Your " + + monitorJSON["name"] + + " service went down.", + color: "#FF0000", + title: + "❌ " + + monitorJSON["name"] + + " service went down. ❌", + title_link: monitorJSON["url"], + fields: [ + { + short: true, + title: "Service Name", + value: monitorJSON["name"], + }, + { + short: true, + title: "Time (UTC)", + value: heartbeatJSON["time"], + }, + { + short: false, + title: "Error", + value: heartbeatJSON["msg"], + }, + ], + }, + ], + }; + await axios.post( + notification.mattermostWebhookUrl, + mattermostdowndata + ); + return okMsg; + } else if (heartbeatJSON["status"] == 1) { + let mattermostupdata = { + username: mattermostUserName, + text: "Uptime Kuma Alert", + channel: mattermostChannel, + icon_emoji: mattermostIconEmoji, + icon_url: mattermostIconUrl, + attachments: [ + { + fallback: + "Your " + + monitorJSON["name"] + + " service went up!", + color: "#32CD32", + title: + "✅ " + + monitorJSON["name"] + + " service went up! ✅", + title_link: monitorJSON["url"], + fields: [ + { + short: true, + title: "Service Name", + value: monitorJSON["name"], + }, + { + short: true, + title: "Time (UTC)", + value: heartbeatJSON["time"], + }, + { + short: false, + title: "Ping", + value: heartbeatJSON["ping"] + "ms", + }, + ], + }, + ], + }; + await axios.post( + notification.mattermostWebhookUrl, + mattermostupdata + ); + return okMsg; + } + } catch (error) { + throwGeneralAxiosError(error); + } + } else if (notification.type === "pushover") { let pushoverlink = "https://api.pushover.net/1/messages.json" try { diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 43b56b2..d639e4f 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -27,6 +27,7 @@ + @@ -238,6 +239,39 @@ + +