mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-03-04 16:35:57 +00:00
Merge branch 'feature-slow-response-visual-improvements' into feature-slow-response-notification
This commit is contained in:
commit
2755276f22
15 changed files with 194 additions and 18 deletions
|
@ -0,0 +1,21 @@
|
||||||
|
exports.up = function (knex) {
|
||||||
|
// add various slow response parameters
|
||||||
|
return knex.schema
|
||||||
|
.alterTable("heartbeat", function (table) {
|
||||||
|
table.integer("ping_status").nullable().defaultTo(null);
|
||||||
|
table.integer("ping_threshold").nullable().defaultTo(null);
|
||||||
|
table.boolean("ping_important").notNullable().defaultTo(0);
|
||||||
|
table.string("ping_msg").nullable().defaultTo(null);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (knex) {
|
||||||
|
// remove various slow response parameters
|
||||||
|
return knex.schema
|
||||||
|
.alterTable("heartbeat", function (table) {
|
||||||
|
table.dropColumn("ping_status");
|
||||||
|
table.dropColumn("ping_threshold");
|
||||||
|
table.dropColumn("ping_important");
|
||||||
|
table.dropColumn("ping_msg");
|
||||||
|
});
|
||||||
|
};
|
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -97,6 +97,7 @@
|
||||||
"bootstrap": "5.1.3",
|
"bootstrap": "5.1.3",
|
||||||
"chart.js": "~4.2.1",
|
"chart.js": "~4.2.1",
|
||||||
"chartjs-adapter-dayjs-4": "~1.0.4",
|
"chartjs-adapter-dayjs-4": "~1.0.4",
|
||||||
|
"chartjs-plugin-annotation": "~3.0.1",
|
||||||
"concurrently": "^7.1.0",
|
"concurrently": "^7.1.0",
|
||||||
"core-js": "~3.26.1",
|
"core-js": "~3.26.1",
|
||||||
"cronstrue": "~2.24.0",
|
"cronstrue": "~2.24.0",
|
||||||
|
@ -6062,6 +6063,15 @@
|
||||||
"dayjs": "^1.9.7"
|
"dayjs": "^1.9.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chartjs-plugin-annotation": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-plugin-annotation/-/chartjs-plugin-annotation-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-hlIrXXKqSDgb+ZjVYHefmlZUXK8KbkCPiynSVrTb/HjTMkT62cOInaT1NTQCKtxKKOm9oHp958DY3RTAFKtkHg==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"chart.js": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/check-more-types": {
|
"node_modules/check-more-types": {
|
||||||
"version": "2.24.0",
|
"version": "2.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
|
"resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
|
||||||
|
|
|
@ -163,6 +163,7 @@
|
||||||
"bootstrap": "5.1.3",
|
"bootstrap": "5.1.3",
|
||||||
"chart.js": "~4.2.1",
|
"chart.js": "~4.2.1",
|
||||||
"chartjs-adapter-dayjs-4": "~1.0.4",
|
"chartjs-adapter-dayjs-4": "~1.0.4",
|
||||||
|
"chartjs-plugin-annotation": "~3.0.1",
|
||||||
"concurrently": "^7.1.0",
|
"concurrently": "^7.1.0",
|
||||||
"core-js": "~3.26.1",
|
"core-js": "~3.26.1",
|
||||||
"cronstrue": "~2.24.0",
|
"cronstrue": "~2.24.0",
|
||||||
|
|
|
@ -54,7 +54,7 @@ async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite =
|
||||||
monitorID,
|
monitorID,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let result = list.reverse();
|
let result = R.convertToBeans("heartbeat", list.reverse());
|
||||||
|
|
||||||
if (toUser) {
|
if (toUser) {
|
||||||
io.to(socket.userID).emit("heartbeatList", monitorID, result, overwrite);
|
io.to(socket.userID).emit("heartbeatList", monitorID, result, overwrite);
|
||||||
|
|
|
@ -6,6 +6,9 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
* 1 = UP
|
* 1 = UP
|
||||||
* 2 = PENDING
|
* 2 = PENDING
|
||||||
* 3 = MAINTENANCE
|
* 3 = MAINTENANCE
|
||||||
|
* pingStatus:
|
||||||
|
* 4 = SLOW
|
||||||
|
* 5 = NOMINAL
|
||||||
*/
|
*/
|
||||||
class Heartbeat extends BeanModel {
|
class Heartbeat extends BeanModel {
|
||||||
|
|
||||||
|
@ -37,6 +40,10 @@ class Heartbeat extends BeanModel {
|
||||||
important: this._important,
|
important: this._important,
|
||||||
duration: this._duration,
|
duration: this._duration,
|
||||||
retries: this._retries,
|
retries: this._retries,
|
||||||
|
pingThreshold: this._pingThreshold,
|
||||||
|
pingStatus: this._pingStatus,
|
||||||
|
pingImportant: this._pingImportant,
|
||||||
|
pingMsg: this._pingMsg,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const { Prometheus } = require("../prometheus");
|
const { Prometheus } = require("../prometheus");
|
||||||
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND,
|
const { log, UP, DOWN, PENDING, MAINTENANCE, NOMINAL, SLOW, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, SQL_DATETIME_FORMAT
|
||||||
SQL_DATETIME_FORMAT
|
|
||||||
} = require("../../src/util");
|
} = require("../../src/util");
|
||||||
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery,
|
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery,
|
||||||
redisPingAsync, mongodbPing, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
|
redisPingAsync, mongodbPing, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
|
||||||
|
@ -34,6 +33,9 @@ const rootCertificates = rootCertificatesFingerprints();
|
||||||
* 1 = UP
|
* 1 = UP
|
||||||
* 2 = PENDING
|
* 2 = PENDING
|
||||||
* 3 = MAINTENANCE
|
* 3 = MAINTENANCE
|
||||||
|
* pingStatus:
|
||||||
|
* 4 = SLOW
|
||||||
|
* 5 = NOMINAL
|
||||||
*/
|
*/
|
||||||
class Monitor extends BeanModel {
|
class Monitor extends BeanModel {
|
||||||
|
|
||||||
|
@ -1565,7 +1567,7 @@ class Monitor extends BeanModel {
|
||||||
// Create stats to append to messages/logs
|
// Create stats to append to messages/logs
|
||||||
const methodDescription = [ "average", "max" ].includes(method) ? `${method} of last ${windowDuration}s` : method;
|
const methodDescription = [ "average", "max" ].includes(method) ? `${method} of last ${windowDuration}s` : method;
|
||||||
let msgStats = `Response: ${actualResponseTime}ms (${methodDescription}) | Threshold: ${threshold}ms (${thresholdDescription})`;
|
let msgStats = `Response: ${actualResponseTime}ms (${methodDescription}) | Threshold: ${threshold}ms (${thresholdDescription})`;
|
||||||
// Add window duration for methods that make sense
|
let pingMsg = `${actualResponseTime}ms resp. (${methodDescription})`;
|
||||||
|
|
||||||
// Verify valid response time was calculated
|
// Verify valid response time was calculated
|
||||||
if (actualResponseTime === 0 || !Number.isInteger(actualResponseTime)) {
|
if (actualResponseTime === 0 || !Number.isInteger(actualResponseTime)) {
|
||||||
|
@ -1579,8 +1581,11 @@ class Monitor extends BeanModel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bean.pingThreshold = threshold;
|
||||||
|
|
||||||
// Responding normally
|
// Responding normally
|
||||||
if (actualResponseTime < threshold) {
|
if (actualResponseTime < threshold) {
|
||||||
|
bean.pingStatus = NOMINAL;
|
||||||
if (bean.slowResponseCount === 0) {
|
if (bean.slowResponseCount === 0) {
|
||||||
log.debug("monitor", `[${this.name}] Responding normally. No need to send slow response notification | ${msgStats}`);
|
log.debug("monitor", `[${this.name}] Responding normally. No need to send slow response notification | ${msgStats}`);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1588,6 +1593,11 @@ class Monitor extends BeanModel {
|
||||||
log.debug("monitor", `[${this.name}] Returned to normal response time | ${msgStats}`);
|
log.debug("monitor", `[${this.name}] Returned to normal response time | ${msgStats}`);
|
||||||
let msg = `[${this.name}] Returned to Normal Response Time \n${msgStats}`;
|
let msg = `[${this.name}] Returned to Normal Response Time \n${msgStats}`;
|
||||||
Monitor.sendSlowResponseNotification(monitor, bean, msg);
|
Monitor.sendSlowResponseNotification(monitor, bean, msg);
|
||||||
|
|
||||||
|
// Mark important (SLOW -> NOMINAL)
|
||||||
|
pingMsg += ` < ${threshold}ms`;
|
||||||
|
bean.pingImportant = true;
|
||||||
|
bean.pingMsg = pingMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset slow response count
|
// Reset slow response count
|
||||||
|
@ -1595,6 +1605,7 @@ class Monitor extends BeanModel {
|
||||||
|
|
||||||
// Responding slowly
|
// Responding slowly
|
||||||
} else {
|
} else {
|
||||||
|
bean.pingStatus = SLOW;
|
||||||
++bean.slowResponseCount;
|
++bean.slowResponseCount;
|
||||||
|
|
||||||
// Always send first notification
|
// Always send first notification
|
||||||
|
@ -1602,6 +1613,12 @@ class Monitor extends BeanModel {
|
||||||
log.debug("monitor", `[${this.name}] Responded slowly, sending notification | ${msgStats}`);
|
log.debug("monitor", `[${this.name}] Responded slowly, sending notification | ${msgStats}`);
|
||||||
let msg = `[${this.name}] Responded Slowly \n${msgStats}`;
|
let msg = `[${this.name}] Responded Slowly \n${msgStats}`;
|
||||||
Monitor.sendSlowResponseNotification(monitor, bean, msg);
|
Monitor.sendSlowResponseNotification(monitor, bean, msg);
|
||||||
|
|
||||||
|
// Mark important (NOMINAL -> SLOW)
|
||||||
|
pingMsg += ` > ${threshold}ms`;
|
||||||
|
bean.pingImportant = true;
|
||||||
|
bean.pingMsg = pingMsg;
|
||||||
|
|
||||||
// Send notification every x times
|
// Send notification every x times
|
||||||
} else if (this.slowResponseNotificationResendInterval > 0) {
|
} else if (this.slowResponseNotificationResendInterval > 0) {
|
||||||
if (((bean.slowResponseCount) % this.slowResponseNotificationResendInterval) === 0) {
|
if (((bean.slowResponseCount) % this.slowResponseNotificationResendInterval) === 0) {
|
||||||
|
|
|
@ -1199,9 +1199,9 @@ let needSetup = false;
|
||||||
|
|
||||||
let count;
|
let count;
|
||||||
if (monitorID == null) {
|
if (monitorID == null) {
|
||||||
count = await R.count("heartbeat", "important = 1");
|
count = await R.count("heartbeat", "important = 1 OR ping_important = 1");
|
||||||
} else {
|
} else {
|
||||||
count = await R.count("heartbeat", "monitor_id = ? AND important = 1", [
|
count = await R.count("heartbeat", "monitor_id = ? AND (important = 1 OR ping_important = 1)", [
|
||||||
monitorID,
|
monitorID,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -1225,7 +1225,7 @@ let needSetup = false;
|
||||||
let list;
|
let list;
|
||||||
if (monitorID == null) {
|
if (monitorID == null) {
|
||||||
list = await R.find("heartbeat", `
|
list = await R.find("heartbeat", `
|
||||||
important = 1
|
important = 1 OR ping_important = 1
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
OFFSET ?
|
OFFSET ?
|
||||||
|
@ -1236,7 +1236,7 @@ let needSetup = false;
|
||||||
} else {
|
} else {
|
||||||
list = await R.find("heartbeat", `
|
list = await R.find("heartbeat", `
|
||||||
monitor_id = ?
|
monitor_id = ?
|
||||||
AND important = 1
|
AND (important = 1 OR ping_important = 1)
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
OFFSET ?
|
OFFSET ?
|
||||||
|
@ -1449,7 +1449,9 @@ let needSetup = false;
|
||||||
|
|
||||||
log.info("manage", `Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`);
|
log.info("manage", `Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`);
|
||||||
|
|
||||||
await R.exec("UPDATE heartbeat SET msg = ?, important = ? WHERE monitor_id = ? ", [
|
await R.exec("UPDATE heartbeat SET msg = ?, important = ?, ping_msg = ?, ping_important = ? WHERE monitor_id = ? ", [
|
||||||
|
"",
|
||||||
|
"0",
|
||||||
"",
|
"",
|
||||||
"0",
|
"0",
|
||||||
monitorID,
|
monitorID,
|
||||||
|
|
|
@ -19,11 +19,12 @@
|
||||||
<script lang="js">
|
<script lang="js">
|
||||||
import { BarController, BarElement, Chart, Filler, LinearScale, LineController, LineElement, PointElement, TimeScale, Tooltip } from "chart.js";
|
import { BarController, BarElement, Chart, Filler, LinearScale, LineController, LineElement, PointElement, TimeScale, Tooltip } from "chart.js";
|
||||||
import "chartjs-adapter-dayjs-4";
|
import "chartjs-adapter-dayjs-4";
|
||||||
|
import annotationPlugin from "chartjs-plugin-annotation";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { Line } from "vue-chartjs";
|
import { Line } from "vue-chartjs";
|
||||||
import { DOWN, PENDING, MAINTENANCE, log } from "../util.ts";
|
import { DOWN, PENDING, MAINTENANCE, log } from "../util.ts";
|
||||||
|
|
||||||
Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler);
|
Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler, annotationPlugin);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { Line },
|
components: { Line },
|
||||||
|
@ -56,6 +57,19 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
threshold() {
|
||||||
|
let heartbeatList = this.heartbeatList ||
|
||||||
|
(this.monitorId in this.$root.heartbeatList && this.$root.heartbeatList[this.monitorId]) ||
|
||||||
|
[];
|
||||||
|
|
||||||
|
let lastBeat = heartbeatList.at(-1);
|
||||||
|
|
||||||
|
if (lastBeat) {
|
||||||
|
return lastBeat.pingThreshold;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
chartOptions() {
|
chartOptions() {
|
||||||
return {
|
return {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
|
@ -153,6 +167,22 @@ export default {
|
||||||
legend: {
|
legend: {
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
|
annotation: {
|
||||||
|
annotations: {
|
||||||
|
line1: {
|
||||||
|
type: "line",
|
||||||
|
mode: "horizontal",
|
||||||
|
scaleID: "y",
|
||||||
|
value: this.threshold,
|
||||||
|
endValue: this.threshold,
|
||||||
|
borderColor: "rgba(248,163,6,1.0)",
|
||||||
|
borderWith: 2,
|
||||||
|
borderDash: [ 1, 3 ],
|
||||||
|
adjustScaleRange: false,
|
||||||
|
display: this.threshold !== undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,6 +30,14 @@ export default {
|
||||||
return "maintenance";
|
return "maintenance";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.status === 4) {
|
||||||
|
return "warning";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.status === 5) {
|
||||||
|
return "primary";
|
||||||
|
}
|
||||||
|
|
||||||
return "secondary";
|
return "secondary";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -50,6 +58,14 @@ export default {
|
||||||
return this.$t("statusMaintenance");
|
return this.$t("statusMaintenance");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.status === 4) {
|
||||||
|
return this.$t("Slow");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.status === 5) {
|
||||||
|
return this.$t("Nominal");
|
||||||
|
}
|
||||||
|
|
||||||
return this.$t("Unknown");
|
return this.$t("Unknown");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
"Pending": "Pending",
|
"Pending": "Pending",
|
||||||
"statusMaintenance": "Maintenance",
|
"statusMaintenance": "Maintenance",
|
||||||
"Maintenance": "Maintenance",
|
"Maintenance": "Maintenance",
|
||||||
|
"Slow": "Slow",
|
||||||
|
"Nominal": "Nominal",
|
||||||
"Unknown": "Unknown",
|
"Unknown": "Unknown",
|
||||||
"Cannot connect to the socket server": "Cannot connect to the socket server",
|
"Cannot connect to the socket server": "Cannot connect to the socket server",
|
||||||
"Reconnecting...": "Reconnecting...",
|
"Reconnecting...": "Reconnecting...",
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Favico from "favico.js";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import mitt from "mitt";
|
import mitt from "mitt";
|
||||||
|
|
||||||
import { DOWN, MAINTENANCE, PENDING, UP } from "../util.ts";
|
import { DOWN, MAINTENANCE, PENDING, UP, SLOW, NOMINAL } from "../util.ts";
|
||||||
import { getDevContainerServerHostname, isDevContainer, getToastSuccessTimeout, getToastErrorTimeout } from "../util-frontend.js";
|
import { getDevContainerServerHostname, isDevContainer, getToastSuccessTimeout, getToastErrorTimeout } from "../util-frontend.js";
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
@ -190,6 +190,10 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to important list if it is important
|
// Add to important list if it is important
|
||||||
|
if (data.important || data.pingImportant) {
|
||||||
|
this.emitter.emit("newImportantHeartbeat", data);
|
||||||
|
}
|
||||||
|
|
||||||
// Also toast
|
// Also toast
|
||||||
if (data.important) {
|
if (data.important) {
|
||||||
|
|
||||||
|
@ -206,8 +210,23 @@ export default {
|
||||||
toast(`[${this.monitorList[data.monitorID].name}] ${data.msg}`);
|
toast(`[${this.monitorList[data.monitorID].name}] ${data.msg}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.emitter.emit("newImportantHeartbeat", data);
|
if (data.pingImportant) {
|
||||||
|
|
||||||
|
if (this.monitorList[data.monitorID] !== undefined) {
|
||||||
|
if (data.pingStatus === SLOW) {
|
||||||
|
toast.warning(`[${this.monitorList[data.monitorID].name}] [SLOW] ${data.pingMsg}`, {
|
||||||
|
timeout: getToastErrorTimeout(),
|
||||||
|
});
|
||||||
|
} else if (data.pingStatus === NOMINAL) {
|
||||||
|
toast.success(`[${this.monitorList[data.monitorID].name}] [NOMINAL] ${data.pingMsg}`, {
|
||||||
|
timeout: getToastSuccessTimeout(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast(`[${this.monitorList[data.monitorID].name}] ${data.pingMsg}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -745,11 +764,30 @@ export default {
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pingStatusList() {
|
||||||
|
let result = {};
|
||||||
|
|
||||||
|
for (let monitorID in this.lastHeartbeatList) {
|
||||||
|
let lastHeartBeat = this.lastHeartbeatList[monitorID];
|
||||||
|
|
||||||
|
if (lastHeartBeat?.status === UP) {
|
||||||
|
if (lastHeartBeat.pingStatus === SLOW) {
|
||||||
|
result[monitorID] = {
|
||||||
|
text: this.$t("Slow"),
|
||||||
|
color: "warning",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
stats() {
|
stats() {
|
||||||
let result = {
|
let result = {
|
||||||
active: 0,
|
active: 0,
|
||||||
up: 0,
|
up: 0,
|
||||||
down: 0,
|
down: 0,
|
||||||
|
slow: 0,
|
||||||
maintenance: 0,
|
maintenance: 0,
|
||||||
pending: 0,
|
pending: 0,
|
||||||
unknown: 0,
|
unknown: 0,
|
||||||
|
@ -775,6 +813,10 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
result.unknown++;
|
result.unknown++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (beat.pingStatus === SLOW) {
|
||||||
|
result.slow++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result.unknown++;
|
result.unknown++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
<h3>{{ $t("Down") }}</h3>
|
<h3>{{ $t("Down") }}</h3>
|
||||||
<span class="num text-danger">{{ $root.stats.down }}</span>
|
<span class="num text-danger">{{ $root.stats.down }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h3>{{ $t("Slow") }}</h3>
|
||||||
|
<span class="num text-warning">{{ $root.stats.slow }}</span>
|
||||||
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>{{ $t("Maintenance") }}</h3>
|
<h3>{{ $t("Maintenance") }}</h3>
|
||||||
<span class="num text-maintenance">{{ $root.stats.maintenance }}</span>
|
<span class="num text-maintenance">{{ $root.stats.maintenance }}</span>
|
||||||
|
@ -43,11 +47,16 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(beat, index) in displayedRecords" :key="index" :class="{ 'shadow-box': $root.windowWidth <= 550}">
|
<tr v-for="(beat, index) in displayedRecords" :key="index" :class="{ 'shadow-box': $root.windowWidth <= 550}">
|
||||||
<td><router-link :to="`/dashboard/${beat.monitorID}`">{{ $root.monitorList[beat.monitorID]?.name }}</router-link></td>
|
<td><router-link :to="`/dashboard/${beat.monitorID}`">{{ $root.monitorList[beat.monitorID]?.name }}</router-link></td>
|
||||||
<td><Status :status="beat.status" /></td>
|
<td>
|
||||||
|
<div v-if="beat.important"><Status :status="beat.status" /></div>
|
||||||
|
<div v-if="beat.pingImportant"><Status :status="beat.pingStatus" /></div>
|
||||||
|
</td>
|
||||||
<td :class="{ 'border-0':! beat.msg}"><Datetime :value="beat.time" /></td>
|
<td :class="{ 'border-0':! beat.msg}"><Datetime :value="beat.time" /></td>
|
||||||
<td class="border-0">{{ beat.msg }}</td>
|
<td class="border-0">
|
||||||
|
<div v-if="beat.important">{{ beat.msg }}</div>
|
||||||
|
<div v-if="beat.pingImportant">{{ beat.pingMsg }}</div>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr v-if="importantHeartBeatListLength === 0">
|
<tr v-if="importantHeartBeatListLength === 0">
|
||||||
<td colspan="4">
|
<td colspan="4">
|
||||||
{{ $t("No important events") }}
|
{{ $t("No important events") }}
|
||||||
|
|
|
@ -71,7 +71,8 @@
|
||||||
<span class="word">{{ $t("checkEverySecond", [ monitor.interval ]) }}</span>
|
<span class="word">{{ $t("checkEverySecond", [ monitor.interval ]) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 text-center">
|
<div class="col-md-4 text-center">
|
||||||
<span class="badge rounded-pill" :class=" 'bg-' + status.color " style="font-size: 30px;">{{ status.text }}</span>
|
<span class="badge rounded-pill m-1" :class=" 'bg-' + status.color " style="font-size: 30px;">{{ status.text }}</span>
|
||||||
|
<span v-if="pingStatus" class="badge rounded-pill m-1" :class=" 'bg-' + pingStatus.color " style="font-size: 30px;">{{ pingStatus.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -219,9 +220,15 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(beat, index) in displayedRecords" :key="index" style="padding: 10px;">
|
<tr v-for="(beat, index) in displayedRecords" :key="index" style="padding: 10px;">
|
||||||
<td><Status :status="beat.status" /></td>
|
<td>
|
||||||
|
<div v-if="beat.important"><Status :status="beat.status" /></div>
|
||||||
|
<div v-if="beat.pingImportant"><Status :status="beat.pingStatus" /></div>
|
||||||
|
</td>
|
||||||
<td :class="{ 'border-0':! beat.msg}"><Datetime :value="beat.time" /></td>
|
<td :class="{ 'border-0':! beat.msg}"><Datetime :value="beat.time" /></td>
|
||||||
<td class="border-0">{{ beat.msg }}</td>
|
<td class="border-0">
|
||||||
|
<div v-if="beat.important">{{ beat.msg }}</div>
|
||||||
|
<div v-if="beat.pingImportant">{{ beat.pingMsg }}</div>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr v-if="importantHeartBeatListLength === 0">
|
<tr v-if="importantHeartBeatListLength === 0">
|
||||||
|
@ -366,6 +373,14 @@ export default {
|
||||||
return { };
|
return { };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pingStatus() {
|
||||||
|
if (this.$root.pingStatusList[this.monitor.id]) {
|
||||||
|
return this.$root.pingStatusList[this.monitor.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return { };
|
||||||
|
},
|
||||||
|
|
||||||
tlsInfo() {
|
tlsInfo() {
|
||||||
// Add: this.$root.tlsInfoList[this.monitor.id].certInfo
|
// Add: this.$root.tlsInfoList[this.monitor.id].certInfo
|
||||||
// Fix: TypeError: Cannot read properties of undefined (reading 'validTo')
|
// Fix: TypeError: Cannot read properties of undefined (reading 'validTo')
|
||||||
|
|
|
@ -20,6 +20,8 @@ exports.DOWN = 0;
|
||||||
exports.UP = 1;
|
exports.UP = 1;
|
||||||
exports.PENDING = 2;
|
exports.PENDING = 2;
|
||||||
exports.MAINTENANCE = 3;
|
exports.MAINTENANCE = 3;
|
||||||
|
exports.SLOW = 4;
|
||||||
|
exports.NOMINAL = 5;
|
||||||
exports.STATUS_PAGE_ALL_DOWN = 0;
|
exports.STATUS_PAGE_ALL_DOWN = 0;
|
||||||
exports.STATUS_PAGE_ALL_UP = 1;
|
exports.STATUS_PAGE_ALL_UP = 1;
|
||||||
exports.STATUS_PAGE_PARTIAL_DOWN = 2;
|
exports.STATUS_PAGE_PARTIAL_DOWN = 2;
|
||||||
|
|
|
@ -24,6 +24,8 @@ export const DOWN = 0;
|
||||||
export const UP = 1;
|
export const UP = 1;
|
||||||
export const PENDING = 2;
|
export const PENDING = 2;
|
||||||
export const MAINTENANCE = 3;
|
export const MAINTENANCE = 3;
|
||||||
|
export const SLOW = 4;
|
||||||
|
export const NOMINAL = 5;
|
||||||
|
|
||||||
export const STATUS_PAGE_ALL_DOWN = 0;
|
export const STATUS_PAGE_ALL_DOWN = 0;
|
||||||
export const STATUS_PAGE_ALL_UP = 1;
|
export const STATUS_PAGE_ALL_UP = 1;
|
||||||
|
|
Loading…
Add table
Reference in a new issue