mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-23 06:19:49 -05:00
Implement recurring day of month and day of week
This commit is contained in:
parent
0b8d4cdaac
commit
d8a676abb6
@ -112,6 +112,40 @@ class Maintenance extends BeanModel {
|
|||||||
return this.toPublicJSON(timezone);
|
return this.toPublicJSON(timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDayOfWeekList() {
|
||||||
|
log.debug("timeslot", "List: " + this.weekdays);
|
||||||
|
return JSON.parse(this.weekdays).sort(function (a, b) {
|
||||||
|
return a - b;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getDayOfMonthList() {
|
||||||
|
return JSON.parse(this.days_of_month).sort(function (a, b) {
|
||||||
|
return a - b;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getStartDateTime() {
|
||||||
|
let startOfTheDay = dayjs.utc(this.start_date).format("HH:mm");
|
||||||
|
log.debug("timeslot", "startOfTheDay: " + startOfTheDay);
|
||||||
|
|
||||||
|
// Start Time
|
||||||
|
let startTimeSecond = dayjs.utc(this.start_time, "HH:mm").diff(dayjs.utc(startOfTheDay, "HH:mm"), "second");
|
||||||
|
log.debug("timeslot", "startTime: " + startTimeSecond);
|
||||||
|
|
||||||
|
// Bake StartDate + StartTime = Start DateTime
|
||||||
|
return dayjs.utc(this.start_date).add(startTimeSecond, "second");
|
||||||
|
}
|
||||||
|
|
||||||
|
getDuration() {
|
||||||
|
let duration = dayjs.utc(this.end_time, "HH:mm").diff(dayjs.utc(this.start_time, "HH:mm"), "second");
|
||||||
|
// Add 24hours if it is across day
|
||||||
|
if (duration < 0) {
|
||||||
|
duration += 24 * 3600;
|
||||||
|
}
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
static jsonToBean(bean, obj) {
|
static jsonToBean(bean, obj) {
|
||||||
if (obj.id) {
|
if (obj.id) {
|
||||||
bean.id = obj.id;
|
bean.id = obj.id;
|
||||||
|
@ -40,6 +40,7 @@ class MaintenanceTimeslot extends BeanModel {
|
|||||||
|
|
||||||
if (maintenance.strategy === "manual") {
|
if (maintenance.strategy === "manual") {
|
||||||
log.debug("maintenance", "No need to generate timeslot for manual type");
|
log.debug("maintenance", "No need to generate timeslot for manual type");
|
||||||
|
|
||||||
} else if (maintenance.strategy === "single") {
|
} else if (maintenance.strategy === "single") {
|
||||||
let bean = R.dispense("maintenance_timeslot");
|
let bean = R.dispense("maintenance_timeslot");
|
||||||
bean.maintenance_id = maintenance.id;
|
bean.maintenance_id = maintenance.id;
|
||||||
@ -47,74 +48,131 @@ class MaintenanceTimeslot extends BeanModel {
|
|||||||
bean.end_date = maintenance.end_date;
|
bean.end_date = maintenance.end_date;
|
||||||
bean.generated_next = true;
|
bean.generated_next = true;
|
||||||
return await R.store(bean);
|
return await R.store(bean);
|
||||||
} else if (maintenance.strategy === "recurring-interval") {
|
|
||||||
let bean = R.dispense("maintenance_timeslot");
|
|
||||||
|
|
||||||
|
} else if (maintenance.strategy === "recurring-interval") {
|
||||||
// Prevent dead loop, in case interval_day is not set
|
// Prevent dead loop, in case interval_day is not set
|
||||||
if (!maintenance.interval_day || maintenance.interval_day <= 0) {
|
if (!maintenance.interval_day || maintenance.interval_day <= 0) {
|
||||||
maintenance.interval_day = 1;
|
maintenance.interval_day = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let startOfTheDay = dayjs.utc(maintenance.start_date).format("HH:mm");
|
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
|
||||||
log.debug("timeslot", "startOfTheDay: " + startOfTheDay);
|
return startDateTime.add(maintenance.interval_day, "day");
|
||||||
|
});
|
||||||
|
|
||||||
// Start Time
|
|
||||||
let startTimeSecond = dayjs.utc(maintenance.start_time, "HH:mm").diff(dayjs.utc(startOfTheDay, "HH:mm"), "second");
|
|
||||||
log.debug("timeslot", "startTime: " + startTimeSecond);
|
|
||||||
|
|
||||||
// Duration
|
|
||||||
let duration = dayjs.utc(maintenance.end_time, "HH:mm").diff(dayjs.utc(maintenance.start_time, "HH:mm"), "second");
|
|
||||||
// Add 24hours if it is across day
|
|
||||||
if (duration < 0) {
|
|
||||||
duration += 24 * 3600;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bake StartDate + StartTime = Start DateTime
|
|
||||||
let startDateTime = dayjs.utc(maintenance.start_date).add(startTimeSecond, "second");
|
|
||||||
let endDateTime;
|
|
||||||
|
|
||||||
// Keep generating from the first possible date, until it is ok
|
|
||||||
while (true) {
|
|
||||||
log.debug("timeslot", "startDateTime: " + startDateTime.format());
|
|
||||||
|
|
||||||
// Handling out of effective date range
|
|
||||||
if (startDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
|
|
||||||
log.debug("timeslot", "Out of effective date range");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
endDateTime = startDateTime.add(duration, "second");
|
|
||||||
|
|
||||||
// If endDateTime is out of effective date range, use the end datetime from effective date range
|
|
||||||
if (endDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
|
|
||||||
endDateTime = dayjs.utc(maintenance.end_date);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If minDate is set, the endDateTime must be bigger than it.
|
|
||||||
// And the endDateTime must be bigger current time
|
|
||||||
if (
|
|
||||||
(!minDate || endDateTime.diff(minDate) > 0) &&
|
|
||||||
endDateTime.diff(dayjs()) > 0
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
startDateTime = startDateTime.add(maintenance.interval_day, "day");
|
|
||||||
}
|
|
||||||
|
|
||||||
bean.maintenance_id = maintenance.id;
|
|
||||||
bean.start_date = localToUTC(startDateTime);
|
|
||||||
bean.end_date = localToUTC(endDateTime);
|
|
||||||
bean.generated_next = false;
|
|
||||||
return await R.store(bean);
|
|
||||||
} else if (maintenance.strategy === "recurring-weekday") {
|
} else if (maintenance.strategy === "recurring-weekday") {
|
||||||
// TODO
|
let dayOfWeekList = maintenance.getDayOfWeekList();
|
||||||
|
|
||||||
|
if (dayOfWeekList.length <= 0) {
|
||||||
|
log.debug("timeslot", "No weekdays selected?");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
|
||||||
|
while (true) {
|
||||||
|
startDateTime = startDateTime.add(1, "day");
|
||||||
|
|
||||||
|
log.debug("timeslot", "nextDateTime: " + startDateTime);
|
||||||
|
|
||||||
|
let day = startDateTime.local().day();
|
||||||
|
log.debug("timeslot", "nextDateTime.day(): " + day);
|
||||||
|
|
||||||
|
if (dayOfWeekList.includes(day)) {
|
||||||
|
return startDateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
} else if (maintenance.strategy === "recurring-day-of-month") {
|
} else if (maintenance.strategy === "recurring-day-of-month") {
|
||||||
// TODO
|
let dayOfMonthList = maintenance.getDayOfMonthList();
|
||||||
|
if (dayOfMonthList.length <= 0) {
|
||||||
|
log.debug("timeslot", "No day selected?");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
startDateTime = startDateTime.add(1, "day");
|
||||||
|
|
||||||
|
let day = parseInt(startDateTime.local().format("D"));
|
||||||
|
|
||||||
|
log.debug("timeslot", "day: " + day);
|
||||||
|
|
||||||
|
// Check 1-31
|
||||||
|
if (dayOfMonthList.includes(day)) {
|
||||||
|
return startDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check "lastDay1","lastDay2"...
|
||||||
|
let daysInMonth = startDateTime.daysInMonth();
|
||||||
|
let lastDayList = [];
|
||||||
|
|
||||||
|
// Small first, e.g. 28 > 29 > 30 > 31
|
||||||
|
for (let i = 4; i >= 1; i--) {
|
||||||
|
if (dayOfMonthList.includes("lastDay" + i)) {
|
||||||
|
lastDayList.push(daysInMonth - i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("timeslot", "lastDayList: " + lastDayList);
|
||||||
|
if (lastDayList.includes(day)) {
|
||||||
|
return startDateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unknown maintenance strategy");
|
throw new Error("Unknown maintenance strategy");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a next timeslot for all recurring types
|
||||||
|
* @param maintenance
|
||||||
|
* @param minDate
|
||||||
|
* @param nextDayCallback The logic how to get the next possible day
|
||||||
|
* @returns {Promise<null|MaintenanceTimeslot>}
|
||||||
|
*/
|
||||||
|
static async handleRecurringType(maintenance, minDate, nextDayCallback) {
|
||||||
|
let bean = R.dispense("maintenance_timeslot");
|
||||||
|
|
||||||
|
let duration = maintenance.getDuration();
|
||||||
|
let startDateTime = maintenance.getStartDateTime();
|
||||||
|
let endDateTime;
|
||||||
|
|
||||||
|
// Keep generating from the first possible date, until it is ok
|
||||||
|
while (true) {
|
||||||
|
log.debug("timeslot", "startDateTime: " + startDateTime.format());
|
||||||
|
|
||||||
|
// Handling out of effective date range
|
||||||
|
if (startDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
|
||||||
|
log.debug("timeslot", "Out of effective date range");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
endDateTime = startDateTime.add(duration, "second");
|
||||||
|
|
||||||
|
// If endDateTime is out of effective date range, use the end datetime from effective date range
|
||||||
|
if (endDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
|
||||||
|
endDateTime = dayjs.utc(maintenance.end_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If minDate is set, the endDateTime must be bigger than it.
|
||||||
|
// And the endDateTime must be bigger current time
|
||||||
|
if (
|
||||||
|
(!minDate || endDateTime.diff(minDate) > 0) &&
|
||||||
|
endDateTime.diff(dayjs()) > 0
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
startDateTime = nextDayCallback(startDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
bean.maintenance_id = maintenance.id;
|
||||||
|
bean.start_date = localToUTC(startDateTime);
|
||||||
|
bean.end_date = localToUTC(endDateTime);
|
||||||
|
bean.generated_next = false;
|
||||||
|
return await R.store(bean);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = MaintenanceTimeslot;
|
module.exports = MaintenanceTimeslot;
|
||||||
|
@ -620,6 +620,7 @@ export default {
|
|||||||
weekdayShortFri: "Fri",
|
weekdayShortFri: "Fri",
|
||||||
weekdayShortSat: "Sat",
|
weekdayShortSat: "Sat",
|
||||||
weekdayShortSun: "Sun",
|
weekdayShortSun: "Sun",
|
||||||
|
dayOfWeek: "Day of Week",
|
||||||
dayOfMonth: "Day of Month",
|
dayOfMonth: "Day of Month",
|
||||||
lastDay: "Last Day",
|
lastDay: "Last Day",
|
||||||
lastDay1: "Last Day of Month",
|
lastDay1: "Last Day of Month",
|
||||||
|
@ -91,8 +91,8 @@
|
|||||||
<option value="manual">{{ $t("strategyManual") }}</option>
|
<option value="manual">{{ $t("strategyManual") }}</option>
|
||||||
<option value="single">Single Maintenance Window</option>
|
<option value="single">Single Maintenance Window</option>
|
||||||
<option value="recurring-interval">{{ $t("Recurring") }} - {{ $t("recurringInterval") }}</option>
|
<option value="recurring-interval">{{ $t("Recurring") }} - {{ $t("recurringInterval") }}</option>
|
||||||
<option value="recurring-weekday">{{ $t("Recurring") }} - Weekday</option>
|
<option value="recurring-weekday">{{ $t("Recurring") }} - {{ $t("dayOfWeek") }}</option>
|
||||||
<option value="recurring-day-of-month">{{ $t("Recurring") }} - Day of Month</option>
|
<option value="recurring-day-of-month">{{ $t("Recurring") }} - {{ $t("dayOfMonth") }}</option>
|
||||||
<option v-if="false" value="recurring-day-of-year">{{ $t("Recurring") }} - Day of Year</option>
|
<option v-if="false" value="recurring-day-of-year">{{ $t("Recurring") }} - Day of Year</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -136,7 +136,7 @@
|
|||||||
<template v-if="maintenance.strategy === 'recurring-weekday'">
|
<template v-if="maintenance.strategy === 'recurring-weekday'">
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<label for="interval-day" class="form-label">
|
<label for="interval-day" class="form-label">
|
||||||
{{ $t("Weekday") }}
|
{{ $t("dayOfWeek") }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<!-- Weekday Picker -->
|
<!-- Weekday Picker -->
|
||||||
@ -201,6 +201,7 @@
|
|||||||
:minDate="minDate"
|
:minDate="minDate"
|
||||||
format="yyyy-MM-dd HH:mm:ss"
|
format="yyyy-MM-dd HH:mm:ss"
|
||||||
modelType="yyyy-MM-dd HH:mm:ss"
|
modelType="yyyy-MM-dd HH:mm:ss"
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -297,9 +298,9 @@ export default {
|
|||||||
value: 6,
|
value: 6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "weekday7",
|
id: "weekday0",
|
||||||
langKey: "weekdayShortSun",
|
langKey: "weekdayShortSun",
|
||||||
value: 7,
|
value: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user