diff --git a/package-lock.json b/package-lock.json index f422d6a8..161208af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "@vitejs/plugin-legacy": "~2.1.0", "@vitejs/plugin-vue": "~3.1.0", "@vue/compiler-sfc": "~3.2.36", - "@vuepic/vue-datepicker": "^3.4.8", + "@vuepic/vue-datepicker": "~3.4.8", "aedes": "^0.46.3", "babel-plugin-rewire": "~1.2.0", "bootstrap": "5.1.3", diff --git a/server/model/maintenance.js b/server/model/maintenance.js index 840267ef..d46b9d4b 100644 --- a/server/model/maintenance.js +++ b/server/model/maintenance.js @@ -1,5 +1,5 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); -const { parseTimeObject, parseTimeFromTimeObject, isoToUTCDateTime, utcToISODateTime, SQL_DATETIME_FORMAT, utcToLocal, localToUTC } = require("../../src/util"); +const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC } = require("../../src/util"); const { isArray } = require("chart.js/helpers"); const { timeObjectToUTC, timeObjectToLocal } = require("../util-server"); @@ -11,7 +11,7 @@ class Maintenance extends BeanModel { * @param {string} timezone If not specified, the timeRange will be in UTC * @returns {Object} */ - async toPublicJSON(timezone = null) { + async toPublicJSON() { let dateRange = []; if (this.start_date) { @@ -22,21 +22,11 @@ class Maintenance extends BeanModel { } let timeRange = []; - let startTime = parseTimeObject(this.start_time); + let startTime = timeObjectToLocal(parseTimeObject(this.start_time)); timeRange.push(startTime); - let endTime = parseTimeObject(this.end_time); + let endTime = timeObjectToLocal(parseTimeObject(this.end_time)); timeRange.push(endTime); - // Apply timezone offset - if (timezone) { - if (this.start_time) { - timeObjectToLocal(startTime, timezone); - } - if (this.end_time) { - timeObjectToLocal(endTime, timezone); - } - } - let obj = { id: this.id, title: this.title, @@ -70,18 +60,16 @@ class Maintenance extends BeanModel { return this.toPublicJSON(timezone); } - static jsonToBean(bean, obj, timezone) { + static jsonToBean(bean, obj) { if (obj.id) { bean.id = obj.id; } // Apply timezone offset to timeRange, as it cannot apply automatically. - if (timezone) { - if (obj.timeRange[0]) { - timeObjectToUTC(obj.timeRange[0], timezone); - if (obj.timeRange[1]) { - timeObjectToUTC(obj.timeRange[1], timezone); - } + if (obj.timeRange[0]) { + timeObjectToUTC(obj.timeRange[0]); + if (obj.timeRange[1]) { + timeObjectToUTC(obj.timeRange[1]); } } @@ -118,7 +106,7 @@ class Maintenance extends BeanModel { (maintenance_timeslot.start_date <= DATETIME('now') AND maintenance_timeslot.end_date >= DATETIME('now') AND maintenance.active = 1) - AND + OR (maintenance.strategy = 'manual' AND active = 1) `; diff --git a/server/model/maintenance_timeslot.js b/server/model/maintenance_timeslot.js index 0ac5158d..4db3a1db 100644 --- a/server/model/maintenance_timeslot.js +++ b/server/model/maintenance_timeslot.js @@ -40,6 +40,12 @@ class MaintenanceTimeslot extends BeanModel { bean.end_date = maintenance.end_date; bean.generated_next = true; await R.store(bean); + } else if (maintenance.strategy === "recurring-interval") { + // TODO + } else if (maintenance.strategy === "recurring-weekday") { + // TODO + } else if (maintenance.strategy === "recurring-day-of-month") { + // TODO } else { throw new Error("Unknown maintenance strategy"); } diff --git a/server/socket-handlers/maintenance-socket-handler.js b/server/socket-handlers/maintenance-socket-handler.js index 9ae36b5c..49527f23 100644 --- a/server/socket-handlers/maintenance-socket-handler.js +++ b/server/socket-handlers/maintenance-socket-handler.js @@ -5,7 +5,6 @@ const apicache = require("../modules/apicache"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const Maintenance = require("../model/maintenance"); const server = UptimeKumaServer.getInstance(); -const dayjs = require("dayjs"); const MaintenanceTimeslot = require("../model/maintenance_timeslot"); /** @@ -14,13 +13,13 @@ const MaintenanceTimeslot = require("../model/maintenance_timeslot"); */ module.exports.maintenanceSocketHandler = (socket) => { // Add a new maintenance - socket.on("addMaintenance", async (maintenance, timezone, callback) => { + socket.on("addMaintenance", async (maintenance, callback) => { try { checkLogin(socket); log.debug("maintenance", maintenance); - let bean = Maintenance.jsonToBean(R.dispense("maintenance"), maintenance, timezone); + let bean = Maintenance.jsonToBean(R.dispense("maintenance"), maintenance); bean.user_id = socket.userID; let maintenanceID = await R.store(bean); await MaintenanceTimeslot.generateTimeslot(bean); @@ -42,7 +41,7 @@ module.exports.maintenanceSocketHandler = (socket) => { }); // Edit a maintenance - socket.on("editMaintenance", async (maintenance, timezone, callback) => { + socket.on("editMaintenance", async (maintenance, callback) => { try { checkLogin(socket); @@ -52,7 +51,7 @@ module.exports.maintenanceSocketHandler = (socket) => { throw new Error("Permission denied."); } - Maintenance.jsonToBean(bean, maintenance, timezone); + Maintenance.jsonToBean(bean, maintenance); await R.store(bean); await MaintenanceTimeslot.generateTimeslot(bean, null, true); @@ -142,7 +141,7 @@ module.exports.maintenanceSocketHandler = (socket) => { } }); - socket.on("getMaintenance", async (maintenanceID, timezone, callback) => { + socket.on("getMaintenance", async (maintenanceID, callback) => { try { checkLogin(socket); @@ -155,7 +154,7 @@ module.exports.maintenanceSocketHandler = (socket) => { callback({ ok: true, - maintenance: await bean.toJSON(timezone), + maintenance: await bean.toJSON(), }); } catch (e) { diff --git a/server/util-server.js b/server/util-server.js index ddb9dab5..7c81cde7 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -648,8 +648,14 @@ module.exports.send403 = (res, msg = "") => { }; function timeObjectConvertTimezone(obj, timezone, timeObjectToUTC = true) { - // e.g. +08:00 - let offsetString = dayjs().tz(timezone).format("Z"); + let offsetString; + + if (timezone) { + offsetString = dayjs().tz(timezone).format("Z"); + } else { + offsetString = dayjs().format("Z"); + } + let hours = parseInt(offsetString.substring(1, 3)); let minutes = parseInt(offsetString.substring(4, 6)); @@ -680,10 +686,22 @@ function timeObjectConvertTimezone(obj, timezone, timeObjectToUTC = true) { return obj; } -module.exports.timeObjectToUTC = (obj, timezone) => { +/** + * + * @param {object} obj + * @param {string} timezone + * @returns {object} + */ +module.exports.timeObjectToUTC = (obj, timezone = undefined) => { return timeObjectConvertTimezone(obj, timezone, true); }; -module.exports.timeObjectToLocal = (obj, timezone) => { +/** + * + * @param {object} obj + * @param {string} timezone + * @returns {object} + */ +module.exports.timeObjectToLocal = (obj, timezone = undefined) => { return timeObjectConvertTimezone(obj, timezone, false); }; diff --git a/src/languages/en.js b/src/languages/en.js index d6a65b04..835fa248 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -630,4 +630,5 @@ export default { lastDay2: "2nd Last Day of Month", lastDay3: "3rd Last Day of Month", lastDay4: "4th Last Day of Month", + "No Maintenance": "No Maintenance", }; diff --git a/src/pages/EditMaintenance.vue b/src/pages/EditMaintenance.vue index 946059cb..790588d8 100644 --- a/src/pages/EditMaintenance.vue +++ b/src/pages/EditMaintenance.vue @@ -200,7 +200,8 @@ :monthChangeOnScroll="false" :minDate="minDate" :enableTimePicker="false" - :utc="true" + format="yyyy-MM-dd" + modelType="yyyy-MM-dd HH:mm:ss" /> @@ -356,9 +357,6 @@ export default { }, methods: { init() { - // Use browser's timezone! - let timezone = dayjs.tz.guess(); - this.affectedMonitors = []; this.selectedStatusPages = []; @@ -381,7 +379,7 @@ export default { daysOfMonth: [], }; } else if (this.isEdit) { - this.$root.getSocket().emit("getMaintenance", this.$route.params.id, timezone, (res) => { + this.$root.getSocket().emit("getMaintenance", this.$route.params.id, (res) => { if (res.ok) { this.maintenance = res.maintenance; @@ -440,11 +438,8 @@ export default { this.maintenance.end_date = this.$root.toUTC(this.maintenance.end_date); */ - // Use browser's timezone! - let timezone = dayjs.tz.guess(); - if (this.isAdd) { - this.$root.addMaintenance(this.maintenance, timezone, async (res) => { + this.$root.addMaintenance(this.maintenance, async (res) => { if (res.ok) { await this.addMonitorMaintenance(res.maintenanceID, async () => { await this.addMaintenanceStatusPage(res.maintenanceID, () => { @@ -461,7 +456,7 @@ export default { }); } else { - this.$root.getSocket().emit("editMaintenance", this.maintenance, timezone, async (res) => { + this.$root.getSocket().emit("editMaintenance", this.maintenance, async (res) => { if (res.ok) { await this.addMonitorMaintenance(res.maintenanceID, async () => { await this.addMaintenanceStatusPage(res.maintenanceID, () => { diff --git a/src/pages/ManageMaintenance.vue b/src/pages/ManageMaintenance.vue index 4bfa9059..51e3ee28 100644 --- a/src/pages/ManageMaintenance.vue +++ b/src/pages/ManageMaintenance.vue @@ -13,7 +13,7 @@
- {{ $t("No maintenance") }} + {{ $t("No Maintenance") }}
{{ $t("Details") }} + + + + + {{ $t("Edit") }} + @@ -48,6 +58,10 @@ Learn More
+ + {{ $t("pauseMaintenanceMsg") }} + + {{ $t("deleteMaintenanceMsg") }} @@ -148,6 +162,33 @@ export default { } }); }, + + /** + * Show dialog to confirm pause + */ + pauseDialog() { + this.$refs.confirmPause.show(); + }, + + /** + * Pause maintenance + */ + pauseMonitor() { + return; + this.$root.getSocket().emit("pauseMaintenance", selectedMaintenanceID, (res) => { + this.$root.toastRes(res); + }); + }, + + /** + * Resume maintenance + */ + resumeMaintenance() { + return; + this.$root.getSocket().emit("resumeMaintenance", selectedMaintenanceID, (res) => { + this.$root.toastRes(res); + }); + }, }, };