diff --git a/package-lock.json b/package-lock.json index eefd9d5a..5b961b90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "1.11.4", + "version": "1.12.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "1.11.4", + "version": "1.12.1", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-svg-core": "~1.2.36", @@ -29,6 +29,7 @@ "dayjs": "~1.10.7", "express": "~4.17.1", "express-basic-auth": "~1.2.0", + "favico.js": "^0.3.10", "form-data": "~4.0.0", "http-graceful-shutdown": "~3.1.5", "iconv-lite": "^0.6.3", @@ -6140,6 +6141,11 @@ "reusify": "^1.0.4" } }, + "node_modules/favico.js": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/favico.js/-/favico.js-0.3.10.tgz", + "integrity": "sha1-gFhuJ6EX8kqNUcGKmb3HFNQzkwE=" + }, "node_modules/fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", @@ -18240,6 +18246,11 @@ "reusify": "^1.0.4" } }, + "favico.js": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/favico.js/-/favico.js-0.3.10.tgz", + "integrity": "sha1-gFhuJ6EX8kqNUcGKmb3HFNQzkwE=" + }, "fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", diff --git a/package.json b/package.json index 99c9720e..23f7acde 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "dayjs": "~1.10.7", "express": "~4.17.1", "express-basic-auth": "~1.2.0", + "favico.js": "^0.3.10", "form-data": "~4.0.0", "http-graceful-shutdown": "~3.1.5", "iconv-lite": "^0.6.3", diff --git a/src/mixins/socket.js b/src/mixins/socket.js index affac4f8..14a805fd 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -1,6 +1,7 @@ import { io } from "socket.io-client"; import { useToast } from "vue-toastification"; import jwt_decode from "jwt-decode"; +import Favico from "favico.js"; const toast = useToast(); let socket; @@ -11,6 +12,10 @@ const noSocketIOPages = [ "/" ]; +const favicon = new Favico({ + animation: "none" +}); + export default { data() { @@ -392,10 +397,50 @@ export default { return result; }, + + stats() { + let result = { + up: 0, + down: 0, + unknown: 0, + pause: 0, + }; + + for (let monitorID in this.$root.monitorList) { + let beat = this.$root.lastHeartbeatList[monitorID]; + let monitor = this.$root.monitorList[monitorID]; + + if (monitor && ! monitor.active) { + result.pause++; + } else if (beat) { + if (beat.status === 1) { + result.up++; + } else if (beat.status === 0) { + result.down++; + } else if (beat.status === 2) { + result.up++; + } else { + result.unknown++; + } + } else { + result.unknown++; + } + } + + return result; + }, }, watch: { + // Update Badge + "stats.down"(to, from) { + if (to !== from) { + favicon.badge(to); + console.log(to); + } + }, + // Reload the SPA if the server version is changed. "info.version"(to, from) { if (from && from !== to) { diff --git a/src/pages/DashboardHome.vue b/src/pages/DashboardHome.vue index 16d07983..6e8a5bbc 100644 --- a/src/pages/DashboardHome.vue +++ b/src/pages/DashboardHome.vue @@ -9,19 +9,19 @@

{{ $t("Up") }}

- {{ stats.up }} + {{ $root.stats.up }}

{{ $t("Down") }}

- {{ stats.down }} + {{ $root.stats.down }}

{{ $t("Unknown") }}

- {{ stats.unknown }} + {{ $root.stats.unknown }}

{{ $t("pauseDashboardHome") }}

- {{ stats.pause }} + {{ $root.stats.pause }}
@@ -89,37 +89,6 @@ export default { }; }, computed: { - stats() { - let result = { - up: 0, - down: 0, - unknown: 0, - pause: 0, - }; - - for (let monitorID in this.$root.monitorList) { - let beat = this.$root.lastHeartbeatList[monitorID]; - let monitor = this.$root.monitorList[monitorID]; - - if (monitor && ! monitor.active) { - result.pause++; - } else if (beat) { - if (beat.status === 1) { - result.up++; - } else if (beat.status === 0) { - result.down++; - } else if (beat.status === 2) { - result.up++; - } else { - result.unknown++; - } - } else { - result.unknown++; - } - } - - return result; - }, importantHeartBeatList() { let result = []; diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index 0dc49518..fab3ec89 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -220,12 +220,18 @@ import ImageCropUpload from "vue-image-crop-upload"; import { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_PARTIAL_DOWN, UP } from "../util.ts"; import { useToast } from "vue-toastification"; import dayjs from "dayjs"; +import Favico from "favico.js"; + const toast = useToast(); const leavePageMsg = "Do you really want to leave? you have unsaved changes!"; let feedInterval; +const favicon = new Favico({ + animation: "none" +}); + export default { components: { PublicGroupList, @@ -304,7 +310,7 @@ export default { }, tagsVisible() { - return this.config.statusPageTags + return this.config.statusPageTags; }, logoClass() { @@ -439,8 +445,25 @@ export default { // If editMode, it will use the data from websocket. if (! this.editMode) { axios.get("/api/status-page/heartbeat").then((res) => { - this.$root.heartbeatList = res.data.heartbeatList; - this.$root.uptimeList = res.data.uptimeList; + const { heartbeatList, uptimeList } = res.data; + + this.$root.heartbeatList = heartbeatList; + this.$root.uptimeList = uptimeList; + + const heartbeatIds = Object.keys(heartbeatList); + const downMonitors = heartbeatIds.reduce((downMonitorsAmount, currentId) => { + const monitorHeartbeats = heartbeatList[currentId]; + const lastHeartbeat = monitorHeartbeats.at(-1); + + if (lastHeartbeat) { + return lastHeartbeat.status === 0 ? downMonitorsAmount + 1 : downMonitorsAmount; + } else { + return downMonitorsAmount; + } + }, 0); + + favicon.badge(downMonitors); + this.loadedData = true; }); } @@ -501,9 +524,9 @@ export default { return { ...monitor, tags: newState ? this.$root.monitorList[monitor.id].tags : [] - } + }; }) - } + }; }); },