mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-27 16:54:04 +00:00
WIP
This commit is contained in:
parent
2271ac4a5a
commit
e07aa982c3
10 changed files with 152 additions and 33 deletions
|
@ -125,7 +125,7 @@ async function sendInfo(socket) {
|
||||||
latestVersion: checkVersion.latestVersion,
|
latestVersion: checkVersion.latestVersion,
|
||||||
primaryBaseURL: await setting("primaryBaseURL"),
|
primaryBaseURL: await setting("primaryBaseURL"),
|
||||||
serverTimezone: await server.getTimezone(),
|
serverTimezone: await server.getTimezone(),
|
||||||
serverTimezoneOffset: dayjs().format("Z"),
|
serverTimezoneOffset: server.getTimezoneOffset(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,15 @@ 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(),
|
timeslotList: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const timeslotList = await this.getTimeslotList();
|
||||||
|
|
||||||
|
for (let timeslot of timeslotList) {
|
||||||
|
obj.timeslotList.push(await timeslot.toPublicJSON());
|
||||||
|
}
|
||||||
|
|
||||||
if (!isArray(obj.weekdays)) {
|
if (!isArray(obj.weekdays)) {
|
||||||
obj.weekdays = [];
|
obj.weekdays = [];
|
||||||
}
|
}
|
||||||
|
@ -53,7 +59,9 @@ class Maintenance extends BeanModel {
|
||||||
// Maintenance Status
|
// Maintenance Status
|
||||||
if (!obj.active) {
|
if (!obj.active) {
|
||||||
obj.status = "inactive";
|
obj.status = "inactive";
|
||||||
} else if (obj.strategy === "manual" || obj.timeslotList.length > 0) {
|
} else if (obj.strategy === "manual") {
|
||||||
|
obj.status = "under-maintenance";
|
||||||
|
} else if (obj.timeslotList.length > 0) {
|
||||||
for (let timeslot of obj.timeslotList) {
|
for (let timeslot of obj.timeslotList) {
|
||||||
if (dayjs.utc(timeslot.start_date) <= dayjs.utc() && dayjs.utc(timeslot.end_date) >= dayjs.utc()) {
|
if (dayjs.utc(timeslot.start_date) <= dayjs.utc() && dayjs.utc(timeslot.end_date) >= dayjs.utc()) {
|
||||||
obj.status = "under-maintenance";
|
obj.status = "under-maintenance";
|
||||||
|
@ -78,7 +86,7 @@ class Maintenance extends BeanModel {
|
||||||
* @returns {Promise<[]>}
|
* @returns {Promise<[]>}
|
||||||
*/
|
*/
|
||||||
async getTimeslotList() {
|
async getTimeslotList() {
|
||||||
return await R.getAll(`
|
return R.convertToBeans("maintenance_timeslot", await R.getAll(`
|
||||||
SELECT maintenance_timeslot.*
|
SELECT maintenance_timeslot.*
|
||||||
FROM maintenance_timeslot, maintenance
|
FROM maintenance_timeslot, maintenance
|
||||||
WHERE maintenance_timeslot.maintenance_id = maintenance.id
|
WHERE maintenance_timeslot.maintenance_id = maintenance.id
|
||||||
|
@ -86,7 +94,7 @@ class Maintenance extends BeanModel {
|
||||||
AND ${Maintenance.getActiveAndFutureMaintenanceSQLCondition()}
|
AND ${Maintenance.getActiveAndFutureMaintenanceSQLCondition()}
|
||||||
`, [
|
`, [
|
||||||
this.id
|
this.id
|
||||||
]);
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,10 +164,10 @@ class Maintenance extends BeanModel {
|
||||||
*/
|
*/
|
||||||
static getActiveAndFutureMaintenanceSQLCondition() {
|
static getActiveAndFutureMaintenanceSQLCondition() {
|
||||||
return `
|
return `
|
||||||
(maintenance_timeslot.end_date >= DATETIME('now')
|
((maintenance_timeslot.end_date >= DATETIME('now')
|
||||||
AND maintenance.active = 1)
|
AND maintenance.active = 1)
|
||||||
OR
|
OR
|
||||||
(maintenance.strategy = 'manual' AND active = 1)
|
(maintenance.strategy = 'manual' AND active = 1))
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { log } = require("../../src/util");
|
const { log, utcToLocal, SQL_DATETIME_FORMAT_WITHOUT_SECOND } = require("../../src/util");
|
||||||
|
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||||
|
|
||||||
class MaintenanceTimeslot extends BeanModel {
|
class MaintenanceTimeslot extends BeanModel {
|
||||||
|
|
||||||
async toPublicJSON() {
|
async toPublicJSON() {
|
||||||
|
const serverTimezoneOffset = await UptimeKumaServer.getInstance().getTimezoneOffset();
|
||||||
|
|
||||||
|
const obj = {
|
||||||
|
id: this.id,
|
||||||
|
startDate: this.start_date,
|
||||||
|
endDate: this.end_date,
|
||||||
|
startDateServerTimezone: utcToLocal(this.start_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND),
|
||||||
|
endDateServerTimezone: utcToLocal(this.end_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND),
|
||||||
|
serverTimezoneOffset,
|
||||||
|
};
|
||||||
|
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
async toJSON() {
|
async toJSON() {
|
||||||
|
return await this.toPublicJSON();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -258,4 +258,54 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("pauseMaintenance", async (maintenanceID, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
log.debug("maintenance", `Pause Maintenance: ${maintenanceID} User ID: ${socket.userID}`);
|
||||||
|
|
||||||
|
await R.exec("UPDATE maintenance SET active = 0 WHERE id = ? ", [
|
||||||
|
maintenanceID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "Paused Successfully.",
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.sendMaintenanceList(socket);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("resumeMaintenance", async (maintenanceID, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
log.debug("maintenance", `Resume Maintenance: ${maintenanceID} User ID: ${socket.userID}`);
|
||||||
|
|
||||||
|
await R.exec("UPDATE maintenance SET active = 1 WHERE id = ? ", [
|
||||||
|
maintenanceID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "Resume Successfully",
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.sendMaintenanceList(socket);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -204,6 +204,10 @@ class UptimeKumaServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTimezoneOffset() {
|
||||||
|
return dayjs().format("Z");
|
||||||
|
}
|
||||||
|
|
||||||
async setTimezone(timezone) {
|
async setTimezone(timezone) {
|
||||||
await Settings.set("serverTimezone", timezone, "general");
|
await Settings.set("serverTimezone", timezone, "general");
|
||||||
process.env.TZ = timezone;
|
process.env.TZ = timezone;
|
||||||
|
|
|
@ -101,11 +101,6 @@ optgroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override Bootstrap
|
|
||||||
.btn-group > .btn:hover {
|
|
||||||
z-index: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
|
@ -125,6 +120,19 @@ optgroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-normal {
|
||||||
|
$bg-color: #F5F5F5;
|
||||||
|
|
||||||
|
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: white;
|
color: white;
|
||||||
|
|
||||||
|
|
|
@ -631,4 +631,10 @@ export default {
|
||||||
lastDay3: "3rd Last Day of Month",
|
lastDay3: "3rd Last Day of Month",
|
||||||
lastDay4: "4th Last Day of Month",
|
lastDay4: "4th Last Day of Month",
|
||||||
"No Maintenance": "No Maintenance",
|
"No Maintenance": "No Maintenance",
|
||||||
|
pauseMaintenanceMsg: "Are you sure want to pause?",
|
||||||
|
"maintenanceStatus-under-maintenance": "Under Maintenance",
|
||||||
|
"maintenanceStatus-inactive": "Inactive",
|
||||||
|
"maintenanceStatus-scheduled": "Scheduled",
|
||||||
|
"maintenanceStatus-ended": "Ended",
|
||||||
|
"maintenanceStatus-unknown": "Unknown",
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,7 +28,18 @@
|
||||||
></div>
|
></div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="title">{{ item.title }}</div>
|
<div class="title">{{ item.title }}</div>
|
||||||
<div>{{ item.description }}</div>
|
<div v-if="false">{{ item.description }}</div>
|
||||||
|
<div class="status">
|
||||||
|
{{ $t("maintenanceStatus-" + item.status) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="item.strategy === 'manual'" class="timeslot">
|
||||||
|
{{ $t("Manual") }}
|
||||||
|
</div>
|
||||||
|
<div v-else-if="item.timeslotList.length > 0" class="timeslot">
|
||||||
|
{{ item.timeslotList[0].startDateServerTimezone }} <span class="to">-</span> {{ item.timeslotList[0].endDateServerTimezone }}
|
||||||
|
(UTC{{ item.timeslotList[0].serverTimezoneOffset }})
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -36,11 +47,11 @@
|
||||||
<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>
|
||||||
|
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button v-if="item.active" class="btn btn-normal" @click="pauseDialog">
|
<button v-if="item.active" class="btn btn-normal" @click="pauseDialog(item.id)">
|
||||||
<font-awesome-icon icon="pause" /> {{ $t("Pause") }}
|
<font-awesome-icon icon="pause" /> {{ $t("Pause") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button v-if="!item.active" class="btn btn-primary" @click="resumeMaintenance">
|
<button v-if="!item.active" class="btn btn-primary" @click="resumeMaintenance(item.id)">
|
||||||
<font-awesome-icon icon="play" /> {{ $t("Resume") }}
|
<font-awesome-icon icon="play" /> {{ $t("Resume") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -149,7 +160,8 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Show dialog to confirm pause
|
* Show dialog to confirm pause
|
||||||
*/
|
*/
|
||||||
pauseDialog() {
|
pauseDialog(maintenanceID) {
|
||||||
|
this.selectedMaintenanceID = maintenanceID;
|
||||||
this.$refs.confirmPause.show();
|
this.$refs.confirmPause.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -157,8 +169,7 @@ export default {
|
||||||
* Pause maintenance
|
* Pause maintenance
|
||||||
*/
|
*/
|
||||||
pauseMaintenance() {
|
pauseMaintenance() {
|
||||||
return;
|
this.$root.getSocket().emit("pauseMaintenance", this.selectedMaintenanceID, (res) => {
|
||||||
this.$root.getSocket().emit("pauseMaintenance", selectedMaintenanceID, (res) => {
|
|
||||||
this.$root.toastRes(res);
|
this.$root.toastRes(res);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -166,9 +177,8 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Resume maintenance
|
* Resume maintenance
|
||||||
*/
|
*/
|
||||||
resumeMaintenance() {
|
resumeMaintenance(id) {
|
||||||
return;
|
this.$root.getSocket().emit("resumeMaintenance", id, (res) => {
|
||||||
this.$root.getSocket().emit("resumeMaintenance", selectedMaintenanceID, (res) => {
|
|
||||||
this.$root.toastRes(res);
|
this.$root.toastRes(res);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -189,6 +199,7 @@ export default {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
min-height: 90px;
|
min-height: 90px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $highlight-white;
|
background-color: $highlight-white;
|
||||||
|
@ -251,9 +262,27 @@ export default {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slug {
|
.status {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timeslot {
|
||||||
|
margin-top: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
.to {
|
||||||
|
margin: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
color: white;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/util.js
11
src/util.js
|
@ -7,7 +7,7 @@
|
||||||
// Backend uses the compiled file util.js
|
// Backend uses the compiled file util.js
|
||||||
// Frontend uses util.ts
|
// Frontend uses util.ts
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0;
|
exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0;
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
exports.isDev = process.env.NODE_ENV === "development";
|
exports.isDev = process.env.NODE_ENV === "development";
|
||||||
exports.appName = "Uptime Kuma";
|
exports.appName = "Uptime Kuma";
|
||||||
|
@ -21,6 +21,7 @@ exports.STATUS_PAGE_PARTIAL_DOWN = 2;
|
||||||
exports.STATUS_PAGE_MAINTENANCE = 3;
|
exports.STATUS_PAGE_MAINTENANCE = 3;
|
||||||
exports.SQL_DATE_FORMAT = "YYYY-MM-DD";
|
exports.SQL_DATE_FORMAT = "YYYY-MM-DD";
|
||||||
exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
|
exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
|
||||||
|
exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm";
|
||||||
/** Flip the status of s */
|
/** Flip the status of s */
|
||||||
function flipStatus(s) {
|
function flipStatus(s) {
|
||||||
if (s === exports.UP) {
|
if (s === exports.UP) {
|
||||||
|
@ -366,11 +367,11 @@ exports.utcToISODateTime = utcToISODateTime;
|
||||||
/**
|
/**
|
||||||
* For SQL_DATETIME_FORMAT
|
* For SQL_DATETIME_FORMAT
|
||||||
*/
|
*/
|
||||||
function utcToLocal(input) {
|
function utcToLocal(input, format = exports.SQL_DATETIME_FORMAT) {
|
||||||
return dayjs.utc(input).local().format(exports.SQL_DATETIME_FORMAT);
|
return dayjs.utc(input).local().format(format);
|
||||||
}
|
}
|
||||||
exports.utcToLocal = utcToLocal;
|
exports.utcToLocal = utcToLocal;
|
||||||
function localToUTC(input) {
|
function localToUTC(input, format = exports.SQL_DATETIME_FORMAT) {
|
||||||
return dayjs(input).utc().format(exports.SQL_DATETIME_FORMAT);
|
return dayjs(input).utc().format(format);
|
||||||
}
|
}
|
||||||
exports.localToUTC = localToUTC;
|
exports.localToUTC = localToUTC;
|
||||||
|
|
|
@ -25,6 +25,7 @@ export const STATUS_PAGE_MAINTENANCE = 3;
|
||||||
|
|
||||||
export const SQL_DATE_FORMAT = "YYYY-MM-DD";
|
export const SQL_DATE_FORMAT = "YYYY-MM-DD";
|
||||||
export const SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
|
export const SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
|
||||||
|
export const SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm";
|
||||||
|
|
||||||
/** Flip the status of s */
|
/** Flip the status of s */
|
||||||
export function flipStatus(s: number) {
|
export function flipStatus(s: number) {
|
||||||
|
@ -412,10 +413,10 @@ export function utcToISODateTime(input : string) {
|
||||||
/**
|
/**
|
||||||
* For SQL_DATETIME_FORMAT
|
* For SQL_DATETIME_FORMAT
|
||||||
*/
|
*/
|
||||||
export function utcToLocal(input : string) {
|
export function utcToLocal(input : string, format = SQL_DATETIME_FORMAT) {
|
||||||
return dayjs.utc(input).local().format(SQL_DATETIME_FORMAT);
|
return dayjs.utc(input).local().format(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function localToUTC(input : string) {
|
export function localToUTC(input : string, format = SQL_DATETIME_FORMAT) {
|
||||||
return dayjs(input).utc().format(SQL_DATETIME_FORMAT);
|
return dayjs(input).utc().format(format);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue