From 31b90d12a4ef07c0bdd45187baf31d8931e25c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Kr=C3=BDda?= Date: Sat, 30 Apr 2022 17:17:22 +0200 Subject: [PATCH] Added the ability to choose on which status pages maintenance information should be displayed --- db/patch-maintenance-table.sql | 9 +++ server/routers/api-router.js | 19 ++--- server/server.js | 58 ++++++++++++++++ src/languages/en.js | 5 ++ src/mixins/socket.js | 8 +++ src/pages/EditMaintenance.vue | 116 +++++++++++++++++++++++++++---- src/pages/MaintenanceDetails.vue | 24 +++++-- src/pages/StatusPage.vue | 6 +- 8 files changed, 216 insertions(+), 29 deletions(-) diff --git a/db/patch-maintenance-table.sql b/db/patch-maintenance-table.sql index ee4a7f882..ce14f7662 100644 --- a/db/patch-maintenance-table.sql +++ b/db/patch-maintenance-table.sql @@ -20,6 +20,15 @@ CREATE TABLE monitor_maintenance CONSTRAINT FK_monitor FOREIGN KEY (monitor_id) REFERENCES monitor (id) ON DELETE CASCADE ON UPDATE CASCADE ); +CREATE TABLE maintenance_status_page +( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + status_page_id INTEGER NOT NULL, + maintenance_id INTEGER NOT NULL, + CONSTRAINT FK_maintenance FOREIGN KEY (maintenance_id) REFERENCES maintenance (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_status_page FOREIGN KEY (status_page_id) REFERENCES status_page (id) ON DELETE CASCADE ON UPDATE CASCADE +); + create index maintenance_user_id on maintenance (user_id); COMMIT; diff --git a/server/routers/api-router.js b/server/routers/api-router.js index a5a87b8c5..da036ee2c 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -128,7 +128,7 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons incident = incident.toPublicJSON(); } - let maintenance = await getMaintenanceList(); + let maintenance = await getMaintenanceList(statusPage.id); // Public Group List const publicGroupList = []; @@ -158,17 +158,20 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons }); // Status Page - Maintenance List -async function getMaintenanceList() { +async function getMaintenanceList(statusPageId) { try { const publicMaintenanceList = []; let maintenanceBeanList = R.convertToBeans("maintenance", await R.getAll(` - SELECT maintenance.* - FROM maintenance - WHERE datetime(maintenance.start_date) <= datetime('now') - AND datetime(maintenance.end_date) >= datetime('now') - ORDER BY maintenance.end_date - `)); + SELECT m.* + FROM maintenance m + JOIN maintenance_status_page msp + ON msp.maintenance_id = m.id + WHERE datetime(m.start_date) <= datetime('now') + AND datetime(m.end_date) >= datetime('now') + AND msp.status_page_id = ? + ORDER BY m.end_date + `, [ statusPageId ])); for (const bean of maintenanceBeanList) { publicMaintenanceList.push(await bean.toPublicJSON()); diff --git a/server/server.js b/server/server.js index b4060351a..d45b97a4b 100644 --- a/server/server.js +++ b/server/server.js @@ -802,6 +802,40 @@ try { } }); + // Add a new monitor_maintenance + socket.on("addMaintenanceStatusPage", async (maintenanceID, statusPages, callback) => { + try { + checkLogin(socket); + + await R.exec("DELETE FROM maintenance_status_page WHERE maintenance_id = ?", [ + maintenanceID + ]); + + for await (const statusPage of statusPages) { + let bean = R.dispense("maintenance_status_page"); + + bean.import({ + status_page_id: statusPage.id, + maintenance_id: maintenanceID + }); + await R.store(bean); + } + + apicache.clear(); + + callback({ + ok: true, + msg: "Added Successfully.", + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + socket.on("getMonitorList", async (callback) => { try { checkLogin(socket); @@ -906,6 +940,30 @@ try { } }); + socket.on("getMaintenanceStatusPage", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + console.log(`Get Status Pages for Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + let statusPages = await R.getAll("SELECT status_page.id, status_page.title FROM maintenance_status_page msp JOIN status_page ON msp.status_page_id = status_page.id WHERE msp.maintenance_id = ? ", [ + maintenanceID, + ]); + + callback({ + ok: true, + statusPages, + }); + + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + socket.on("getMonitorBeats", async (monitorID, period, callback) => { try { checkLogin(socket); diff --git a/src/languages/en.js b/src/languages/en.js index 8bb1a73c3..37f7cb437 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -15,9 +15,14 @@ export default { "Pick Affected Monitors...": "Pick Affected Monitors...", "Start of maintenance": "Start of maintenance", "Expected end of maintenance": "Expected end of maintenance", + "Show on all pages": "Show on all status pages", + "Selected status pages": "Selected status pages", + "Select status pages...": "Select status pages...", End: "End", affectedMonitorsDescription: "Select monitors that are affected by current maintenance", atLeastOneMonitor: "Select at least one affected monitor", + selectedStatusPagesDescription: "Select status pages to display maintenance info on", + atLeastOneStatusPage: "Select at least one status page", maintenanceTitleExample: "Network infrastructure maintenance", maintenanceDescriptionExample: "Example: Network infrastructure maintenance is underway which will affect some of our services.", passwordNotMatchMsg: "The repeat password does not match.", diff --git a/src/mixins/socket.js b/src/mixins/socket.js index 6d4311b1f..4fa779bfe 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -388,10 +388,18 @@ export default { socket.emit("addMonitorMaintenance", maintenanceID, monitors, callback); }, + addMaintenanceStatusPage(maintenanceID, statusPages, callback) { + socket.emit("addMaintenanceStatusPage", maintenanceID, statusPages, callback); + }, + getMonitorMaintenance(maintenanceID, callback) { socket.emit("getMonitorMaintenance", maintenanceID, callback); }, + getMaintenanceStatusPage(maintenanceID, callback) { + socket.emit("getMaintenanceStatusPage", maintenanceID, callback); + }, + deleteMonitor(monitorID, callback) { socket.emit("deleteMonitor", monitorID, callback); }, diff --git a/src/pages/EditMaintenance.vue b/src/pages/EditMaintenance.vue index e8cfeb4f0..26aa857f2 100644 --- a/src/pages/EditMaintenance.vue +++ b/src/pages/EditMaintenance.vue @@ -54,22 +54,63 @@
- +
- +
+ +
+ + +
+ + +
+ + + + +
+ {{ $t("selectedStatusPagesDescription") }} +
+
+
- + - +
- +
+ + +
+ {{ $t("deleteMaintenanceMsg") }} @@ -45,6 +52,7 @@ export default { data() { return { affectedMonitors: [], + selectedStatusPages: [], }; }, computed: { @@ -65,6 +73,14 @@ export default { toast.error(res.msg); } }); + + this.$root.getSocket().emit("getMaintenanceStatusPage", this.$route.params.id, (res) => { + if (res.ok) { + this.selectedStatusPages = Object.values(res.statusPages).map(statusPage => statusPage.title); + } else { + toast.error(res.msg); + } + }); }, deleteDialog() { diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index 015a57be2..4d021dc46 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -247,7 +247,7 @@
- + {{ $t("Maintenance") }}
@@ -595,7 +595,7 @@ export default { } this.incident = res.data.incident; - this.maintenance = res.data.maintenance; + this.maintenance = res.data.maintenance || []; this.$root.publicGroupList = res.data.publicGroupList; }); @@ -956,7 +956,7 @@ footer { background-color: #0d1117; } -.statusMaintenance { +.status-maintenance { color: $maintenance; margin-right: 5px; }