mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-08-21 00:26:47 +08:00
Merge branch 'master' into fix-weblate-conflict2
# Conflicts: # src/lang/bg-BG.json # src/lang/cs-CZ.json # src/lang/de-CH.json # src/lang/de-DE.json # src/lang/fr-FR.json # src/lang/ga.json # src/lang/id-ID.json # src/lang/tr-TR.json # src/lang/uk-UA.json # src/lang/zh-CN.json
This commit is contained in:
@@ -118,6 +118,7 @@ export default {
|
||||
"clicksendsms": "ClickSend SMS",
|
||||
"CallMeBot": "CallMeBot (WhatsApp, Telegram Call, Facebook Messanger)",
|
||||
"discord": "Discord",
|
||||
"Elks": "46elks",
|
||||
"GoogleChat": "Google Chat (Google Workspace)",
|
||||
"gorush": "Gorush",
|
||||
"gotify": "Gotify",
|
||||
|
48
src/components/notifications/46elks.vue
Normal file
48
src/components/notifications/46elks.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="ElksUsername" class="form-label">{{ $t("Username") }}</label>
|
||||
<input id="ElksUsername" v-model="$parent.notification.elksUsername" type="text" class="form-control" required>
|
||||
<label for="ElksPassword" class="form-label">{{ $t("Password") }}</label>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
<HiddenInput id="ElksPassword" v-model="$parent.notification.elksAuthToken" :required="true" autocomplete="new-password"></HiddenInput>
|
||||
<i18n-t tag="p" keypath="Can be found on:">
|
||||
<a href="https://46elks.com/account" target="_blank">https://46elks.com/account</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="Elks-from-number" class="form-label">{{ $t("From") }}</label>
|
||||
<input id="Elks-from-number" v-model="$parent.notification.elksFromNumber" type="text" class="form-control" required>
|
||||
<div class="form-text">
|
||||
{{ $t("Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.") }}
|
||||
<i18n-t tag="p" keypath="More info on:">
|
||||
<a href="https://46elks.se/kb/text-sender-id" target="_blank">https://46elks.se/kb/text-sender-id</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="Elks-to-number" class="form-label">{{ $t("To Number") }}</label>
|
||||
<input id="Elks-to-number" v-model="$parent.notification.elksToNumber" type="text" class="form-control" required>
|
||||
<div class="form-text">
|
||||
{{ $t("The phone number of the recipient in E.164 format.") }}
|
||||
<i18n-t tag="p" keypath="More info on:">
|
||||
<a href="https://46elks.se/kb/e164" target="_blank">https://46elks.se/kb/e164</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
|
||||
<a href="https://46elks.com/docs/send-sms" target="_blank">https://46elks.com/docs/send-sms</a>
|
||||
</i18n-t>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
},
|
||||
};
|
||||
</script>
|
@@ -9,6 +9,12 @@
|
||||
<label for="slack-channel" class="form-label">{{ $t("Channel Name") }}</label>
|
||||
<input id="slack-channel-name" v-model="$parent.notification.slackchannel" type="text" class="form-control">
|
||||
|
||||
<label class="form-label">{{ $t("Message format") }}</label>
|
||||
<div class="form-check form-switch">
|
||||
<input id="slack-text-message" v-model="$parent.notification.slackrichmessage" type="checkbox" class="form-check-input">
|
||||
<label for="slack-text-message" class="form-label">{{ $t("Send rich messages") }}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-text">
|
||||
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
||||
<i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;">
|
||||
|
@@ -4,6 +4,53 @@
|
||||
<HiddenInput id="push-api-key" v-model="$parent.notification.pushAPIKey" :required="true" autocomplete="new-password"></HiddenInput>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="push-api-title" class="form-label">{{ $t("Title") }}</label>
|
||||
<input id="push-api-title" v-model="$parent.notification.pushTitle" type="text" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="push-api-channel" class="form-label">{{ $t("Notification Channel") }}</label>
|
||||
<input id="push-api-channel" v-model="$parent.notification.pushChannel" type="text" class="form-control" patttern="[A-Za-z0-9-]+">
|
||||
<div class="form-text">
|
||||
{{ $t("Alphanumerical string and hyphens only") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="push-api-sound" class="form-label">{{ $t("Sound") }}</label>
|
||||
<select id="push-api-sound" v-model="$parent.notification.pushSound" class="form-select">
|
||||
<option value="default">{{ $t("Default") }}</option>
|
||||
<option value="arcade">{{ $t("Arcade") }}</option>
|
||||
<option value="correct">{{ $t("Correct") }}</option>
|
||||
<option value="fail">{{ $t("Fail") }}</option>
|
||||
<option value="harp">{{ $t("Harp") }}</option>
|
||||
<option value="reveal">{{ $t("Reveal") }}</option>
|
||||
<option value="bubble">{{ $t("Bubble") }}</option>
|
||||
<option value="doorbell">{{ $t("Doorbell") }}</option>
|
||||
<option value="flute">{{ $t("Flute") }}</option>
|
||||
<option value="money">{{ $t("Money") }}</option>
|
||||
<option value="scifi">{{ $t("Scifi") }}</option>
|
||||
<option value="clear">{{ $t("Clear") }}</option>
|
||||
<option value="elevator">{{ $t("Elevator") }}</option>
|
||||
<option value="guitar">{{ $t("Guitar") }}</option>
|
||||
<option value="pop">{{ $t("Pop") }}</option>
|
||||
</select>
|
||||
<div class="form-text">
|
||||
{{ $t("Custom sound to override default notification sound") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input v-model="$parent.notification.pushTimeSensitive" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label">{{ $t("Time Sensitive (iOS Only)") }}</label>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
{{ $t("Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
|
||||
<a href="https://docs.push.techulus.com" target="_blank">https://docs.push.techulus.com</a>
|
||||
</i18n-t>
|
||||
@@ -16,5 +63,19 @@ export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
},
|
||||
mounted() {
|
||||
if (typeof this.$parent.notification.pushTitle === "undefined") {
|
||||
this.$parent.notification.pushTitle = "Uptime-Kuma";
|
||||
}
|
||||
if (typeof this.$parent.notification.pushChannel === "undefined") {
|
||||
this.$parent.notification.pushChannel = "uptime-kuma";
|
||||
}
|
||||
if (typeof this.$parent.notification.pushSound === "undefined") {
|
||||
this.$parent.notification.pushSound = "default";
|
||||
}
|
||||
if (typeof this.$parent.notification.pushTimeSensitive === "undefined") {
|
||||
this.$parent.notification.pushTimeSensitive = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@@ -9,6 +9,7 @@ import CallMeBot from "./CallMeBot.vue";
|
||||
import SMSC from "./SMSC.vue";
|
||||
import DingDing from "./DingDing.vue";
|
||||
import Discord from "./Discord.vue";
|
||||
import Elks from "./46elks.vue";
|
||||
import Feishu from "./Feishu.vue";
|
||||
import FreeMobile from "./FreeMobile.vue";
|
||||
import GoogleChat from "./GoogleChat.vue";
|
||||
@@ -82,6 +83,7 @@ const NotificationFormList = {
|
||||
"smsc": SMSC,
|
||||
"DingDing": DingDing,
|
||||
"discord": Discord,
|
||||
"Elks": Elks,
|
||||
"Feishu": Feishu,
|
||||
"FreeMobile": FreeMobile,
|
||||
"GoogleChat": GoogleChat,
|
||||
|
@@ -1050,6 +1050,5 @@
|
||||
"less than": "по-малко от",
|
||||
"greater than": "по-голямо от",
|
||||
"greater than or equal to": "по-голямо или равно на",
|
||||
"record": "запис",
|
||||
"shrinkDatabaseDescriptionSqlite": "Стартира {vacuum} за база данни тип SQLite. Функцията {auto_vacuum} вече е активиран, но това не дефрагментира базата данни, нито препакетира отделните страници на базата данни по начина, по който го прави командата {vacuum}."
|
||||
"record": "запис"
|
||||
}
|
||||
|
@@ -82,6 +82,7 @@
|
||||
"resendEveryXTimes": "Resend every {0} times",
|
||||
"resendDisabled": "Resend disabled",
|
||||
"retriesDescription": "Maximum retries before the service is marked as down and a notification is sent",
|
||||
"ignoredTLSError": "TLS/SSL errors have been ignored",
|
||||
"ignoreTLSError": "Ignore TLS/SSL errors for HTTPS websites",
|
||||
"ignoreTLSErrorGeneral": "Ignore TLS/SSL error for connection",
|
||||
"upsideDownModeDescription": "Flip the status upside down. If the service is reachable, it is DOWN.",
|
||||
@@ -96,6 +97,8 @@
|
||||
"pushOthers": "Others",
|
||||
"programmingLanguages": "Programming Languages",
|
||||
"Save": "Save",
|
||||
"Debug": "Debug",
|
||||
"Copy": "Copy",
|
||||
"Notifications": "Notifications",
|
||||
"Not available, please setup.": "Not available, please set up.",
|
||||
"Setup Notification": "Set Up Notification",
|
||||
@@ -248,6 +251,14 @@
|
||||
"PushUrl": "Push URL",
|
||||
"HeadersInvalidFormat": "The request headers are not valid JSON: ",
|
||||
"BodyInvalidFormat": "The request body is not valid JSON: ",
|
||||
"CopyToClipboardError": "Couldn't copy to clipbard: {error}",
|
||||
"CopyToClipboardSuccess": "Copied!",
|
||||
"CurlDebugInfo": "To debug the monitor, you can either paste this into your own machines terminal or into the machines terminal which uptime kuma is running on and see what you are requesting.{newiline}Please be aware of networking differences like {firewalls}, {dns_resolvers} or {docker_networks}.",
|
||||
"firewalls": "firewalls",
|
||||
"dns resolvers": "dns resolvers",
|
||||
"docker networks": "docker networks",
|
||||
"CurlDebugInfoOAuth2CCUnsupported": "Full oauth client credential flow is not supported in {curl}.{newline}Please get a bearer token and pass it via the {oauth2_bearer} option.",
|
||||
"CurlDebugInfoProxiesUnsupported": "Proxy support in the above {curl} command is currently not implemented.",
|
||||
"Monitor History": "Monitor History",
|
||||
"clearDataOlderThan": "Keep monitor history data for {0} days.",
|
||||
"PasswordsDoNotMatch": "Passwords do not match.",
|
||||
@@ -884,6 +895,8 @@
|
||||
"cacheBusterParamDescription": "Randomly generated parameter to skip caches.",
|
||||
"gamedigGuessPort": "Gamedig: Guess Port",
|
||||
"gamedigGuessPortDescription": "The port used by Valve Server Query Protocol may be different from the client port. Try this if the monitor cannot connect to your server.",
|
||||
"Message format": "Message format",
|
||||
"Send rich messages": "Send rich messages",
|
||||
"Bitrix24 Webhook URL": "Bitrix24 Webhook URL",
|
||||
"wayToGetBitrix24Webhook": "You can create a webhook by following the steps at {0}",
|
||||
"bitrix24SupportUserID": "Enter your user ID in Bitrix24. You can find out the ID from the link by going to the user's profile.",
|
||||
@@ -1014,5 +1027,29 @@
|
||||
"greater than": "greater than",
|
||||
"less than or equal to": "less than or equal to",
|
||||
"greater than or equal to": "greater than or equal to",
|
||||
"record": "record"
|
||||
"record": "record",
|
||||
"Notification Channel": "Notification Channel",
|
||||
"Sound": "Sound",
|
||||
"Alphanumerical string and hyphens only": "Alphanumerical string and hyphens only",
|
||||
"Arcade": "Arcade",
|
||||
"Correct": "Correct",
|
||||
"Fail":"Fail",
|
||||
"Harp":"Harp",
|
||||
"Reveal":"Reveal",
|
||||
"Bubble":"Bubble",
|
||||
"Doorbell":"Doorbell",
|
||||
"Flute":"Flute",
|
||||
"Money":"Money",
|
||||
"Scifi":"Scifi",
|
||||
"Clear":"Clear",
|
||||
"Elevator":"Elevator",
|
||||
"Guitar":"Guitar",
|
||||
"Pop":"Pop",
|
||||
"Custom sound to override default notification sound": "Custom sound to override default notification sound",
|
||||
"Time Sensitive (iOS Only)": "Time Sensitive (iOS Only)",
|
||||
"Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.": "Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.",
|
||||
"From":"From",
|
||||
"Can be found on:": "Can be found on: {0}",
|
||||
"The phone number of the recipient in E.164 format.": "The phone number of the recipient in E.164 format.",
|
||||
"Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.":"Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies."
|
||||
}
|
||||
|
@@ -141,19 +141,23 @@ export default {
|
||||
});
|
||||
|
||||
socket.on("monitorList", (data) => {
|
||||
// Add Helper function
|
||||
Object.entries(data).forEach(([ monitorID, monitor ]) => {
|
||||
monitor.getUrl = () => {
|
||||
try {
|
||||
return new URL(monitor.url);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
this.assignMonitorUrlParser(data);
|
||||
this.monitorList = data;
|
||||
});
|
||||
|
||||
socket.on("updateMonitorIntoList", (data) => {
|
||||
this.assignMonitorUrlParser(data);
|
||||
Object.entries(data).forEach(([ monitorID, updatedMonitor ]) => {
|
||||
this.monitorList[monitorID] = updatedMonitor;
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("deleteMonitorFromList", (monitorID) => {
|
||||
if (this.monitorList[monitorID]) {
|
||||
delete this.monitorList[monitorID];
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("monitorTypeList", (data) => {
|
||||
this.monitorTypeList = data;
|
||||
});
|
||||
@@ -289,6 +293,23 @@ export default {
|
||||
location.reload();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* parse all urls from list.
|
||||
* @param {object} data Monitor data to modify
|
||||
* @returns {object} list
|
||||
*/
|
||||
assignMonitorUrlParser(data) {
|
||||
Object.entries(data).forEach(([ monitorID, monitor ]) => {
|
||||
monitor.getUrl = () => {
|
||||
try {
|
||||
return new URL(monitor.url);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* The storage currently in use
|
||||
|
@@ -565,8 +565,8 @@
|
||||
|
||||
<h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
|
||||
|
||||
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' " class="my-3 form-check">
|
||||
<input id="expiry-notification" v-model="monitor.expiryNotification" class="form-check-input" type="checkbox">
|
||||
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' " class="my-3 form-check" :title="monitor.ignoreTls ? $t('ignoredTLSError') : ''">
|
||||
<input id="expiry-notification" v-model="monitor.expiryNotification" class="form-check-input" type="checkbox" :disabled="monitor.ignoreTls">
|
||||
<label class="form-check-label" for="expiry-notification">
|
||||
{{ $t("Certificate Expiry Notification") }}
|
||||
</label>
|
||||
@@ -982,13 +982,23 @@
|
||||
<div class="fixed-bottom-bar p-3">
|
||||
<button
|
||||
id="monitor-submit-btn"
|
||||
class="btn btn-primary"
|
||||
class="btn btn-primary me-2"
|
||||
type="submit"
|
||||
:disabled="processing"
|
||||
data-testid="save-button"
|
||||
>
|
||||
{{ $t("Save") }}
|
||||
</button>
|
||||
<button
|
||||
v-if="monitor.type === 'http'"
|
||||
id="monitor-debug-btn"
|
||||
class="btn btn-outline-primary"
|
||||
type="button"
|
||||
:disabled="processing"
|
||||
@click.stop="modal.show()"
|
||||
>
|
||||
{{ $t("Debug") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1000,9 +1010,58 @@
|
||||
<RemoteBrowserDialog ref="remoteBrowserDialog" />
|
||||
</div>
|
||||
</transition>
|
||||
<div ref="modal" class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<textarea id="curl-debug" v-model="curlCommand" class="form-control mb-3" readonly wrap="off"></textarea>
|
||||
<button id="debug-copy-btn" class="btn btn-outline-primary position-absolute top-0 end-0 mt-3 me-3 border-0" type="button" @click.stop="copyToClipboard">
|
||||
<font-awesome-icon icon="copy" />
|
||||
</button>
|
||||
<i18n-t keypath="CurlDebugInfo" tag="p" class="form-text">
|
||||
<template #newiline>
|
||||
<br>
|
||||
</template>
|
||||
<template #firewalls>
|
||||
<a href="https://xkcd.com/2259/" target="_blank">{{ $t('firewalls') }}</a>
|
||||
</template>
|
||||
<template #dns_resolvers>
|
||||
<a href="https://www.reddit.com/r/sysadmin/comments/rxho93/thank_you_for_the_running_its_always_dns_joke_its/" target="_blank">{{ $t('dns resolvers') }}</a>
|
||||
</template>
|
||||
<template #docker_networks>
|
||||
<a href="https://youtu.be/bKFMS5C4CG0" target="_blank">{{ $t('docker networks') }}</a>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<div v-if="monitor.authMethod === 'oauth2-cc'" class="alert alert-warning d-flex align-items-center gap-2" role="alert">
|
||||
<div role="img" aria-label="Warning:">⚠️</div>
|
||||
<i18n-t keypath="CurlDebugInfoOAuth2CCUnsupported" tag="div">
|
||||
<template #curl>
|
||||
<code>curl</code>
|
||||
</template>
|
||||
<template #newline>
|
||||
<br>
|
||||
</template>
|
||||
<template #oauth2_bearer>
|
||||
<code>--oauth2-bearer TOKEN</code>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</div>
|
||||
<div v-if="monitor.proxyId" class="alert alert-warning d-flex align-items-center gap-2" role="alert">
|
||||
<div role="img" aria-label="Warning:">⚠️</div>
|
||||
<i18n-t keypath="CurlDebugInfoProxiesUnsupported" tag="div">
|
||||
<template #curl>
|
||||
<code>curl</code>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Modal } from "bootstrap";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import { useToast } from "vue-toastification";
|
||||
import ActionSelect from "../components/ActionSelect.vue";
|
||||
@@ -1017,8 +1076,10 @@ import { genSecret, isDev, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, sleep } fro
|
||||
import { hostNameRegexPattern } from "../util-frontend";
|
||||
import HiddenInput from "../components/HiddenInput.vue";
|
||||
import EditMonitorConditions from "../components/EditMonitorConditions.vue";
|
||||
import { version } from "../../package.json";
|
||||
const userAgent = `'Uptime-Kuma/${version}'`;
|
||||
|
||||
const toast = useToast;
|
||||
const toast = useToast();
|
||||
|
||||
const pushTokenLength = 32;
|
||||
|
||||
@@ -1081,6 +1142,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
modal: null,
|
||||
minInterval: MIN_INTERVAL_SECOND,
|
||||
maxInterval: MAX_INTERVAL_SECOND,
|
||||
processing: false,
|
||||
@@ -1108,6 +1170,53 @@ export default {
|
||||
|
||||
computed: {
|
||||
|
||||
curlCommand() {
|
||||
const command = [ "curl", "--verbose", "--head", "--request", this.monitor.method, "\\\n", "--user-agent", userAgent, "\\\n" ];
|
||||
if (this.monitor.ignoreTls) {
|
||||
command.push("--insecure", "\\\n");
|
||||
}
|
||||
if (this.monitor.headers) {
|
||||
try {
|
||||
// trying to parse the supplied data as json to trim whitespace
|
||||
for (const [ key, value ] of Object.entries(JSON.parse(this.monitor.headers))) {
|
||||
command.push("--header", `'${key}: ${value}'`, "\\\n");
|
||||
}
|
||||
} catch (e) {
|
||||
command.push("--header", `'${this.monitor.headers}'`, "\\\n");
|
||||
}
|
||||
}
|
||||
if (this.monitor.authMethod === "basic") {
|
||||
command.push("--user", `${this.monitor.basic_auth_user}:${this.monitor.basic_auth_pass}`, "--basic", "\\\n");
|
||||
} else if (this.monitor.authmethod === "mtls") {
|
||||
command.push("--cacert", `'${this.monitor.tlsCa}'`, "\\\n", "--key", `'${this.monitor.tlsKey}'`, "\\\n", "--cert", `'${this.monitor.tlsCert}'`, "\\\n");
|
||||
} else if (this.monitor.authMethod === "ntlm") {
|
||||
command.push("--user", `'${this.monitor.authDomain ? `${this.monitor.authDomain}/` : ""}${this.monitor.basic_auth_user}:${this.monitor.basic_auth_pass}'`, "--ntlm", "\\\n");
|
||||
}
|
||||
if (this.monitor.body && this.monitor.httpBodyEncoding === "json") {
|
||||
let json = "";
|
||||
try {
|
||||
// trying to parse the supplied data as json to trim whitespace
|
||||
json = JSON.stringify(JSON.parse(this.monitor.body));
|
||||
} catch (e) {
|
||||
json = this.monitor.body;
|
||||
}
|
||||
command.push("--header", "'Content-Type: application/json'", "\\\n", "--data", `'${json}'`, "\\\n");
|
||||
} else if (this.monitor.body && this.monitor.httpBodyEncoding === "xml") {
|
||||
command.push("--headers", "'Content-Type: application/xml'", "\\\n", "--data", `'${this.monitor.body}'`, "\\\n");
|
||||
}
|
||||
if (this.monitor.maxredirects) {
|
||||
command.push("--location", "--max-redirs", this.monitor.maxredirects, "\\\n");
|
||||
}
|
||||
if (this.monitor.timeout) {
|
||||
command.push("--max-time", this.monitor.timeout, "\\\n");
|
||||
}
|
||||
if (this.monitor.maxretries) {
|
||||
command.push("--retry", this.monitor.maxretries, "\\\n");
|
||||
}
|
||||
command.push("--url", this.monitor.url);
|
||||
return command.join(" ");
|
||||
},
|
||||
|
||||
ipRegex() {
|
||||
|
||||
// Allow to test with simple dns server with port (127.0.0.1:5300)
|
||||
@@ -1456,8 +1565,15 @@ message HealthCheckResponse {
|
||||
}
|
||||
this.monitor.game = newGameObject.keys[0];
|
||||
},
|
||||
|
||||
"monitor.ignoreTls"(newVal) {
|
||||
if (newVal) {
|
||||
this.monitor.expiryNotification = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.modal = new Modal(this.$refs.modal);
|
||||
this.init();
|
||||
|
||||
let acceptedStatusCodeOptions = [
|
||||
@@ -1498,6 +1614,14 @@ message HealthCheckResponse {
|
||||
this.kafkaSaslMechanismOptions = kafkaSaslMechanismOptions;
|
||||
},
|
||||
methods: {
|
||||
async copyToClipboard() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(this.curlCommand);
|
||||
toast.success(this.$t("CopyToClipboardSuccess"));
|
||||
} catch (err) {
|
||||
toast.error(this.$t("CopyToClipboardError", { error: err.message }));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Initialize the edit monitor form
|
||||
* @returns {void}
|
||||
@@ -1689,7 +1813,6 @@ message HealthCheckResponse {
|
||||
await this.startParentGroupMonitor();
|
||||
}
|
||||
this.processing = false;
|
||||
this.$root.getMonitorList();
|
||||
this.$router.push("/dashboard/" + res.monitorID);
|
||||
} else {
|
||||
this.processing = false;
|
||||
@@ -1786,4 +1909,9 @@ message HealthCheckResponse {
|
||||
textarea {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
#curl-debug {
|
||||
font-family: monospace;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
@@ -68,15 +68,17 @@ const routes = [
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/add",
|
||||
component: EditMonitor,
|
||||
children: [
|
||||
{
|
||||
path: "/clone/:id",
|
||||
component: EditMonitor,
|
||||
},
|
||||
{
|
||||
path: "/add",
|
||||
component: EditMonitor,
|
||||
},
|
||||
],
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "/list",
|
||||
|
73
src/util.js
73
src/util.js
@@ -8,34 +8,17 @@
|
||||
// Backend uses the compiled file util.js
|
||||
// Frontend uses util.ts
|
||||
*/
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var _a;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = 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.isNode = exports.isDev = void 0;
|
||||
exports.evaluateJsonQuery = exports.intHash = 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.ucfirst = void 0;
|
||||
exports.evaluateJsonQuery = exports.intHash = 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 = void 0;
|
||||
exports.intHash = 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 = void 0;
|
||||
const dayjs_1 = __importDefault(require("dayjs"));
|
||||
const jsonata = __importStar(require("jsonata"));
|
||||
const dayjs = require("dayjs");
|
||||
const jsonata = require("jsonata");
|
||||
exports.isDev = process.env.NODE_ENV === "development";
|
||||
exports.isNode = typeof process !== "undefined" && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
||||
exports.appName = "Uptime Kuma";
|
||||
@@ -83,6 +66,7 @@ exports.CONSOLE_STYLE_BgMagenta = "\x1b[45m";
|
||||
exports.CONSOLE_STYLE_BgCyan = "\x1b[46m";
|
||||
exports.CONSOLE_STYLE_BgWhite = "\x1b[47m";
|
||||
exports.CONSOLE_STYLE_BgGray = "\x1b[100m";
|
||||
|
||||
const consoleModuleColors = [
|
||||
exports.CONSOLE_STYLE_FgCyan,
|
||||
exports.CONSOLE_STYLE_FgGreen,
|
||||
@@ -141,6 +125,10 @@ function ucfirst(str) {
|
||||
return firstLetter.toUpperCase() + str.substr(1);
|
||||
}
|
||||
exports.ucfirst = ucfirst;
|
||||
function debug(msg) {
|
||||
exports.log.log("", msg, "debug");
|
||||
}
|
||||
exports.debug = debug;
|
||||
class Logger {
|
||||
constructor() {
|
||||
this.hideLog = {
|
||||
@@ -168,6 +156,8 @@ class Logger {
|
||||
if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
module = module.toUpperCase();
|
||||
level = level.toUpperCase();
|
||||
let now;
|
||||
if (dayjs_1.default.tz) {
|
||||
now = dayjs_1.default.tz(new Date()).format();
|
||||
@@ -177,20 +167,10 @@ class Logger {
|
||||
}
|
||||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
let timePart = now;
|
||||
let modulePart = module;
|
||||
let levelPart = level;
|
||||
let msgPart = msg;
|
||||
if (process.env.UPTIME_KUMA_LOG_FORMAT === "json") {
|
||||
console.log(JSON.stringify({
|
||||
time: timePart,
|
||||
module: modulePart,
|
||||
level: levelPart,
|
||||
msg: typeof msg === "string" ? msg : JSON.stringify(msg),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
module = module.toUpperCase();
|
||||
let timePart;
|
||||
let modulePart;
|
||||
let levelPart;
|
||||
let msgPart;
|
||||
if (exports.isNode) {
|
||||
switch (level) {
|
||||
case "DEBUG":
|
||||
@@ -207,17 +187,28 @@ class Logger {
|
||||
if (typeof msg === "string") {
|
||||
msgPart = exports.CONSOLE_STYLE_FgRed + msg + exports.CONSOLE_STYLE_Reset;
|
||||
}
|
||||
else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
case "DEBUG":
|
||||
if (typeof msg === "string") {
|
||||
msgPart = exports.CONSOLE_STYLE_FgGray + msg + exports.CONSOLE_STYLE_Reset;
|
||||
}
|
||||
else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msgPart = msg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
timePart = now;
|
||||
modulePart = `[${module}]`;
|
||||
levelPart = `${level}:`;
|
||||
msgPart = msg;
|
||||
}
|
||||
switch (level) {
|
||||
case "ERROR":
|
||||
@@ -240,23 +231,23 @@ class Logger {
|
||||
}
|
||||
}
|
||||
info(module, msg) {
|
||||
this.log(module, msg, "INFO");
|
||||
this.log(module, msg, "info");
|
||||
}
|
||||
warn(module, msg) {
|
||||
this.log(module, msg, "WARN");
|
||||
this.log(module, msg, "warn");
|
||||
}
|
||||
error(module, msg) {
|
||||
this.log(module, msg, "ERROR");
|
||||
this.log(module, msg, "error");
|
||||
}
|
||||
debug(module, msg) {
|
||||
this.log(module, msg, "DEBUG");
|
||||
this.log(module, msg, "debug");
|
||||
}
|
||||
exception(module, exception, msg) {
|
||||
let finalMessage = exception;
|
||||
if (msg) {
|
||||
finalMessage = `${msg}: ${exception}`;
|
||||
}
|
||||
this.log(module, finalMessage, "ERROR");
|
||||
this.log(module, finalMessage, "error");
|
||||
}
|
||||
}
|
||||
exports.log = new Logger();
|
||||
@@ -467,4 +458,4 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue
|
||||
throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`);
|
||||
}
|
||||
}
|
||||
exports.evaluateJsonQuery = evaluateJsonQuery;
|
||||
exports.evaluateJsonQuery = evaluateJsonQuery;
|
73
src/util.ts
73
src/util.ts
@@ -120,7 +120,11 @@ export const badgeConstants = {
|
||||
defaultCertExpireDownDays: "7"
|
||||
};
|
||||
|
||||
/** Flip the status of s */
|
||||
/**
|
||||
* Flip the status of s between UP and DOWN if this is possible
|
||||
* @param s {number} status
|
||||
* @returns {number} flipped status
|
||||
*/
|
||||
export function flipStatus(s: number) {
|
||||
if (s === UP) {
|
||||
return DOWN;
|
||||
@@ -156,6 +160,15 @@ export function ucfirst(str: string) {
|
||||
return firstLetter.toUpperCase() + str.substr(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use log.debug (https://github.com/louislam/uptime-kuma/pull/910)
|
||||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
export function debug(msg: unknown) {
|
||||
log.log("", msg, "debug");
|
||||
}
|
||||
|
||||
class Logger {
|
||||
|
||||
/**
|
||||
@@ -197,13 +210,12 @@ class Logger {
|
||||
|
||||
/**
|
||||
* Write a message to the log
|
||||
* @private
|
||||
* @param module The module the log comes from
|
||||
* @param msg Message to write
|
||||
* @param level {"INFO"|"WARN"|"ERROR"|"DEBUG"} Log level
|
||||
* @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
|
||||
* @returns {void}
|
||||
*/
|
||||
log(module: string, msg: unknown, level: "INFO"|"WARN"|"ERROR"|"DEBUG"): void {
|
||||
log(module: string, msg: any, level: string) {
|
||||
if (level === "DEBUG" && !isDev) {
|
||||
return;
|
||||
}
|
||||
@@ -212,6 +224,9 @@ class Logger {
|
||||
return;
|
||||
}
|
||||
|
||||
module = module.toUpperCase();
|
||||
level = level.toUpperCase();
|
||||
|
||||
let now;
|
||||
if (dayjs.tz) {
|
||||
now = dayjs.tz(new Date()).format();
|
||||
@@ -222,23 +237,10 @@ class Logger {
|
||||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
|
||||
let timePart: string = now;
|
||||
let modulePart: string = module;
|
||||
let levelPart: string = level;
|
||||
let msgPart: unknown = msg;
|
||||
|
||||
if (process.env.UPTIME_KUMA_LOG_FORMAT === "json") {
|
||||
console.log(JSON.stringify({
|
||||
time: timePart,
|
||||
module: modulePart,
|
||||
level: levelPart,
|
||||
msg: typeof msg === "string" ? msg : JSON.stringify(msg),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
// Console rendering:
|
||||
module = module.toUpperCase();
|
||||
let timePart: string;
|
||||
let modulePart: string;
|
||||
let levelPart: string;
|
||||
let msgPart: string;
|
||||
|
||||
if (isNode) {
|
||||
// Add console colors
|
||||
@@ -259,18 +261,27 @@ class Logger {
|
||||
case "ERROR":
|
||||
if (typeof msg === "string") {
|
||||
msgPart = CONSOLE_STYLE_FgRed + msg + CONSOLE_STYLE_Reset;
|
||||
} else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
case "DEBUG":
|
||||
if (typeof msg === "string") {
|
||||
msgPart = CONSOLE_STYLE_FgGray + msg + CONSOLE_STYLE_Reset;
|
||||
} else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msgPart = msg;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// No console colors
|
||||
timePart = now;
|
||||
modulePart = `[${module}]`;
|
||||
levelPart = `${level}:`;
|
||||
msgPart = msg;
|
||||
}
|
||||
|
||||
// Write to console
|
||||
@@ -301,8 +312,8 @@ class Logger {
|
||||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
info(module: string, msg: string): void {
|
||||
this.log(module, msg, "INFO");
|
||||
info(module: string, msg: unknown) {
|
||||
this.log(module, msg, "info");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,8 +322,8 @@ class Logger {
|
||||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
warn(module: string, msg: string): void {
|
||||
this.log(module, msg, "WARN");
|
||||
warn(module: string, msg: unknown) {
|
||||
this.log(module, msg, "warn");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,8 +332,8 @@ class Logger {
|
||||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
error(module: string, msg: string): void {
|
||||
this.log(module, msg, "ERROR");
|
||||
error(module: string, msg: unknown) {
|
||||
this.log(module, msg, "error");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,8 +342,8 @@ class Logger {
|
||||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
debug(module: string, msg: string): void {
|
||||
this.log(module, msg, "DEBUG");
|
||||
debug(module: string, msg: unknown) {
|
||||
this.log(module, msg, "debug");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,7 +360,7 @@ class Logger {
|
||||
finalMessage = `${msg}: ${exception}`;
|
||||
}
|
||||
|
||||
this.log(module, finalMessage, "ERROR");
|
||||
this.log(module, finalMessage, "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +404,7 @@ export class TimeLogger {
|
||||
* @param name Name of monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
print(name: string): void {
|
||||
print(name: string) {
|
||||
if (isDev && process.env.TIMELOGGER === "1") {
|
||||
console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms");
|
||||
}
|
||||
|
Reference in New Issue
Block a user