mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-14 16:42:35 +02:00
Added the ability to choose which monitors the current monitor depends on.
This commit is contained in:
parent
a9df7b4a14
commit
64c8a90e8a
16 changed files with 269 additions and 20 deletions
13
db/patch-dependent-monitors-table.sql
Normal file
13
db/patch-dependent-monitors-table.sql
Normal file
|
@ -0,0 +1,13 @@
|
|||
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
CREATE TABLE dependent_monitors
|
||||
(
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
monitor_id INTEGER NOT NULL,
|
||||
depends_on INTEGER NOT NULL,
|
||||
CONSTRAINT FK_monitor_depends_on FOREIGN KEY (depends_on) REFERENCES monitor (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT FK_monitor_id FOREIGN KEY (monitor_id) REFERENCES monitor (id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
COMMIT;
|
|
@ -53,6 +53,7 @@ class Database {
|
|||
"patch-2fa-invalidate-used-token.sql": true,
|
||||
"patch-notification_sent_history.sql": true,
|
||||
"patch-monitor-basic-auth.sql": true,
|
||||
"patch-dependent-monitors-table.sql": true,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
|
|||
* 0 = DOWN
|
||||
* 1 = UP
|
||||
* 2 = PENDING
|
||||
* 4 = DEGRADED
|
||||
*/
|
||||
class Heartbeat extends BeanModel {
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ dayjs.extend(utc);
|
|||
dayjs.extend(timezone);
|
||||
const axios = require("axios");
|
||||
const { Prometheus } = require("../prometheus");
|
||||
const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
|
||||
const { debug, UP, DOWN, PENDING, DEGRADED, flipStatus, TimeLogger } = require("../../src/util");
|
||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog } = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||
|
@ -20,6 +20,7 @@ const apicache = require("../modules/apicache");
|
|||
* 0 = DOWN
|
||||
* 1 = UP
|
||||
* 2 = PENDING
|
||||
* 4 = DEGRADED
|
||||
*/
|
||||
class Monitor extends BeanModel {
|
||||
|
||||
|
@ -362,6 +363,11 @@ class Monitor extends BeanModel {
|
|||
|
||||
retries = 0;
|
||||
|
||||
if (bean.status === UP && await Monitor.isDegraded(this.id)) {
|
||||
bean.msg = "Monitor is degraded, because at least one dependent monitor is DOWN";
|
||||
bean.status = DEGRADED;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
bean.msg = error.message;
|
||||
|
@ -387,8 +393,13 @@ class Monitor extends BeanModel {
|
|||
if (isImportant) {
|
||||
bean.important = true;
|
||||
|
||||
debug(`[${this.name}] sendNotification`);
|
||||
await Monitor.sendNotification(isFirstBeat, this, bean);
|
||||
if (Monitor.isImportantForNotification(isFirstBeat, previousBeat?.status, bean.status)) {
|
||||
debug(`[${this.name}] sendNotification`);
|
||||
await Monitor.sendNotification(isFirstBeat, this, bean);
|
||||
}
|
||||
else {
|
||||
debug(`[${this.name}] will not sendNotification because it is not required`);
|
||||
}
|
||||
|
||||
// Clear Status Page Cache
|
||||
debug(`[${this.name}] apicache clear`);
|
||||
|
@ -405,6 +416,8 @@ class Monitor extends BeanModel {
|
|||
beatInterval = this.retryInterval;
|
||||
}
|
||||
console.warn(`Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`);
|
||||
} else if (bean.status === DEGRADED) {
|
||||
console.warn(`Monitor #${this.id} '${this.name}': Degraded: ${bean.msg} | Type: ${this.type}`);
|
||||
} else {
|
||||
console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`);
|
||||
}
|
||||
|
@ -659,11 +672,42 @@ class Monitor extends BeanModel {
|
|||
// DOWN -> PENDING = this case not exists
|
||||
// DOWN -> DOWN = not important
|
||||
// * DOWN -> UP = important
|
||||
let isImportant = isFirstBeat ||
|
||||
// * DEGRADED -> DOWN = important
|
||||
// * DEGRADED -> UP = important
|
||||
// * DOWN -> DEGRADED = important
|
||||
// * UP -> DEGRADED = important
|
||||
// DEGRADED -> PENDING = not important
|
||||
return isFirstBeat ||
|
||||
(previousBeatStatus === DEGRADED && currentBeatStatus === DOWN) ||
|
||||
(previousBeatStatus === DEGRADED && currentBeatStatus === UP) ||
|
||||
(previousBeatStatus === DOWN && currentBeatStatus === DEGRADED) ||
|
||||
(previousBeatStatus === UP && currentBeatStatus === DEGRADED) ||
|
||||
(previousBeatStatus === UP && currentBeatStatus === DOWN) ||
|
||||
(previousBeatStatus === DOWN && currentBeatStatus === UP) ||
|
||||
(previousBeatStatus === PENDING && currentBeatStatus === DOWN);
|
||||
}
|
||||
|
||||
static isImportantForNotification(isFirstBeat, previousBeatStatus, currentBeatStatus) {
|
||||
// * ? -> ANY STATUS = important [isFirstBeat]
|
||||
// UP -> PENDING = not important
|
||||
// * UP -> DOWN = important
|
||||
// UP -> UP = not important
|
||||
// PENDING -> PENDING = not important
|
||||
// * PENDING -> DOWN = important
|
||||
// PENDING -> UP = not important
|
||||
// DOWN -> PENDING = this case not exists
|
||||
// DOWN -> DOWN = not important
|
||||
// * DOWN -> UP = important
|
||||
// * DEGRADED -> DOWN = important
|
||||
// DEGRADED -> UP = not important
|
||||
// DOWN -> DEGRADED = not important
|
||||
// UP -> DEGRADED = not important
|
||||
// DEGRADED -> PENDING = not important
|
||||
return isFirstBeat ||
|
||||
(previousBeatStatus === DEGRADED && currentBeatStatus === DOWN) ||
|
||||
(previousBeatStatus === UP && currentBeatStatus === DOWN) ||
|
||||
(previousBeatStatus === DOWN && currentBeatStatus === UP) ||
|
||||
(previousBeatStatus === PENDING && currentBeatStatus === DOWN);
|
||||
return isImportant;
|
||||
}
|
||||
|
||||
static async sendNotification(isFirstBeat, monitor, bean) {
|
||||
|
@ -763,6 +807,17 @@ class Monitor extends BeanModel {
|
|||
monitorID
|
||||
]);
|
||||
}
|
||||
|
||||
static async isDegraded(monitorID) {
|
||||
const monitors = await R.getAll(`
|
||||
SELECT hb.id FROM heartbeat hb JOIN dependent_monitors dm on hb.monitor_id = dm.depends_on JOIN (SELECT MAX(id) AS id FROM heartbeat GROUP BY monitor_id) USING (id)
|
||||
WHERE dm.monitor_id = ? AND hb.status = 0
|
||||
`, [
|
||||
monitorID
|
||||
]);
|
||||
|
||||
return monitors.length !== 0;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Monitor;
|
||||
|
|
|
@ -5,7 +5,7 @@ const server = require("../server");
|
|||
const apicache = require("../modules/apicache");
|
||||
const Monitor = require("../model/monitor");
|
||||
const dayjs = require("dayjs");
|
||||
const { UP, flipStatus, debug } = require("../../src/util");
|
||||
const { UP, flipStatus, debug, DEGRADED } = require("../../src/util");
|
||||
let router = express.Router();
|
||||
|
||||
let cache = apicache.middleware;
|
||||
|
@ -51,6 +51,11 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
|||
duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second");
|
||||
}
|
||||
|
||||
if (status === UP && await Monitor.isDegraded(monitor.id)) {
|
||||
msg = "Monitor is degraded, because at least one dependent monitor is DOWN";
|
||||
status = DEGRADED;
|
||||
}
|
||||
|
||||
debug("PreviousStatus: " + previousStatus);
|
||||
debug("Current Status: " + status);
|
||||
|
||||
|
@ -70,7 +75,7 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
|||
ok: true,
|
||||
});
|
||||
|
||||
if (bean.important) {
|
||||
if (Monitor.isImportantForNotification(isFirstBeat, previousStatus, status)) {
|
||||
await Monitor.sendNotification(isFirstBeat, monitor, bean);
|
||||
}
|
||||
|
||||
|
|
|
@ -625,6 +625,38 @@ exports.entryPage = "dashboard";
|
|||
}
|
||||
});
|
||||
|
||||
// Add a new dependent_monitors
|
||||
socket.on("addDependentMonitors", async (monitorID, monitors, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
await R.exec("DELETE FROM dependent_monitors WHERE monitor_id = ?", [
|
||||
monitorID
|
||||
]);
|
||||
|
||||
for await (const monitor of monitors) {
|
||||
let bean = R.dispense("dependent_monitors");
|
||||
|
||||
bean.import({
|
||||
monitor_id: monitorID,
|
||||
depends_on: monitor.id
|
||||
});
|
||||
await R.store(bean);
|
||||
}
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Added Successfully.",
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("getMonitorList", async (callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
@ -665,6 +697,29 @@ exports.entryPage = "dashboard";
|
|||
}
|
||||
});
|
||||
|
||||
socket.on("getDependentMonitors", async (monitorID, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
console.log(`Get dependent Monitors for Monitor: ${monitorID} User ID: ${socket.userID}`);
|
||||
|
||||
let monitors = await R.getAll("SELECT monitor.id, monitor.name FROM dependent_monitors dm JOIN monitor ON dm.depends_on = monitor.id WHERE dm.monitor_id = ? ", [
|
||||
monitorID,
|
||||
]);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
monitors,
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("getMonitorBeats", async (monitorID, period, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
v-for="(beat, index) in shortBeatList"
|
||||
:key="index"
|
||||
class="beat"
|
||||
:class="{ 'empty' : (beat === 0), 'down' : (beat.status === 0), 'pending' : (beat.status === 2) }"
|
||||
:class="{ 'empty' : (beat === 0), 'down' : (beat.status === 0), 'pending' : (beat.status === 2 || beat.status === 4) }"
|
||||
:style="beatStyle"
|
||||
:title="getBeatTitle(beat)"
|
||||
/>
|
||||
|
|
|
@ -18,7 +18,7 @@ export default {
|
|||
return "primary";
|
||||
}
|
||||
|
||||
if (this.status === 2) {
|
||||
if (this.status === 2 || this.status === 4) {
|
||||
return "warning";
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,10 @@ export default {
|
|||
return this.$t("Pending");
|
||||
}
|
||||
|
||||
if (this.status === 4) {
|
||||
return this.$t("Degraded");
|
||||
}
|
||||
|
||||
return this.$t("Unknown");
|
||||
},
|
||||
},
|
||||
|
|
|
@ -34,7 +34,7 @@ export default {
|
|||
return "primary"
|
||||
}
|
||||
|
||||
if (this.lastHeartBeat.status === 2) {
|
||||
if (this.lastHeartBeat.status === 2 || this.lastHeartBeat.status === 4) {
|
||||
return "warning"
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@ export default {
|
|||
ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
|
||||
upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
|
||||
maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
|
||||
Degraded: "Degraded",
|
||||
"Dependent Monitors": "Dependent Monitors",
|
||||
"Pick Dependent Monitors...": "Pick Dependent Monitors...",
|
||||
dependentMonitorsDescription: "Select the monitor(s) on which this monitor depends. If the dependent monitor(s) fails, this monitor will be affected too.",
|
||||
acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
|
||||
passwordNotMatchMsg: "The repeat password does not match.",
|
||||
notificationDescription: "Notifications must be assigned to a monitor to function.",
|
||||
|
|
|
@ -317,6 +317,14 @@ export default {
|
|||
socket.emit("deleteMonitor", monitorID, callback);
|
||||
},
|
||||
|
||||
addDependentMonitors(monitorID, monitors, callback) {
|
||||
socket.emit("addDependentMonitors", monitorID, monitors, callback);
|
||||
},
|
||||
|
||||
getDependentMonitors(monitorID, callback) {
|
||||
socket.emit("getDependentMonitors", monitorID, callback);
|
||||
},
|
||||
|
||||
clearData() {
|
||||
console.log("reset heartbeat list");
|
||||
this.heartbeatList = {};
|
||||
|
@ -385,6 +393,11 @@ export default {
|
|||
text: this.$t("Pending"),
|
||||
color: "warning",
|
||||
};
|
||||
} else if (lastHeartBeat.status === 4) {
|
||||
result[monitorID] = {
|
||||
text: this.$t("Degraded"),
|
||||
color: "warning",
|
||||
};
|
||||
} else {
|
||||
result[monitorID] = unknown;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
<h3>{{ $t("Down") }}</h3>
|
||||
<span class="num text-danger">{{ stats.down }}</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h3>{{ $t("Degraded") }}</h3>
|
||||
<span class="num text-warning">{{ stats.degraded }}</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h3>{{ $t("Unknown") }}</h3>
|
||||
<span class="num text-secondary">{{ stats.unknown }}</span>
|
||||
|
@ -93,6 +97,7 @@ export default {
|
|||
let result = {
|
||||
up: 0,
|
||||
down: 0,
|
||||
degraded: 0,
|
||||
unknown: 0,
|
||||
pause: 0,
|
||||
};
|
||||
|
@ -110,6 +115,8 @@ export default {
|
|||
result.down++;
|
||||
} else if (beat.status === 2) {
|
||||
result.up++;
|
||||
} else if (beat.status === 4) {
|
||||
result.degraded++;
|
||||
} else {
|
||||
result.unknown++;
|
||||
}
|
||||
|
|
|
@ -154,6 +154,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shadow-box table-shadow-box">
|
||||
<label for="dependent-monitors" class="form-label" style="margin-top: 20px">{{ $t("Dependent Monitors") }}</label>
|
||||
<br>
|
||||
<button v-for="monitor in this.dependentMonitors" class="btn btn-monitor" style="margin: 5px; cursor: auto; color: white; font-weight: bold">
|
||||
{{ monitor }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Confirm ref="confirmPause" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="pauseMonitor">
|
||||
{{ $t("pauseMonitorMsg") }}
|
||||
</Confirm>
|
||||
|
@ -212,6 +220,7 @@ export default {
|
|||
hideCount: true,
|
||||
chunksNavigation: "scroll",
|
||||
},
|
||||
dependentMonitors: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -286,9 +295,19 @@ export default {
|
|||
},
|
||||
},
|
||||
mounted() {
|
||||
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.$root.getSocket().emit("getDependentMonitors", this.$route.params.id, (res) => {
|
||||
if (res.ok) {
|
||||
this.dependentMonitors = Object.values(res.monitors).map(monitor => monitor.name);
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
testNotification() {
|
||||
this.$root.getSocket().emit("testNotification", this.monitor.id);
|
||||
toast.success("Test notification is requested.");
|
||||
|
@ -499,4 +518,8 @@ table {
|
|||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.btn-monitor {
|
||||
background-color: #5cdd8b;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -189,6 +189,32 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Dependent Monitors -->
|
||||
<div class="my-3">
|
||||
<label for="dependent-monitors" class="form-label">{{ $t("Dependent Monitors") }}</label>
|
||||
|
||||
<VueMultiselect
|
||||
id="dependent-monitors"
|
||||
v-model="dependentMonitors"
|
||||
:options="dependentMonitorsOptions"
|
||||
track-by="id"
|
||||
label="name"
|
||||
:multiple="true"
|
||||
:allow-empty="false"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:preserve-search="true"
|
||||
:placeholder="$t('Pick Dependent Monitors...')"
|
||||
:preselect-first="false"
|
||||
:max-height="600"
|
||||
:taggable="false"
|
||||
></VueMultiselect>
|
||||
|
||||
<div class="form-text">
|
||||
{{ $t("dependentMonitorsDescription") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<tags-manager ref="tagsManager" :pre-selected-tags="monitor.tags"></tags-manager>
|
||||
</div>
|
||||
|
@ -317,6 +343,8 @@ export default {
|
|||
},
|
||||
acceptedStatusCodeOptions: [],
|
||||
dnsresolvetypeOptions: [],
|
||||
dependentMonitors: [],
|
||||
dependentMonitorsOptions: [],
|
||||
|
||||
// Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
|
||||
ipRegexPattern: "((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))",
|
||||
|
@ -392,6 +420,17 @@ export default {
|
|||
mounted() {
|
||||
this.init();
|
||||
|
||||
this.$root.getMonitorList((res) => {
|
||||
if (res.ok) {
|
||||
Object.values(this.$root.monitorList).filter(monitor => monitor.id != this.$route.params.id).map(monitor => {
|
||||
this.dependentMonitorsOptions.push({
|
||||
id: monitor.id,
|
||||
name: monitor.name,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let acceptedStatusCodeOptions = [
|
||||
"100-199",
|
||||
"200-299",
|
||||
|
@ -422,6 +461,8 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.dependentMonitors = [];
|
||||
|
||||
if (this.isAdd) {
|
||||
|
||||
this.monitor = {
|
||||
|
@ -451,6 +492,16 @@ export default {
|
|||
if (res.ok) {
|
||||
this.monitor = res.monitor;
|
||||
|
||||
this.$root.getSocket().emit("getDependentMonitors", this.$route.params.id, (res) => {
|
||||
if (res.ok) {
|
||||
Object.values(res.monitors).map(monitor => {
|
||||
this.dependentMonitors.push(monitor);
|
||||
});
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
});
|
||||
|
||||
// Handling for monitors that are created before 1.7.0
|
||||
if (this.monitor.retryInterval === 0) {
|
||||
this.monitor.retryInterval = this.monitor.interval;
|
||||
|
@ -506,10 +557,12 @@ export default {
|
|||
if (res.ok) {
|
||||
await this.$refs.tagsManager.submit(res.monitorID);
|
||||
|
||||
toast.success(res.msg);
|
||||
this.processing = false;
|
||||
this.$root.getMonitorList();
|
||||
this.$router.push("/dashboard/" + res.monitorID);
|
||||
await this.addDependentMonitors(res.monitorID, () => {
|
||||
toast.success(res.msg);
|
||||
this.processing = false;
|
||||
this.$root.getMonitorList();
|
||||
this.$router.push("/dashboard/" + res.monitorID);
|
||||
});
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.processing = false;
|
||||
|
@ -519,14 +572,27 @@ export default {
|
|||
} else {
|
||||
await this.$refs.tagsManager.submit(this.monitor.id);
|
||||
|
||||
this.$root.getSocket().emit("editMonitor", this.monitor, (res) => {
|
||||
this.processing = false;
|
||||
this.$root.toastRes(res);
|
||||
this.init();
|
||||
this.$root.getSocket().emit("editMonitor", this.monitor, async (res) => {
|
||||
await this.addDependentMonitors(this.monitor.id, () => {
|
||||
this.processing = false;
|
||||
this.$root.toastRes(res);
|
||||
this.init();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async addDependentMonitors(monitorID, callback) {
|
||||
await this.$root.addDependentMonitors(monitorID, this.dependentMonitors, async (res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
} else {
|
||||
this.$root.getMonitorList();
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// Added a Notification Event
|
||||
// Enable it if the notification is added in EditMonitor.vue
|
||||
addedNotification(id) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// Backend uses the compiled file util.js
|
||||
// Frontend uses util.ts
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0;
|
||||
exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.DEGRADED = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0;
|
||||
const _dayjs = require("dayjs");
|
||||
const dayjs = _dayjs;
|
||||
exports.isDev = process.env.NODE_ENV === "development";
|
||||
|
@ -15,6 +15,7 @@ exports.appName = "Uptime Kuma";
|
|||
exports.DOWN = 0;
|
||||
exports.UP = 1;
|
||||
exports.PENDING = 2;
|
||||
exports.DEGRADED = 4;
|
||||
exports.STATUS_PAGE_ALL_DOWN = 0;
|
||||
exports.STATUS_PAGE_ALL_UP = 1;
|
||||
exports.STATUS_PAGE_PARTIAL_DOWN = 2;
|
||||
|
|
|
@ -14,6 +14,7 @@ export const appName = "Uptime Kuma";
|
|||
export const DOWN = 0;
|
||||
export const UP = 1;
|
||||
export const PENDING = 2;
|
||||
export const DEGRADED = 4;
|
||||
|
||||
export const STATUS_PAGE_ALL_DOWN = 0;
|
||||
export const STATUS_PAGE_ALL_UP = 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue