mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-18 04:04:41 -05:00
WIP: Add maintenance status
This commit is contained in:
parent
c1ccaa7a9f
commit
c84de4d259
@ -2,13 +2,14 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
|
|||||||
const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC } = require("../../src/util");
|
const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC } = require("../../src/util");
|
||||||
const { isArray } = require("chart.js/helpers");
|
const { isArray } = require("chart.js/helpers");
|
||||||
const { timeObjectToUTC, timeObjectToLocal } = require("../util-server");
|
const { timeObjectToUTC, timeObjectToLocal } = require("../util-server");
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
const dayjs = require("dayjs");
|
||||||
|
|
||||||
class Maintenance extends BeanModel {
|
class Maintenance extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON for public
|
* Return an object that ready to parse to JSON for public
|
||||||
* Only show necessary data to public
|
* Only show necessary data to public
|
||||||
* @param {string} timezone If not specified, the timeRange will be in UTC
|
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
async toPublicJSON() {
|
async toPublicJSON() {
|
||||||
@ -38,6 +39,7 @@ class Maintenance extends BeanModel {
|
|||||||
timeRange: timeRange,
|
timeRange: timeRange,
|
||||||
weekdays: (this.weekdays) ? JSON.parse(this.weekdays) : [],
|
weekdays: (this.weekdays) ? JSON.parse(this.weekdays) : [],
|
||||||
daysOfMonth: (this.days_of_month) ? JSON.parse(this.days_of_month) : [],
|
daysOfMonth: (this.days_of_month) ? JSON.parse(this.days_of_month) : [],
|
||||||
|
timeslotList: await this.getTimeslotList(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isArray(obj.weekdays)) {
|
if (!isArray(obj.weekdays)) {
|
||||||
@ -48,9 +50,45 @@ class Maintenance extends BeanModel {
|
|||||||
obj.daysOfMonth = [];
|
obj.daysOfMonth = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maintenance Status
|
||||||
|
if (!obj.active) {
|
||||||
|
obj.status = "inactive";
|
||||||
|
} else if (obj.strategy === "manual" || obj.timeslotList.length > 0) {
|
||||||
|
for (let timeslot of obj.timeslotList) {
|
||||||
|
if (dayjs.utc(timeslot.start_date) <= dayjs.utc() && dayjs.utc(timeslot.end_date) >= dayjs.utc()) {
|
||||||
|
obj.status = "under-maintenance";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj.status) {
|
||||||
|
obj.status = "scheduled";
|
||||||
|
}
|
||||||
|
} else if (obj.timeslotList.length === 0) {
|
||||||
|
obj.status = "ended";
|
||||||
|
} else {
|
||||||
|
obj.status = "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only get future or current timeslots only
|
||||||
|
* @returns {Promise<[]>}
|
||||||
|
*/
|
||||||
|
async getTimeslotList() {
|
||||||
|
return await R.getAll(`
|
||||||
|
SELECT maintenance_timeslot.*
|
||||||
|
FROM maintenance_timeslot, maintenance
|
||||||
|
WHERE maintenance_timeslot.maintenance_id = maintenance.id
|
||||||
|
AND maintenance.id = ?
|
||||||
|
AND ${Maintenance.getActiveAndFutureMaintenanceSQLCondition()}
|
||||||
|
`, [
|
||||||
|
this.id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON
|
* Return an object that ready to parse to JSON
|
||||||
* @param {string} timezone If not specified, the timeRange will be in UTC
|
* @param {string} timezone If not specified, the timeRange will be in UTC
|
||||||
@ -111,6 +149,19 @@ class Maintenance extends BeanModel {
|
|||||||
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL conditions for active and future maintenance
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static getActiveAndFutureMaintenanceSQLCondition() {
|
||||||
|
return `
|
||||||
|
(maintenance_timeslot.end_date >= DATETIME('now')
|
||||||
|
AND maintenance.active = 1)
|
||||||
|
OR
|
||||||
|
(maintenance.strategy = 'manual' AND active = 1)
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Maintenance;
|
module.exports = Maintenance;
|
||||||
|
@ -1109,10 +1109,10 @@ class Monitor extends BeanModel {
|
|||||||
FROM monitor_maintenance mm
|
FROM monitor_maintenance mm
|
||||||
JOIN maintenance
|
JOIN maintenance
|
||||||
ON mm.maintenance_id = maintenance.id
|
ON mm.maintenance_id = maintenance.id
|
||||||
JOIN maintenance_timeslot
|
AND mm.monitor_id = ?
|
||||||
|
LEFT JOIN maintenance_timeslot
|
||||||
ON maintenance_timeslot.maintenance_id = maintenance.id
|
ON maintenance_timeslot.maintenance_id = maintenance.id
|
||||||
WHERE mm.monitor_id = ?
|
WHERE ${activeCondition}
|
||||||
AND ${activeCondition}
|
|
||||||
LIMIT 1`, [ monitorID ]);
|
LIMIT 1`, [ monitorID ]);
|
||||||
return maintenance.count !== 0;
|
return maintenance.count !== 0;
|
||||||
}
|
}
|
||||||
|
@ -269,6 +269,20 @@ optgroup {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-normal {
|
||||||
|
$bg-color: $dark-header-bg;
|
||||||
|
|
||||||
|
color: $dark-font-color;
|
||||||
|
background-color: $bg-color;
|
||||||
|
border-color: $bg-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
$hover-color: darken($bg-color, 3%);
|
||||||
|
background-color: $hover-color;
|
||||||
|
border-color: $hover-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.btn-warning {
|
.btn-warning {
|
||||||
color: $dark-font-color2;
|
color: $dark-font-color2;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<router-link to="/settings" class="dropdown-item" :class="{ active: $route.path.includes('settings') }">
|
<router-link to="/settings/general" class="dropdown-item" :class="{ active: $route.path.includes('settings') }">
|
||||||
<font-awesome-icon icon="cog" /> {{ $t("Settings") }}
|
<font-awesome-icon icon="cog" /> {{ $t("Settings") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
|
@ -12,10 +12,6 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
isActiveMaintenance(endDate) {
|
|
||||||
return (dayjs.utc(endDate).unix() >= dayjs.utc().unix());
|
|
||||||
},
|
|
||||||
|
|
||||||
toUTC(value) {
|
toUTC(value) {
|
||||||
return dayjs.tz(value, this.timezone).utc().format();
|
return dayjs.tz(value, this.timezone).utc().format();
|
||||||
},
|
},
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
v-for="(item, index) in sortedMaintenanceList"
|
v-for="(item, index) in sortedMaintenanceList"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="item"
|
class="item"
|
||||||
:class="{ 'ended': !$root.isActiveMaintenance(item.end_date) }"
|
:class="item.status"
|
||||||
>
|
>
|
||||||
<div class="left-part">
|
<div class="left-part">
|
||||||
<div
|
<div
|
||||||
@ -35,7 +35,7 @@
|
|||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<router-link v-if="false" :to="maintenanceURL(item.id)" class="btn btn-light">{{ $t("Details") }}</router-link>
|
<router-link v-if="false" :to="maintenanceURL(item.id)" class="btn btn-light">{{ $t("Details") }}</router-link>
|
||||||
|
|
||||||
<button v-if="item.active" class="btn btn-light" @click="pauseDialog">
|
<button v-if="item.active" class="btn btn-normal" @click="pauseDialog">
|
||||||
<font-awesome-icon icon="pause" /> {{ $t("Pause") }}
|
<font-awesome-icon icon="pause" /> {{ $t("Pause") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -43,7 +43,7 @@
|
|||||||
<font-awesome-icon icon="play" /> {{ $t("Resume") }}
|
<font-awesome-icon icon="play" /> {{ $t("Resume") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<router-link :to="'/maintenance/edit/' + item.id" class="btn btn-secondary">
|
<router-link :to="'/maintenance/edit/' + item.id" class="btn btn-normal">
|
||||||
<font-awesome-icon icon="edit" /> {{ $t("Edit") }}
|
<font-awesome-icon icon="edit" /> {{ $t("Edit") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
@ -90,36 +90,6 @@ export default {
|
|||||||
let result = Object.values(this.$root.maintenanceList);
|
let result = Object.values(this.$root.maintenanceList);
|
||||||
|
|
||||||
result.sort((m1, m2) => {
|
result.sort((m1, m2) => {
|
||||||
|
|
||||||
if (this.$root.isActiveMaintenance(m1.end_date) !== this.$root.isActiveMaintenance(m2.end_date)) {
|
|
||||||
if (!this.$root.isActiveMaintenance(m2.end_date)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!this.$root.isActiveMaintenance(m1.end_date)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.$root.isActiveMaintenance(m1.end_date) && this.$root.isActiveMaintenance(m2.end_date)) {
|
|
||||||
if (Date.parse(m1.end_date) < Date.parse(m2.end_date)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Date.parse(m2.end_date) < Date.parse(m1.end_date)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.$root.isActiveMaintenance(m1.end_date) && !this.$root.isActiveMaintenance(m2.end_date)) {
|
|
||||||
if (Date.parse(m1.end_date) < Date.parse(m2.end_date)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Date.parse(m2.end_date) < Date.parse(m1.end_date)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m1.title.localeCompare(m2.title);
|
return m1.title.localeCompare(m2.title);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -173,7 +143,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Pause maintenance
|
* Pause maintenance
|
||||||
*/
|
*/
|
||||||
pauseMonitor() {
|
pauseMaintenance() {
|
||||||
return;
|
return;
|
||||||
this.$root.getSocket().emit("pauseMaintenance", selectedMaintenanceID, (res) => {
|
this.$root.getSocket().emit("pauseMaintenance", selectedMaintenanceID, (res) => {
|
||||||
this.$root.toastRes(res);
|
this.$root.toastRes(res);
|
||||||
@ -211,13 +181,43 @@ export default {
|
|||||||
background-color: $highlight-white;
|
background-color: $highlight-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.under-maintenance {
|
||||||
|
background-color: rgba(23, 71, 245, 0.16);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(23, 71, 245, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
background-color: $maintenance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.scheduled {
|
||||||
|
.circle {
|
||||||
|
background-color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inactive {
|
||||||
|
.circle {
|
||||||
|
background-color: $danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.ended {
|
&.ended {
|
||||||
.left-part {
|
.left-part {
|
||||||
opacity: 0.5;
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
background-color: $dark-font-color;
|
background-color: $dark-font-color;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unknown {
|
||||||
|
.circle {
|
||||||
|
background-color: $dark-font-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +230,6 @@ export default {
|
|||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
border-radius: 50rem;
|
border-radius: 50rem;
|
||||||
background-color: $maintenance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
|
Loading…
Reference in New Issue
Block a user