mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-30 18:24:03 +00:00
Compare commits
6 commits
ceffc2c8c0
...
282ada58e9
Author | SHA1 | Date | |
---|---|---|---|
|
282ada58e9 | ||
|
6899603eb7 | ||
|
f6342b84a1 | ||
|
b000c1d532 | ||
|
2438e87efa | ||
|
ea7bafabdd |
5 changed files with 99 additions and 11 deletions
|
@ -5,20 +5,20 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-from-email" class="form-label">{{ $t("From Email") }}</label>
|
<label for="sendgrid-from-email" class="form-label">{{ $t("From Email") }}</label>
|
||||||
<input id="sendgrid-from-email" v-model="$parent.notification.sendgridFromEmail" type="email" class="form-control" required>
|
<input id="sendgrid-from-email" v-model="$parent.notification.sendgridFromEmail" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-to-email" class="form-label">{{ $t("To Email") }}</label>
|
<label for="sendgrid-to-email" class="form-label">{{ $t("To Email") }}</label>
|
||||||
<input id="sendgrid-to-email" v-model="$parent.notification.sendgridToEmail" type="email" class="form-control" required>
|
<input id="sendgrid-to-email" v-model="$parent.notification.sendgridToEmail" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-cc-email" class="form-label">{{ $t("smtpCC") }}</label>
|
<label for="sendgrid-cc-email" class="form-label">{{ $t("smtpCC") }}</label>
|
||||||
<input id="sendgrid-cc-email" v-model="$parent.notification.sendgridCcEmail" type="email" class="form-control">
|
<input id="sendgrid-cc-email" v-model="$parent.notification.sendgridCcEmail" type="text" class="form-control">
|
||||||
<div class="form-text">{{ $t("Separate multiple email addresses with commas") }}</div>
|
<div class="form-text">{{ $t("Separate multiple email addresses with commas") }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-bcc-email" class="form-label">{{ $t("smtpBCC") }}</label>
|
<label for="sendgrid-bcc-email" class="form-label">{{ $t("smtpBCC") }}</label>
|
||||||
<input id="sendgrid-bcc-email" v-model="$parent.notification.sendgridBccEmail" type="email" class="form-control">
|
<input id="sendgrid-bcc-email" v-model="$parent.notification.sendgridBccEmail" type="text" class="form-control">
|
||||||
<small class="form-text text-muted">{{ $t("Separate multiple email addresses with commas") }}</small>
|
<small class="form-text text-muted">{{ $t("Separate multiple email addresses with commas") }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
|
|
@ -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);
|
||||||
}
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue