Compare commits

...

6 commits

Author SHA1 Message Date
Vivek Pandey
990435d3f5
Merge f6342b84a1 into 8a432ac937 2024-11-12 18:00:27 +00:00
Ionys
8a432ac937
fix(status page): Make sure the group deletion is correctly handled when groupIDList is empty (#5340)
Some checks failed
Auto Test / check-linters (push) Has been cancelled
Auto Test / armv7-simple-test (18, ARMv7) (push) Has been cancelled
Auto Test / armv7-simple-test (20, ARMv7) (push) Has been cancelled
Auto Test / e2e-test (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
validate / json-yaml-validate (push) Has been cancelled
validate / validate (push) Has been cancelled
Auto Test / auto-test (18, ARM64) (push) Has been cancelled
Auto Test / auto-test (18, macos-latest) (push) Has been cancelled
Auto Test / auto-test (18, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (18, windows-latest) (push) Has been cancelled
Auto Test / auto-test (20, ARM64) (push) Has been cancelled
Auto Test / auto-test (20, macos-latest) (push) Has been cancelled
Auto Test / auto-test (20, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (20, windows-latest) (push) Has been cancelled
2024-11-12 19:00:09 +01:00
Vivek Pandey
f6342b84a1 Refactoring variable names, and control flow. 2024-10-19 23:40:43 +05:30
Vivek Pandey
b000c1d532 Removing console log and approx sign 2024-10-19 19:24:41 +05:30
Vivek Pandey
2438e87efa ESLint Fixes 2024-10-19 14:39:39 +05:30
Vivek Pandey
ea7bafabdd Convert interval seconds to days, hours, minutes, and seconds 2024-10-19 01:51:25 +05:30
5 changed files with 105 additions and 13 deletions

View file

@ -220,13 +220,17 @@ module.exports.statusPageSocketHandler = (socket) => {
// Delete groups that are not in the list // Delete groups that are not in the list
log.debug("socket", "Delete groups that are not in the list"); log.debug("socket", "Delete groups that are not in the list");
const slots = groupIDList.map(() => "?").join(","); if (groupIDList.length === 0) {
await R.exec("DELETE FROM `group` WHERE status_page_id = ?", [ statusPage.id ]);
} else {
const slots = groupIDList.map(() => "?").join(",");
const data = [ const data = [
...groupIDList, ...groupIDList,
statusPage.id statusPage.id
]; ];
await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots}) AND status_page_id = ?`, data); await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots}) AND status_page_id = ?`, data);
}
const server = UptimeKumaServer.getInstance(); const server = UptimeKumaServer.getInstance();

View file

@ -1,5 +1,5 @@
import { currentLocale } from "../i18n"; import { currentLocale } from "../i18n";
import { setPageLocale } from "../util-frontend"; import { setPageLocale, relativeTimeFormatter } from "../util-frontend";
const langModules = import.meta.glob("../lang/*.json"); const langModules = import.meta.glob("../lang/*.json");
export default { export default {
@ -28,11 +28,13 @@ export default {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async changeLang(lang) { async changeLang(lang) {
let message = (await langModules["../lang/" + lang + ".json"]()).default; let message = (await langModules["../lang/" + lang + ".json"]())
.default;
this.$i18n.setLocaleMessage(lang, message); this.$i18n.setLocaleMessage(lang, message);
this.$i18n.locale = lang; this.$i18n.locale = lang;
localStorage.locale = lang; localStorage.locale = lang;
setPageLocale(); setPageLocale();
} relativeTimeFormatter.updateLocale(lang);
} },
},
}; };

View file

@ -76,7 +76,7 @@
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<HeartbeatBar :monitor-id="monitor.id" /> <HeartbeatBar :monitor-id="monitor.id" />
<span class="word">{{ $t("checkEverySecond", [ monitor.interval ]) }}</span> <span class="word">{{ $t("checkEverySecond", [ monitor.interval ]) }} ({{ secondsToHumanReadableFormat(monitor.interval) }})</span>
</div> </div>
<div class="col-md-4 text-center"> <div class="col-md-4 text-center">
<span class="badge rounded-pill" :class=" 'bg-' + status.color " style="font-size: 30px;" data-testid="monitor-status">{{ status.text }}</span> <span class="badge rounded-pill" :class=" 'bg-' + status.color " style="font-size: 30px;" data-testid="monitor-status">{{ status.text }}</span>
@ -285,7 +285,7 @@ import Tag from "../components/Tag.vue";
import CertificateInfo from "../components/CertificateInfo.vue"; import CertificateInfo from "../components/CertificateInfo.vue";
import { getMonitorRelativeURL } from "../util.ts"; import { getMonitorRelativeURL } from "../util.ts";
import { URL } from "whatwg-url"; import { URL } from "whatwg-url";
import { getResBaseURL } from "../util-frontend"; import { getResBaseURL, relativeTimeFormatter } from "../util-frontend";
import { highlight, languages } from "prismjs/components/prism-core"; import { highlight, languages } from "prismjs/components/prism-core";
import "prismjs/components/prism-clike"; import "prismjs/components/prism-clike";
import "prismjs/components/prism-javascript"; import "prismjs/components/prism-javascript";
@ -656,7 +656,12 @@ export default {
.replace("https://example.com/api/push/key?status=up&msg=OK&ping=", this.pushURL); .replace("https://example.com/api/push/key?status=up&msg=OK&ping=", this.pushURL);
this.pushMonitor.code = code; this.pushMonitor.code = code;
}); });
},
secondsToHumanReadableFormat(seconds) {
return relativeTimeFormatter.secondsToHumanReadableFormat(seconds);
} }
}, },
}; };
</script> </script>

View file

@ -577,6 +577,9 @@
<div class="my-3"> <div class="my-3">
<label for="interval" class="form-label">{{ $t("Heartbeat Interval") }} ({{ $t("checkEverySecond", [ monitor.interval ]) }})</label> <label for="interval" class="form-label">{{ $t("Heartbeat Interval") }} ({{ $t("checkEverySecond", [ monitor.interval ]) }})</label>
<input id="interval" v-model="monitor.interval" type="number" class="form-control" required :min="minInterval" step="1" :max="maxInterval" @blur="finishUpdateInterval"> <input id="interval" v-model="monitor.interval" type="number" class="form-control" required :min="minInterval" step="1" :max="maxInterval" @blur="finishUpdateInterval">
<div class="form-text">
{{ monitor.humanReadableInterval }}
</div>
</div> </div>
<div class="my-3"> <div class="my-3">
@ -1061,7 +1064,7 @@ import RemoteBrowserDialog from "../components/RemoteBrowserDialog.vue";
import ProxyDialog from "../components/ProxyDialog.vue"; import ProxyDialog from "../components/ProxyDialog.vue";
import TagsManager from "../components/TagsManager.vue"; import TagsManager from "../components/TagsManager.vue";
import { genSecret, isDev, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, sleep } from "../util.ts"; import { genSecret, isDev, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, sleep } from "../util.ts";
import { hostNameRegexPattern } from "../util-frontend"; import { hostNameRegexPattern, relativeTimeFormatter } from "../util-frontend";
import HiddenInput from "../components/HiddenInput.vue"; import HiddenInput from "../components/HiddenInput.vue";
import EditMonitorConditions from "../components/EditMonitorConditions.vue"; import EditMonitorConditions from "../components/EditMonitorConditions.vue";
@ -1076,6 +1079,7 @@ const monitorDefaults = {
url: "https://", url: "https://",
method: "GET", method: "GET",
interval: 60, interval: 60,
humanReadableInterval: relativeTimeFormatter.secondsToHumanReadableFormat(60),
retryInterval: 60, retryInterval: 60,
resendInterval: 0, resendInterval: 0,
maxretries: 0, maxretries: 0,
@ -1412,6 +1416,8 @@ message HealthCheckResponse {
if (this.monitor.retryInterval === oldValue) { if (this.monitor.retryInterval === oldValue) {
this.monitor.retryInterval = value; this.monitor.retryInterval = value;
} }
// Converting monitor.interval to human readable format.
this.monitor.humanReadableInterval = relativeTimeFormatter.secondsToHumanReadableFormat(value);
}, },
"monitor.timeout"(value, oldValue) { "monitor.timeout"(value, oldValue) {

View file

@ -213,3 +213,78 @@ export function getToastErrorTimeout() {
return errorTimeout; return errorTimeout;
} }
class RelativeTimeFormatter {
/**
* Default locale and options for Relative Time Formatter
*/
constructor() {
this.options = { numeric: "auto" };
this.instance = new Intl.RelativeTimeFormat(currentLocale(), this.options);
}
/**
* Method to update the instance locale and options
* @param {string} locale Localization identifier (e.g., "en", "ar-sy") to update the instance with.
* @returns {void} No return value.
*/
updateLocale(locale) {
this.instance = new Intl.RelativeTimeFormat(locale, this.options);
}
/**
* Method to convert seconds into Human readable format
* @param {number} seconds Receive value in seconds.
* @returns {string} String converted to Days Mins Seconds Format
*/
secondsToHumanReadableFormat(seconds) {
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const minutes = Math.floor(((seconds % 86400) % 3600) / 60);
const secs = ((seconds % 86400) % 3600) % 60;
const parts = [];
/**
* Build the formatted string from parts
* 1. Get the relative time formatted parts from the instance.
* 2. Filter out the relevant parts literal (unit of time) or integer (value).
* 3. Map out the required values.
* @param {number} value Receives value in seconds.
* @param {string} unitOfTime Expected unit of time after conversion.
* @returns {void}
*/
const toFormattedPart = (value, unitOfTime) => {
const partsArray = this.instance.formatToParts(value, unitOfTime);
const filteredParts = partsArray
.filter(
(part, index) =>
(part.type === "literal" || part.type === "integer") &&
index > 0
)
.map((part) => part.value);
const formattedString = filteredParts.join("").trim();
parts.push(formattedString);
};
if (days > 0) {
toFormattedPart(days, "days");
}
if (hours > 0) {
toFormattedPart(hours, "hour");
}
if (minutes > 0) {
toFormattedPart(minutes, "minute");
}
if (secs > 0) {
toFormattedPart(secs, "second");
}
if (parts.length > 0) {
return `${parts.join(" ")}`;
}
return this.instance.format(0, "second"); // Handle case for 0 seconds
}
}
export const relativeTimeFormatter = new RelativeTimeFormatter();