mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-27 17:39:20 +08:00
Merge branch 'master' into 1.23.X-merge-to-2.X.X
# Conflicts: # docker/debian-base.dockerfile # package-lock.json # server/database.js # server/model/monitor.js # server/uptime-kuma-server.js # server/util-server.js
This commit is contained in:
@@ -584,6 +584,20 @@ h5.settings-subheading::after {
|
||||
border-bottom: 1px solid $dark-border-color;
|
||||
}
|
||||
|
||||
/* required class */
|
||||
.code-editor, .css-editor {
|
||||
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
|
||||
|
||||
border-radius: 1rem;
|
||||
padding: 10px 5px;
|
||||
border: 1px solid #ced4da;
|
||||
|
||||
.dark & {
|
||||
background: $dark-bg2;
|
||||
border: 1px solid $dark-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$shadow-box-padding: 20px;
|
||||
|
||||
@@ -609,6 +623,18 @@ $shadow-box-padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 770px) {
|
||||
.toast-container {
|
||||
margin-bottom: 100px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
.toast-container {
|
||||
margin-bottom: 126px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Localization
|
||||
|
||||
@import "localization.scss";
|
||||
|
@@ -92,11 +92,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Modal } from "bootstrap";
|
||||
import { useToast } from "vue-toastification";
|
||||
import dayjs from "dayjs";
|
||||
import Datepicker from "@vuepic/vue-datepicker";
|
||||
import CopyableInput from "./CopyableInput.vue";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -126,6 +124,7 @@ export default {
|
||||
methods: {
|
||||
/**
|
||||
* Show modal
|
||||
* @returns {void}
|
||||
*/
|
||||
show() {
|
||||
this.id = null;
|
||||
@@ -138,7 +137,10 @@ export default {
|
||||
this.keyaddmodal.show();
|
||||
},
|
||||
|
||||
/** Submit data to server */
|
||||
/**
|
||||
* Submit data to server
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async submit() {
|
||||
this.processing = true;
|
||||
|
||||
@@ -154,12 +156,15 @@ export default {
|
||||
this.keymodal.show();
|
||||
this.clearForm();
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Clear Form inputs */
|
||||
/**
|
||||
* Clear Form inputs
|
||||
* @returns {void}
|
||||
*/
|
||||
clearForm() {
|
||||
this.key = {
|
||||
name: "",
|
||||
|
@@ -279,8 +279,9 @@ export default {
|
||||
methods: {
|
||||
/**
|
||||
* Setting monitor
|
||||
* @param {number} monitorId ID of monitor
|
||||
* @param {string} monitorName Name of monitor
|
||||
* @param {number} monitorId ID of monitor
|
||||
* @param {string} monitorName Name of monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
show(monitorId, monitorName) {
|
||||
this.monitor = {
|
||||
|
@@ -65,9 +65,9 @@ export default {
|
||||
methods: {
|
||||
/**
|
||||
* Format the subject of the certificate
|
||||
* @param {Object} subject Object representing the certificates
|
||||
* @param {object} subject Object representing the certificates
|
||||
* subject
|
||||
* @returns {string}
|
||||
* @returns {string} Certificate subject
|
||||
*/
|
||||
formatSubject(subject) {
|
||||
if (subject.O && subject.CN && subject.C) {
|
||||
|
@@ -58,18 +58,23 @@ export default {
|
||||
this.modal = new Modal(this.$refs.modal);
|
||||
},
|
||||
methods: {
|
||||
/** Show the confirm dialog */
|
||||
/**
|
||||
* Show the confirm dialog
|
||||
* @returns {void}
|
||||
*/
|
||||
show() {
|
||||
this.modal.show();
|
||||
},
|
||||
/**
|
||||
* @emits string "yes" Notify the parent when Yes is pressed
|
||||
* @fires string "yes" Notify the parent when Yes is pressed
|
||||
* @returns {void}
|
||||
*/
|
||||
yes() {
|
||||
this.$emit("yes");
|
||||
},
|
||||
/**
|
||||
* @emits string "no" Notify the parent when No is pressed
|
||||
* @fires string "no" Notify the parent when No is pressed
|
||||
* @returns {void}
|
||||
*/
|
||||
no() {
|
||||
this.$emit("no");
|
||||
|
@@ -90,19 +90,25 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
|
||||
/** Show the input */
|
||||
/**
|
||||
* Show the input
|
||||
* @returns {void}
|
||||
*/
|
||||
showInput() {
|
||||
this.visibility = "text";
|
||||
},
|
||||
|
||||
/** Hide the input */
|
||||
/**
|
||||
* Hide the input
|
||||
* @returns {void}
|
||||
*/
|
||||
hideInput() {
|
||||
this.visibility = "password";
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the provided text to the users clipboard
|
||||
* @param {string} textToCopy
|
||||
* @param {string} textToCopy Text to copy to clipboard
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
copyToClipboard(textToCopy) {
|
||||
|
@@ -43,10 +43,17 @@ export default {
|
||||
this.modal = new Modal(this.$refs.modal);
|
||||
},
|
||||
methods: {
|
||||
/** Show the confirm dialog */
|
||||
/**
|
||||
* Show the confirm dialog
|
||||
* @returns {void}
|
||||
*/
|
||||
show() {
|
||||
this.modal.show();
|
||||
},
|
||||
/**
|
||||
* Dialog confirmed
|
||||
* @returns {void}
|
||||
*/
|
||||
confirm() {
|
||||
this.$emit("added", this.groupName);
|
||||
this.modal.hide();
|
||||
|
@@ -62,8 +62,6 @@
|
||||
<script lang="ts">
|
||||
import { Modal } from "bootstrap";
|
||||
import Confirm from "./Confirm.vue";
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -91,7 +89,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
|
||||
/** Confirm deletion of docker host */
|
||||
/**
|
||||
* Confirm deletion of docker host
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteConfirm() {
|
||||
this.modal.hide();
|
||||
this.$refs.confirmDelete.show();
|
||||
@@ -99,7 +100,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Show specified docker host
|
||||
* @param {number} dockerHostID
|
||||
* @param {number} dockerHostID ID of host to show
|
||||
* @returns {void}
|
||||
*/
|
||||
show(dockerHostID) {
|
||||
if (dockerHostID) {
|
||||
@@ -116,7 +118,7 @@ export default {
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
toast.error("Docker Host not found!");
|
||||
this.$root.toastError("Docker Host not found!");
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -131,7 +133,10 @@ export default {
|
||||
this.modal.show();
|
||||
},
|
||||
|
||||
/** Add docker host */
|
||||
/**
|
||||
* Add docker host
|
||||
* @returns {void}
|
||||
*/
|
||||
submit() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("addDockerHost", this.dockerHost, this.id, (res) => {
|
||||
@@ -150,7 +155,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Test the docker host */
|
||||
/**
|
||||
* Test the docker host
|
||||
* @returns {void}
|
||||
*/
|
||||
test() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("testDockerHost", this.dockerHost, (res) => {
|
||||
@@ -159,7 +167,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Delete this docker host */
|
||||
/**
|
||||
* Delete this docker host
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteDockerHost() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("deleteDockerHost", this.id, (res) => {
|
||||
|
@@ -56,6 +56,7 @@ export default {
|
||||
|
||||
/**
|
||||
* If heartbeatList is null, get it from $root.heartbeatList
|
||||
* @returns {object} Heartbeat list
|
||||
*/
|
||||
beatList() {
|
||||
if (this.heartbeatList === null) {
|
||||
@@ -67,8 +68,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Calculates the amount of beats of padding needed to fill the length of shortBeatList.
|
||||
*
|
||||
* @return {number} The amount of beats of padding needed to fill the length of shortBeatList.
|
||||
* @returns {number} The amount of beats of padding needed to fill the length of shortBeatList.
|
||||
*/
|
||||
numPadding() {
|
||||
if (!this.beatList) {
|
||||
@@ -148,7 +148,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Returns the style object for positioning the time element.
|
||||
* @return {Object} The style object containing the CSS properties for positioning the time element.
|
||||
* @returns {object} The style object containing the CSS properties for positioning the time element.
|
||||
*/
|
||||
timeStyle() {
|
||||
return {
|
||||
@@ -158,8 +158,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Calculates the time elapsed since the first valid beat.
|
||||
*
|
||||
* @return {string} The time elapsed in minutes or hours.
|
||||
* @returns {string} The time elapsed in minutes or hours.
|
||||
*/
|
||||
timeSinceFirstBeat() {
|
||||
const firstValidBeat = this.shortBeatList.at(this.numPadding);
|
||||
@@ -173,8 +172,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Calculates the elapsed time since the last valid beat was registered.
|
||||
*
|
||||
* @return {string} The elapsed time in a minutes, hours or "now".
|
||||
* @returns {string} The elapsed time in a minutes, hours or "now".
|
||||
*/
|
||||
timeSinceLastBeat() {
|
||||
const lastValidBeat = this.shortBeatList.at(-1);
|
||||
@@ -241,7 +239,10 @@ export default {
|
||||
this.resize();
|
||||
},
|
||||
methods: {
|
||||
/** Resize the heartbeat bar */
|
||||
/**
|
||||
* Resize the heartbeat bar
|
||||
* @returns {void}
|
||||
*/
|
||||
resize() {
|
||||
if (this.$refs.wrap) {
|
||||
this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatMargin * 2));
|
||||
@@ -251,8 +252,8 @@ export default {
|
||||
/**
|
||||
* Get the title of the beat.
|
||||
* Used as the hover tooltip on the heartbeat bar.
|
||||
* @param {Object} beat Beat to get title from
|
||||
* @returns {string}
|
||||
* @param {object} beat Beat to get title from
|
||||
* @returns {string} Beat title
|
||||
*/
|
||||
getBeatTitle(beat) {
|
||||
return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : "");
|
||||
|
@@ -74,11 +74,17 @@ export default {
|
||||
|
||||
},
|
||||
methods: {
|
||||
/** Show users input in plain text */
|
||||
/**
|
||||
* Show users input in plain text
|
||||
* @returns {void}
|
||||
*/
|
||||
showInput() {
|
||||
this.visibility = "text";
|
||||
},
|
||||
/** Censor users input */
|
||||
/**
|
||||
* Censor users input
|
||||
* @returns {void}
|
||||
*/
|
||||
hideInput() {
|
||||
this.visibility = "password";
|
||||
},
|
||||
|
@@ -35,7 +35,7 @@
|
||||
</button>
|
||||
|
||||
<div v-if="res && !res.ok" class="alert alert-danger mt-3" role="alert">
|
||||
{{ res.msg }}
|
||||
{{ $t(res.msg) }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -64,7 +64,10 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Submit the user details and attempt to log in */
|
||||
/**
|
||||
* Submit the user details and attempt to log in
|
||||
* @returns {void}
|
||||
*/
|
||||
submit() {
|
||||
this.processing = true;
|
||||
|
||||
|
@@ -103,6 +103,7 @@ export default {
|
||||
* Improve the sticky appearance of the list by increasing its
|
||||
* height as user scrolls down.
|
||||
* Not used on mobile.
|
||||
* @returns {object} Style for monitor list
|
||||
*/
|
||||
boxStyle() {
|
||||
if (window.innerWidth > 550) {
|
||||
@@ -119,8 +120,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Returns a sorted list of monitors based on the applied filters and search text.
|
||||
*
|
||||
* @return {Array} The sorted list of monitors.
|
||||
* @returns {Array} The sorted list of monitors.
|
||||
*/
|
||||
sortedMonitorList() {
|
||||
let result = Object.values(this.$root.monitorList);
|
||||
@@ -221,8 +221,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Determines if any filters are active.
|
||||
*
|
||||
* @return {boolean} True if any filter is active, false otherwise.
|
||||
* @returns {boolean} True if any filter is active, false otherwise.
|
||||
*/
|
||||
filtersActive() {
|
||||
return this.filterState.status != null || this.filterState.active != null || this.filterState.tags != null || this.searchText !== "";
|
||||
@@ -267,7 +266,10 @@ export default {
|
||||
window.removeEventListener("scroll", this.onScroll);
|
||||
},
|
||||
methods: {
|
||||
/** Handle user scroll */
|
||||
/**
|
||||
* Handle user scroll
|
||||
* @returns {void}
|
||||
*/
|
||||
onScroll() {
|
||||
if (window.top.scrollY <= 133) {
|
||||
this.windowTop = window.top.scrollY;
|
||||
@@ -283,13 +285,17 @@ export default {
|
||||
monitorURL(id) {
|
||||
return getMonitorRelativeURL(id);
|
||||
},
|
||||
/** Clear the search bar */
|
||||
/**
|
||||
* Clear the search bar
|
||||
* @returns {void}
|
||||
*/
|
||||
clearSearchText() {
|
||||
this.searchText = "";
|
||||
},
|
||||
/**
|
||||
* Update the MonitorList Filter
|
||||
* @param {object} newFilter Object with new filter
|
||||
* @returns {void}
|
||||
*/
|
||||
updateFilter(newFilter) {
|
||||
this.filterState = newFilter;
|
||||
@@ -297,6 +303,7 @@ export default {
|
||||
/**
|
||||
* Deselect a monitor
|
||||
* @param {number} id ID of monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
deselect(id) {
|
||||
delete this.selectedMonitors[id];
|
||||
@@ -304,6 +311,7 @@ export default {
|
||||
/**
|
||||
* Select a monitor
|
||||
* @param {number} id ID of monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
select(id) {
|
||||
this.selectedMonitors[id] = true;
|
||||
@@ -311,33 +319,45 @@ export default {
|
||||
/**
|
||||
* Determine if monitor is selected
|
||||
* @param {number} id ID of monitor
|
||||
* @returns {bool}
|
||||
* @returns {bool} Is the monitor selected?
|
||||
*/
|
||||
isSelected(id) {
|
||||
return id in this.selectedMonitors;
|
||||
},
|
||||
/** Disable select mode and reset selection */
|
||||
/**
|
||||
* Disable select mode and reset selection
|
||||
* @returns {void}
|
||||
*/
|
||||
cancelSelectMode() {
|
||||
this.selectMode = false;
|
||||
this.selectedMonitors = {};
|
||||
},
|
||||
/** Show dialog to confirm pause */
|
||||
/**
|
||||
* Show dialog to confirm pause
|
||||
* @returns {void}
|
||||
*/
|
||||
pauseDialog() {
|
||||
this.$refs.confirmPause.show();
|
||||
},
|
||||
/** Pause each selected monitor */
|
||||
/**
|
||||
* Pause each selected monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
pauseSelected() {
|
||||
Object.keys(this.selectedMonitors)
|
||||
.filter(id => this.$root.monitorList[id].active)
|
||||
.forEach(id => this.$root.getSocket().emit("pauseMonitor", id));
|
||||
.forEach(id => this.$root.getSocket().emit("pauseMonitor", id, () => {}));
|
||||
|
||||
this.cancelSelectMode();
|
||||
},
|
||||
/** Resume each selected monitor */
|
||||
/**
|
||||
* Resume each selected monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
resumeSelected() {
|
||||
Object.keys(this.selectedMonitors)
|
||||
.filter(id => !this.$root.monitorList[id].active)
|
||||
.forEach(id => this.$root.getSocket().emit("resumeMonitor", id));
|
||||
.forEach(id => this.$root.getSocket().emit("resumeMonitor", id, () => {}));
|
||||
|
||||
this.cancelSelectMode();
|
||||
},
|
||||
|
@@ -141,6 +141,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="tagsList.length === 0">
|
||||
<div class="dropdown-item disabled px-3">
|
||||
{{ $t('No tags found.') }}
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
</MonitorListFilterDropdown>
|
||||
</div>
|
||||
|
@@ -189,7 +189,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Changes the collapsed value of the current monitor and saves it to local storage
|
||||
* Changes the collapsed value of the current monitor and saves
|
||||
* it to local storage
|
||||
* @returns {void}
|
||||
*/
|
||||
changeCollapsed() {
|
||||
this.isCollapsed = !this.isCollapsed;
|
||||
@@ -214,6 +216,7 @@ export default {
|
||||
},
|
||||
/**
|
||||
* Toggle selection of monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
toggleSelection() {
|
||||
if (this.isSelected(this.monitor.id)) {
|
||||
|
@@ -67,8 +67,9 @@ export default {
|
||||
methods: {
|
||||
/**
|
||||
* Setting monitor
|
||||
* @param {Object} group Data of monitor
|
||||
* @param {Object} monitor Data of monitor
|
||||
* @param {object} group Data of monitor
|
||||
* @param {object} monitor Data of monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
show(group, monitor) {
|
||||
this.monitor = {
|
||||
@@ -86,6 +87,7 @@ export default {
|
||||
* Toggle the value of sendUrl
|
||||
* @param {number} groupIndex Index of group monitor is member of
|
||||
* @param {number} index Index of monitor within group
|
||||
* @returns {void}
|
||||
*/
|
||||
toggleLink(groupIndex, index) {
|
||||
this.$root.publicGroupList[groupIndex].monitorList[index].sendUrl = !this.$root.publicGroupList[groupIndex].monitorList[index].sendUrl;
|
||||
@@ -95,10 +97,10 @@ export default {
|
||||
* Should a link to the monitor be shown?
|
||||
* Attempts to guess if a link should be shown based upon if
|
||||
* sendUrl is set and if the URL is default or not.
|
||||
* @param {Object} monitor Monitor to check
|
||||
* @param {boolean} [ignoreSendUrl=false] Should the presence of the sendUrl
|
||||
* @param {object} monitor Monitor to check
|
||||
* @param {boolean} ignoreSendUrl Should the presence of the sendUrl
|
||||
* property be ignored. This will only work in edit mode.
|
||||
* @returns {boolean}
|
||||
* @returns {boolean} Should the link be shown?
|
||||
*/
|
||||
showLink(monitor, ignoreSendUrl = false) {
|
||||
// We must check if there are any elements in monitorList to
|
||||
|
@@ -119,6 +119,7 @@ export default {
|
||||
"GoogleChat": "Google Chat (Google Workspace)",
|
||||
"gorush": "Gorush",
|
||||
"gotify": "Gotify",
|
||||
"GrafanaOncall": "Grafana Oncall",
|
||||
"HomeAssistant": "Home Assistant",
|
||||
"Kook": "Kook",
|
||||
"line": "LINE Messenger",
|
||||
@@ -218,7 +219,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
|
||||
/** Show dialog to confirm deletion */
|
||||
/**
|
||||
* Show dialog to confirm deletion
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteConfirm() {
|
||||
this.modal.hide();
|
||||
this.$refs.confirmDelete.show();
|
||||
@@ -227,6 +231,7 @@ export default {
|
||||
/**
|
||||
* Show settings for specified notification
|
||||
* @param {number} notificationID ID of notification to show
|
||||
* @returns {void}
|
||||
*/
|
||||
show(notificationID) {
|
||||
if (notificationID) {
|
||||
@@ -250,7 +255,10 @@ export default {
|
||||
this.modal.show();
|
||||
},
|
||||
|
||||
/** Submit the form to the server */
|
||||
/**
|
||||
* Submit the form to the server
|
||||
* @returns {void}
|
||||
*/
|
||||
submit() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("addNotification", this.notification, this.id, (res) => {
|
||||
@@ -269,7 +277,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Test the notification endpoint */
|
||||
/**
|
||||
* Test the notification endpoint
|
||||
* @returns {void}
|
||||
*/
|
||||
test() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("testNotification", this.notification, (res) => {
|
||||
@@ -278,7 +289,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Delete the notification endpoint */
|
||||
/**
|
||||
* Delete the notification endpoint
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteNotification() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("deleteNotification", this.id, (res) => {
|
||||
@@ -293,7 +307,8 @@ export default {
|
||||
/**
|
||||
* Get a unique default name for the notification
|
||||
* @param {keyof NotificationFormList} notificationKey
|
||||
* @return {string}
|
||||
* Notification to retrieve
|
||||
* @returns {string} Default name
|
||||
*/
|
||||
getUniqueDefaultName(notificationKey) {
|
||||
|
||||
|
@@ -21,11 +21,8 @@ import { BarController, BarElement, Chart, Filler, LinearScale, LineController,
|
||||
import "chartjs-adapter-dayjs-4";
|
||||
import dayjs from "dayjs";
|
||||
import { Line } from "vue-chartjs";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { DOWN, PENDING, MAINTENANCE, log } from "../util.ts";
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler);
|
||||
|
||||
export default {
|
||||
@@ -231,7 +228,7 @@ export default {
|
||||
|
||||
this.$root.getMonitorBeats(this.monitorId, newPeriod, (res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
} else {
|
||||
this.heartbeatList = res.data;
|
||||
this.$root.storage()[`chart-period-${this.monitorId}`] = newPeriod;
|
||||
|
@@ -131,7 +131,10 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Show dialog to confirm deletion */
|
||||
/**
|
||||
* Show dialog to confirm deletion
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteConfirm() {
|
||||
this.modal.hide();
|
||||
this.$refs.confirmDelete.show();
|
||||
@@ -140,6 +143,7 @@ export default {
|
||||
/**
|
||||
* Show settings for specified proxy
|
||||
* @param {number} proxyID ID of proxy to show
|
||||
* @returns {void}
|
||||
*/
|
||||
show(proxyID) {
|
||||
if (proxyID) {
|
||||
@@ -169,7 +173,10 @@ export default {
|
||||
this.modal.show();
|
||||
},
|
||||
|
||||
/** Submit form data for saving */
|
||||
/**
|
||||
* Submit form data for saving
|
||||
* @returns {void}
|
||||
*/
|
||||
submit() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("addProxy", this.proxy, this.id, (res) => {
|
||||
@@ -187,7 +194,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Delete this proxy */
|
||||
/**
|
||||
* Delete this proxy
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteProxy() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("deleteProxy", this.id, (res) => {
|
||||
|
@@ -131,6 +131,7 @@ export default {
|
||||
/**
|
||||
* Remove the specified group
|
||||
* @param {number} index Index of group to remove
|
||||
* @returns {void}
|
||||
*/
|
||||
removeGroup(index) {
|
||||
this.$root.publicGroupList.splice(index, 1);
|
||||
@@ -141,6 +142,7 @@ export default {
|
||||
* @param {number} groupIndex Index of group to remove monitor
|
||||
* from
|
||||
* @param {number} index Index of monitor to remove
|
||||
* @returns {void}
|
||||
*/
|
||||
removeMonitor(groupIndex, index) {
|
||||
this.$root.publicGroupList[groupIndex].monitorList.splice(index, 1);
|
||||
@@ -150,10 +152,10 @@ export default {
|
||||
* Should a link to the monitor be shown?
|
||||
* Attempts to guess if a link should be shown based upon if
|
||||
* sendUrl is set and if the URL is default or not.
|
||||
* @param {Object} monitor Monitor to check
|
||||
* @param {boolean} [ignoreSendUrl=false] Should the presence of the sendUrl
|
||||
* @param {object} monitor Monitor to check
|
||||
* @param {boolean} ignoreSendUrl Should the presence of the sendUrl
|
||||
* property be ignored. This will only work in edit mode.
|
||||
* @returns {boolean}
|
||||
* @returns {boolean} Should the link be shown
|
||||
*/
|
||||
showLink(monitor, ignoreSendUrl = false) {
|
||||
// We must check if there are any elements in monitorList to
|
||||
@@ -166,8 +168,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Returns formatted certificate expiry or Bad cert message
|
||||
* @param {Object} monitor Monitor to show expiry for
|
||||
* @returns {string}
|
||||
* @param {object} monitor Monitor to show expiry for
|
||||
* @returns {string} Certificate expiry message
|
||||
*/
|
||||
formattedCertExpiryMessage(monitor) {
|
||||
if (monitor?.element?.validCert && monitor?.element?.certExpiryDaysRemaining) {
|
||||
@@ -180,9 +182,9 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns certificate expiry based on days remaining
|
||||
* @param {Object} monitor Monitor to show expiry for
|
||||
* @returns {string}
|
||||
* Returns certificate expiry color based on days remaining
|
||||
* @param {object} monitor Monitor to show expiry for
|
||||
* @returns {string} Color for certificate expiry
|
||||
*/
|
||||
certExpiryColor(monitor) {
|
||||
if (monitor?.element?.validCert && monitor.element.certExpiryDaysRemaining > 7) {
|
||||
|
@@ -19,12 +19,13 @@
|
||||
|
||||
<script>
|
||||
/**
|
||||
* @typedef {import('./TagsManager.vue').Tag} Tag
|
||||
*/
|
||||
* @typedef {import('./TagsManager.vue').Tag} Tag
|
||||
*/
|
||||
|
||||
export default {
|
||||
props: {
|
||||
/** Object representing tag
|
||||
/**
|
||||
* Object representing tag
|
||||
* @type {Tag}
|
||||
*/
|
||||
item: {
|
||||
|
@@ -123,9 +123,7 @@ import Confirm from "./Confirm.vue";
|
||||
import Tag from "./Tag.vue";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import { colorOptions } from "../util-frontend";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { getMonitorRelativeURL } from "../util.ts";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -207,6 +205,8 @@ export default {
|
||||
},
|
||||
/**
|
||||
* Selected a monitor and add to the list.
|
||||
* @param {object} monitor Monitor to add
|
||||
* @returns {void}
|
||||
*/
|
||||
selectedAddMonitor(monitor) {
|
||||
if (monitor) {
|
||||
@@ -227,6 +227,7 @@ export default {
|
||||
methods: {
|
||||
/**
|
||||
* Show confirmation for deleting a tag
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteConfirm() {
|
||||
this.$refs.confirmDelete.show();
|
||||
@@ -234,6 +235,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Reset the editTag form
|
||||
* @returns {void}
|
||||
*/
|
||||
reset() {
|
||||
this.selectedColor = null;
|
||||
@@ -263,7 +265,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Load tag information for display in the edit dialog
|
||||
* @param {Object} tag tag object to edit
|
||||
* @param {object} tag tag object to edit
|
||||
* @returns {void}
|
||||
*/
|
||||
show(tag) {
|
||||
@@ -316,7 +318,7 @@ export default {
|
||||
for (let addId of this.addingMonitor) {
|
||||
await this.addMonitorTagAsync(this.tag.id, addId, "").then((res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
editResult = false;
|
||||
}
|
||||
});
|
||||
@@ -326,7 +328,7 @@ export default {
|
||||
this.monitors.find(monitor => monitor.id === removeId)?.tags.forEach(async (monitorTag) => {
|
||||
await this.deleteMonitorTagAsync(this.tag.id, removeId, monitorTag.value).then((res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
editResult = false;
|
||||
}
|
||||
});
|
||||
@@ -377,7 +379,7 @@ export default {
|
||||
/**
|
||||
* Get monitors which has a specific tag locally
|
||||
* @param {number} tagId id of the tag to filter
|
||||
* @returns {Object[]} list of monitors which has a specific tag
|
||||
* @returns {object[]} list of monitors which has a specific tag
|
||||
*/
|
||||
monitorsByTag(tagId) {
|
||||
return Object.values(this.$root.monitorList).filter((monitor) => {
|
||||
@@ -396,7 +398,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Add a tag asynchronously
|
||||
* @param {Object} newTag Object representing new tag to add
|
||||
* @param {object} newTag Object representing new tag to add
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
addTagAsync(newTag) {
|
||||
|
@@ -129,21 +129,20 @@
|
||||
<script>
|
||||
import { Modal } from "bootstrap";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { colorOptions } from "../util-frontend";
|
||||
import Tag from "../components/Tag.vue";
|
||||
const toast = useToast();
|
||||
|
||||
/**
|
||||
* @typedef Tag
|
||||
* @type {object}
|
||||
* @property {number | undefined} id
|
||||
* @property {number | undefined} monitor_id
|
||||
* @property {number | undefined} tag_id
|
||||
* @property {string} value
|
||||
* @property {string} name
|
||||
* @property {string} color
|
||||
* @property {boolean | undefined} new
|
||||
* @property {number | undefined} id ID of tag assignment
|
||||
* @property {number | undefined} monitor_id ID of monitor tag is
|
||||
* assigned to
|
||||
* @property {number | undefined} tag_id ID of tag
|
||||
* @property {string} value Value given to tag
|
||||
* @property {string} name Name of tag
|
||||
* @property {string} color Colour of tag
|
||||
* @property {boolean | undefined} new Should a new tag be created?
|
||||
*/
|
||||
|
||||
export default {
|
||||
@@ -152,7 +151,8 @@ export default {
|
||||
VueMultiselect,
|
||||
},
|
||||
props: {
|
||||
/** Array of tags to be pre-selected
|
||||
/**
|
||||
* Array of tags to be pre-selected
|
||||
* @type {Tag[]}
|
||||
*/
|
||||
preSelectedTags: {
|
||||
@@ -244,23 +244,30 @@ export default {
|
||||
this.getExistingTags();
|
||||
},
|
||||
methods: {
|
||||
/** Show the add tag dialog */
|
||||
/**
|
||||
* Show the add tag dialog
|
||||
* @returns {void}
|
||||
*/
|
||||
showAddDialog() {
|
||||
this.modal.show();
|
||||
},
|
||||
/** Get all existing tags */
|
||||
/**
|
||||
* Get all existing tags
|
||||
* @returns {void}
|
||||
*/
|
||||
getExistingTags() {
|
||||
this.$root.getSocket().emit("getTags", (res) => {
|
||||
if (res.ok) {
|
||||
this.existingTags = res.tags;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Delete the specified tag
|
||||
* @param {Object} tag Object representing tag to delete
|
||||
* @param {object} item Object representing tag to delete
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteTag(item) {
|
||||
if (item.new) {
|
||||
@@ -273,10 +280,10 @@ export default {
|
||||
},
|
||||
/**
|
||||
* Get colour of text inside the tag
|
||||
* @param {Object} option The tag that needs to be displayed.
|
||||
* @param {object} option The tag that needs to be displayed.
|
||||
* Defaults to "white" unless the tag has no color, which will
|
||||
* then return the body color (based on application theme)
|
||||
* @returns string
|
||||
* @returns {string} Text color
|
||||
*/
|
||||
textColor(option) {
|
||||
if (option.color) {
|
||||
@@ -285,7 +292,10 @@ export default {
|
||||
return this.$root.theme === "light" ? "var(--bs-body-color)" : "inherit";
|
||||
}
|
||||
},
|
||||
/** Add a draft tag */
|
||||
/**
|
||||
* Add a draft tag
|
||||
* @returns {void}
|
||||
*/
|
||||
addDraftTag() {
|
||||
console.log("Adding Draft Tag: ", this.newDraftTag);
|
||||
if (this.newDraftTag.select != null) {
|
||||
@@ -313,7 +323,10 @@ export default {
|
||||
}
|
||||
this.clearDraftTag();
|
||||
},
|
||||
/** Remove a draft tag */
|
||||
/**
|
||||
* Remove a draft tag
|
||||
* @returns {void}
|
||||
*/
|
||||
clearDraftTag() {
|
||||
this.newDraftTag = {
|
||||
name: null,
|
||||
@@ -327,7 +340,7 @@ export default {
|
||||
},
|
||||
/**
|
||||
* Add a tag asynchronously
|
||||
* @param {Object} newTag Object representing new tag to add
|
||||
* @param {object} newTag Object representing new tag to add
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
addTagAsync(newTag) {
|
||||
@@ -359,7 +372,10 @@ export default {
|
||||
this.$root.getSocket().emit("deleteMonitorTag", tagId, monitorId, value, resolve);
|
||||
});
|
||||
},
|
||||
/** Handle pressing Enter key when inside the modal */
|
||||
/**
|
||||
* Handle pressing Enter key when inside the modal
|
||||
* @returns {void}
|
||||
*/
|
||||
onEnter() {
|
||||
if (!this.validateDraftTag.invalid) {
|
||||
this.addDraftTag();
|
||||
@@ -381,7 +397,7 @@ export default {
|
||||
let newTagResult;
|
||||
await this.addTagAsync(newTag).then((res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
newTagResult = false;
|
||||
}
|
||||
newTagResult = res.tag;
|
||||
@@ -406,7 +422,7 @@ export default {
|
||||
// Assign tag to monitor
|
||||
await this.addMonitorTagAsync(tagId, monitorId, newTag.value).then((res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
newMonitorTagResult = false;
|
||||
}
|
||||
newMonitorTagResult = true;
|
||||
@@ -422,7 +438,7 @@ export default {
|
||||
let deleteMonitorTagResult;
|
||||
await this.deleteMonitorTagAsync(deleteTag.tag_id, deleteTag.monitor_id, deleteTag.value).then((res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
deleteMonitorTagResult = false;
|
||||
}
|
||||
deleteMonitorTagResult = true;
|
||||
|
@@ -76,8 +76,6 @@
|
||||
import { Modal } from "bootstrap";
|
||||
import Confirm from "./Confirm.vue";
|
||||
import VueQrcode from "vue-qrcode";
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -101,22 +99,34 @@ export default {
|
||||
this.getStatus();
|
||||
},
|
||||
methods: {
|
||||
/** Show the dialog */
|
||||
/**
|
||||
* Show the dialog
|
||||
* @returns {void}
|
||||
*/
|
||||
show() {
|
||||
this.modal.show();
|
||||
},
|
||||
|
||||
/** Show dialog to confirm enabling 2FA */
|
||||
/**
|
||||
* Show dialog to confirm enabling 2FA
|
||||
* @returns {void}
|
||||
*/
|
||||
confirmEnableTwoFA() {
|
||||
this.$refs.confirmEnableTwoFA.show();
|
||||
},
|
||||
|
||||
/** Show dialog to confirm disabling 2FA */
|
||||
/**
|
||||
* Show dialog to confirm disabling 2FA
|
||||
* @returns {void}
|
||||
*/
|
||||
confirmDisableTwoFA() {
|
||||
this.$refs.confirmDisableTwoFA.show();
|
||||
},
|
||||
|
||||
/** Prepare 2FA configuration */
|
||||
/**
|
||||
* Prepare 2FA configuration
|
||||
* @returns {void}
|
||||
*/
|
||||
prepare2FA() {
|
||||
this.processing = true;
|
||||
|
||||
@@ -126,12 +136,15 @@ export default {
|
||||
if (res.ok) {
|
||||
this.uri = res.uri;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Save the current 2FA configuration */
|
||||
/**
|
||||
* Save the current 2FA configuration
|
||||
* @returns {void}
|
||||
*/
|
||||
save2FA() {
|
||||
this.processing = true;
|
||||
|
||||
@@ -144,12 +157,15 @@ export default {
|
||||
this.currentPassword = "";
|
||||
this.modal.hide();
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Disable 2FA for this user */
|
||||
/**
|
||||
* Disable 2FA for this user
|
||||
* @returns {void}
|
||||
*/
|
||||
disable2FA() {
|
||||
this.processing = true;
|
||||
|
||||
@@ -162,29 +178,35 @@ export default {
|
||||
this.currentPassword = "";
|
||||
this.modal.hide();
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Verify the token generated by the user */
|
||||
/**
|
||||
* Verify the token generated by the user
|
||||
* @returns {void}
|
||||
*/
|
||||
verifyToken() {
|
||||
this.$root.getSocket().emit("verifyToken", this.token, this.currentPassword, (res) => {
|
||||
if (res.ok) {
|
||||
this.tokenValid = res.valid;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Get current status of 2FA */
|
||||
/**
|
||||
* Get current status of 2FA
|
||||
* @returns {void}
|
||||
*/
|
||||
getStatus() {
|
||||
this.$root.getSocket().emit("twoFAStatus", (res) => {
|
||||
if (res.ok) {
|
||||
this.twoFAStatus = res.status;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@@ -84,10 +84,12 @@ export default {
|
||||
},
|
||||
|
||||
title() {
|
||||
if (this.type === "1y") {
|
||||
return `1${this.$t("-year")}`;
|
||||
}
|
||||
if (this.type === "720") {
|
||||
return `30${this.$t("-day")}`;
|
||||
}
|
||||
|
||||
return `24${this.$t("-hour")}`;
|
||||
}
|
||||
},
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="Bark API Version" class="form-label">{{ $t("Bark API Version") }}</label>
|
||||
<select id="Bark API Version" v-model="$parent.notification.apiVersion" class="form-select" required>
|
||||
<option value="v1">v1</option>
|
||||
<option value="v2">v2</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="Bark Endpoint" class="form-label">{{ $t("Bark Endpoint") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<input id="Bark Endpoint" v-model="$parent.notification.barkEndpoint" type="text" class="form-control" required>
|
||||
|
7
src/components/notifications/GrafanaOncall.vue
Normal file
7
src/components/notifications/GrafanaOncall.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="GrafanaOncallURL" class="form-label">{{ $t("GrafanaOncallURL") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<input id="GrafanaOncallURL" v-model="$parent.notification.GrafanaOncallURL" type="text" class="form-control" required>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -59,6 +59,28 @@
|
||||
<input id="to-bcc" v-model="$parent.notification.smtpBCC" type="text" class="form-control" autocomplete="false" :required="!hasRecipient">
|
||||
</div>
|
||||
|
||||
<p class="form-text">
|
||||
<i18n-t tag="div" keypath="smtpLiquidIntroduction" class="form-text mb-3">
|
||||
<a href="https://liquidjs.com/" target="_blank">{{ $t("documentation") }}</a>
|
||||
</i18n-t>
|
||||
<code v-pre>{{name}}</code>: {{ $t("emailTemplateServiceName") }}<br />
|
||||
<code v-pre>{{msg}}</code>: {{ $t("emailTemplateMsg") }}<br />
|
||||
<code v-pre>{{status}}</code>: {{ $t("emailTemplateStatus") }}<br />
|
||||
<code v-pre>{{heartbeatJSON}}</code>: {{ $t("emailTemplateHeartbeatJSON") }}<b>{{ $t("emailTemplateLimitedToUpDownNotification") }}</b><br />
|
||||
<code v-pre>{{monitorJSON}}</code>: {{ $t("emailTemplateMonitorJSON") }} <b>{{ $t("emailTemplateLimitedToUpDownNotification") }}</b><br />
|
||||
<code v-pre>{{hostnameOrURL}}</code>: {{ $t("emailTemplateHostnameOrURL") }}<br />
|
||||
</p>
|
||||
<div class="mb-3">
|
||||
<label for="subject-email" class="form-label">{{ $t("emailCustomSubject") }}</label>
|
||||
<input id="subject-email" v-model="$parent.notification.customSubject" type="text" class="form-control" autocomplete="false" placeholder="">
|
||||
<div class="form-text">{{ $t("leave blank for default subject") }}</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="body-email" class="form-label">{{ $t("emailCustomBody") }}</label>
|
||||
<textarea id="body-email" v-model="$parent.notification.customBody" type="text" class="form-control" autocomplete="false" placeholder=""></textarea>
|
||||
<div class="form-text">{{ $t("leave blank for default body") }}</div>
|
||||
</div>
|
||||
|
||||
<ToggleSection :heading="$t('smtpDkimSettings')">
|
||||
<i18n-t tag="div" keypath="smtpDkimDesc" class="form-text mb-3">
|
||||
<a href="https://nodemailer.com/dkim/" target="_blank">{{ $t("documentation") }}</a>
|
||||
@@ -89,17 +111,6 @@
|
||||
<input id="dkim-skip-fields" v-model="$parent.notification.smtpDkimskipFields" type="text" class="form-control" autocomplete="false" placeholder="message-id:date">
|
||||
</div>
|
||||
</ToggleSection>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="subject-email" class="form-label">{{ $t("emailCustomSubject") }}</label>
|
||||
<input id="subject-email" v-model="$parent.notification.customSubject" type="text" class="form-control" autocomplete="false" placeholder="">
|
||||
<div v-pre class="form-text">
|
||||
(leave blank for default one)<br />
|
||||
{{NAME}}: Service Name<br />
|
||||
{{HOSTNAME_OR_URL}}: Hostname or URL<br />
|
||||
{{STATUS}}: Status<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@@ -58,8 +58,6 @@
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
import axios from "axios";
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -68,7 +66,7 @@ export default {
|
||||
methods: {
|
||||
/**
|
||||
* Get the URL for telegram updates
|
||||
* @param {string} [mode=masked] Should the token be masked?
|
||||
* @param {string} mode Should the token be masked?
|
||||
* @returns {string} formatted URL
|
||||
*/
|
||||
telegramGetUpdatesURL(mode = "masked") {
|
||||
@@ -85,7 +83,11 @@ export default {
|
||||
return `https://api.telegram.org/bot${token}/getUpdates`;
|
||||
},
|
||||
|
||||
/** Get the telegram chat ID */
|
||||
/**
|
||||
* Get the telegram chat ID
|
||||
* @returns {void}
|
||||
* @throws The chat ID could not be found
|
||||
*/
|
||||
async autoGetTelegramChatID() {
|
||||
try {
|
||||
let res = await axios.get(this.telegramGetUpdatesURL("withToken"));
|
||||
@@ -106,7 +108,7 @@ export default {
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
toast.error(error.message);
|
||||
this.$root.toastError(error.message);
|
||||
}
|
||||
|
||||
},
|
||||
|
@@ -12,9 +12,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="webhook-request-body" class="form-label">{{
|
||||
$t("Request Body")
|
||||
}}</label>
|
||||
<label for="webhook-request-body" class="form-label">{{ $t("Request Body") }}</label>
|
||||
<select
|
||||
id="webhook-request-body"
|
||||
v-model="$parent.notification.webhookContentType"
|
||||
@@ -26,40 +24,29 @@
|
||||
<option value="custom">{{ $t("webhookBodyCustomOption") }}</option>
|
||||
</select>
|
||||
|
||||
<div class="form-text">
|
||||
<div v-if="$parent.notification.webhookContentType == 'json'">
|
||||
<p>{{ $t("webhookJsonDesc", ['"application/json"']) }}</p>
|
||||
</div>
|
||||
<div v-if="$parent.notification.webhookContentType == 'form-data'">
|
||||
<i18n-t tag="p" keypath="webhookFormDataDesc">
|
||||
<template #multipart>multipart/form-data"</template>
|
||||
<template #decodeFunction>
|
||||
<strong>json_decode($_POST['data'])</strong>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</div>
|
||||
<div v-if="$parent.notification.webhookContentType == 'custom'">
|
||||
<i18n-t tag="p" keypath="webhookCustomBodyDesc">
|
||||
<template #msg>
|
||||
<code>msg</code>
|
||||
</template>
|
||||
<template #heartbeat>
|
||||
<code>heartbeatJSON</code>
|
||||
</template>
|
||||
<template #monitor>
|
||||
<code>monitorJSON</code>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="$parent.notification.webhookContentType == 'json'" class="form-text">{{ $t("webhookJsonDesc", ['"application/json"']) }}</div>
|
||||
<i18n-t v-else-if="$parent.notification.webhookContentType == 'form-data'" tag="div" keypath="webhookFormDataDesc" class="form-text">
|
||||
<template #multipart>multipart/form-data"</template>
|
||||
<template #decodeFunction>
|
||||
<strong>json_decode($_POST['data'])</strong>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<template v-else-if="$parent.notification.webhookContentType == 'custom'">
|
||||
<i18n-t tag="div" keypath="liquidIntroduction" class="form-text">
|
||||
<a href="https://liquidjs.com/" target="_blank">{{ $t("documentation") }}</a>
|
||||
</i18n-t>
|
||||
<code v-pre>{{msg}}</code>: {{ $t("templateMsg") }}<br />
|
||||
<code v-pre>{{heartbeatJSON}}</code>: {{ $t("templateHeartbeatJSON") }} <b>({{ $t("templateLimitedToUpDownNotifications") }})</b><br />
|
||||
<code v-pre>{{monitorJSON}}</code>: {{ $t("templateMonitorJSON") }} <b>({{ $t("templateLimitedToUpDownCertNotifications") }})</b><br />
|
||||
|
||||
<textarea
|
||||
v-if="$parent.notification.webhookContentType == 'custom'"
|
||||
id="customBody"
|
||||
v-model="$parent.notification.webhookCustomBody"
|
||||
class="form-control"
|
||||
:placeholder="customBodyPlaceholder"
|
||||
></textarea>
|
||||
<textarea
|
||||
id="customBody"
|
||||
v-model="$parent.notification.webhookCustomBody"
|
||||
class="form-control"
|
||||
:placeholder="customBodyPlaceholder"
|
||||
required
|
||||
></textarea>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
@@ -67,15 +54,14 @@
|
||||
<input v-model="showAdditionalHeadersField" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label">{{ $t("webhookAdditionalHeadersTitle") }}</label>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
<i18n-t tag="p" keypath="webhookAdditionalHeadersDesc"> </i18n-t>
|
||||
</div>
|
||||
<div class="form-text">{{ $t("webhookAdditionalHeadersDesc") }}</div>
|
||||
<textarea
|
||||
v-if="showAdditionalHeadersField"
|
||||
id="additionalHeaders"
|
||||
v-model="$parent.notification.webhookAdditionalHeaders"
|
||||
class="form-control"
|
||||
:placeholder="headersPlaceholder"
|
||||
:required="showAdditionalHeadersField"
|
||||
></textarea>
|
||||
</div>
|
||||
</template>
|
||||
@@ -90,18 +76,18 @@ export default {
|
||||
computed: {
|
||||
headersPlaceholder() {
|
||||
return this.$t("Example:", [
|
||||
`
|
||||
{
|
||||
`{
|
||||
"Authorization": "Authorization Token"
|
||||
}`,
|
||||
]);
|
||||
},
|
||||
customBodyPlaceholder() {
|
||||
return `Example:
|
||||
{
|
||||
"Title": "Uptime Kuma Alert - {{ monitorJSON['name'] }}",
|
||||
return this.$t("Example:", [
|
||||
`{
|
||||
"Title": "Uptime Kuma Alert{% if monitorJSON %} - {{ monitorJSON['name'] }}{% endif %}",
|
||||
"Body": "{{ msg }}"
|
||||
}`;
|
||||
}`
|
||||
]);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@@ -12,6 +12,7 @@ import FreeMobile from "./FreeMobile.vue";
|
||||
import GoogleChat from "./GoogleChat.vue";
|
||||
import Gorush from "./Gorush.vue";
|
||||
import Gotify from "./Gotify.vue";
|
||||
import GrafanaOncall from "./GrafanaOncall.vue";
|
||||
import HomeAssistant from "./HomeAssistant.vue";
|
||||
import Kook from "./Kook.vue";
|
||||
import Line from "./Line.vue";
|
||||
@@ -54,7 +55,6 @@ import Splunk from "./Splunk.vue";
|
||||
|
||||
/**
|
||||
* Manage all notification form.
|
||||
*
|
||||
* @type { Record<string, any> }
|
||||
*/
|
||||
const NotificationFormList = {
|
||||
@@ -72,6 +72,7 @@ const NotificationFormList = {
|
||||
"GoogleChat": GoogleChat,
|
||||
"gorush": Gorush,
|
||||
"gotify": Gotify,
|
||||
"GrafanaOncall": GrafanaOncall,
|
||||
"HomeAssistant": HomeAssistant,
|
||||
"Kook": Kook,
|
||||
"line": Line,
|
||||
|
@@ -72,8 +72,6 @@
|
||||
<script>
|
||||
import APIKeyDialog from "../../components/APIKeyDialog.vue";
|
||||
import Confirm from "../Confirm.vue";
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -96,6 +94,7 @@ export default {
|
||||
/**
|
||||
* Show dialog to confirm deletion
|
||||
* @param {number} keyID ID of monitor that is being deleted
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteDialog(keyID) {
|
||||
this.selectedKeyID = keyID;
|
||||
@@ -104,19 +103,18 @@ export default {
|
||||
|
||||
/**
|
||||
* Delete a key
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteKey() {
|
||||
this.$root.deleteAPIKey(this.selectedKeyID, (res) => {
|
||||
if (res.ok) {
|
||||
toast.success(res.msg);
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
this.$root.toastRes(res);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show dialog to confirm pause
|
||||
* @param {number} keyID ID of key to pause
|
||||
* @returns {void}
|
||||
*/
|
||||
disableDialog(keyID) {
|
||||
this.selectedKeyID = keyID;
|
||||
@@ -124,7 +122,8 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* Pause maintenance
|
||||
* Pause API key
|
||||
* @returns {void}
|
||||
*/
|
||||
disableKey() {
|
||||
this.$root.getSocket().emit("disableAPIKey", this.selectedKeyID, (res) => {
|
||||
@@ -133,7 +132,9 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* Resume maintenance
|
||||
* Resume API key
|
||||
* @param {number} id Key to resume
|
||||
* @returns {void}
|
||||
*/
|
||||
enableKey(id) {
|
||||
this.$root.getSocket().emit("enableAPIKey", id, (res) => {
|
||||
|
@@ -1,228 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="my-4">
|
||||
<div class="alert alert-warning" role="alert" style="border-radius: 15px;">
|
||||
{{ $t("backupOutdatedWarning") }}<br />
|
||||
<br />
|
||||
{{ $t("backupRecommend") }}
|
||||
</div>
|
||||
|
||||
<h4 class="mt-4 mb-2">{{ $t("Export Backup") }}</h4>
|
||||
|
||||
<p>
|
||||
{{ $t("backupDescription") }} <br />
|
||||
({{ $t("backupDescription2") }}) <br />
|
||||
</p>
|
||||
|
||||
<div class="mb-2">
|
||||
<button class="btn btn-primary" @click="downloadBackup">
|
||||
{{ $t("Export") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<strong>{{ $t("backupDescription3") }}</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<h4 class="mt-4 mb-2">{{ $t("Import Backup") }}</h4>
|
||||
|
||||
<label class="form-label">{{ $t("Options") }}:</label>
|
||||
<br />
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="radioKeep"
|
||||
v-model="importHandle"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="radioImportHandle"
|
||||
value="keep"
|
||||
/>
|
||||
<label class="form-check-label" for="radioKeep">
|
||||
{{ $t("Keep both") }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="radioSkip"
|
||||
v-model="importHandle"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="radioImportHandle"
|
||||
value="skip"
|
||||
/>
|
||||
<label class="form-check-label" for="radioSkip">
|
||||
{{ $t("Skip existing") }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="radioOverwrite"
|
||||
v-model="importHandle"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="radioImportHandle"
|
||||
value="overwrite"
|
||||
/>
|
||||
<label class="form-check-label" for="radioOverwrite">
|
||||
{{ $t("Overwrite") }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-text mb-2">
|
||||
{{ $t("importHandleDescription") }}
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<input
|
||||
id="import-backend"
|
||||
type="file"
|
||||
class="form-control"
|
||||
accept="application/json"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-2 justify-content-end">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-primary"
|
||||
:disabled="processing"
|
||||
@click="confirmImport"
|
||||
>
|
||||
<div
|
||||
v-if="processing"
|
||||
class="spinner-border spinner-border-sm me-1"
|
||||
></div>
|
||||
{{ $t("Import") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="importAlert"
|
||||
class="alert alert-danger mt-3"
|
||||
style="padding: 6px 16px;"
|
||||
>
|
||||
{{ importAlert }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Confirm
|
||||
ref="confirmImport"
|
||||
btn-style="btn-danger"
|
||||
:yes-text="$t('Yes')"
|
||||
:no-text="$t('No')"
|
||||
@yes="importBackup"
|
||||
>
|
||||
{{ $t("confirmImportMsg") }}
|
||||
</Confirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Confirm from "../../components/Confirm.vue";
|
||||
import dayjs from "dayjs";
|
||||
import { useToast } from "vue-toastification";
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Confirm,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
processing: false,
|
||||
importHandle: "skip",
|
||||
importAlert: null,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Show the confimation dialog confirming the configuration
|
||||
* be imported
|
||||
*/
|
||||
confirmImport() {
|
||||
this.$refs.confirmImport.show();
|
||||
},
|
||||
|
||||
/** Download a backup of the configuration */
|
||||
downloadBackup() {
|
||||
let time = dayjs().format("YYYY_MM_DD-hh_mm_ss");
|
||||
let fileName = `Uptime_Kuma_Backup_${time}.json`;
|
||||
let monitorList = Object.values(this.$root.monitorList);
|
||||
let exportData = {
|
||||
version: this.$root.info.version,
|
||||
notificationList: this.$root.notificationList,
|
||||
monitorList: monitorList,
|
||||
};
|
||||
exportData = JSON.stringify(exportData, null, 4);
|
||||
let downloadItem = document.createElement("a");
|
||||
downloadItem.setAttribute(
|
||||
"href",
|
||||
"data:application/json;charset=utf-8," +
|
||||
encodeURIComponent(exportData)
|
||||
);
|
||||
downloadItem.setAttribute("download", fileName);
|
||||
downloadItem.click();
|
||||
},
|
||||
|
||||
/**
|
||||
* Import the specified backup file
|
||||
* @returns {?string}
|
||||
*/
|
||||
importBackup() {
|
||||
this.processing = true;
|
||||
let uploadItem = document.getElementById("import-backend").files;
|
||||
|
||||
if (uploadItem.length <= 0) {
|
||||
this.processing = false;
|
||||
return (this.importAlert = this.$t("alertNoFile"));
|
||||
}
|
||||
|
||||
if (uploadItem.item(0).type !== "application/json") {
|
||||
this.processing = false;
|
||||
return (this.importAlert = this.$t("alertWrongFileType"));
|
||||
}
|
||||
|
||||
let fileReader = new FileReader();
|
||||
fileReader.readAsText(uploadItem.item(0));
|
||||
|
||||
fileReader.onload = (item) => {
|
||||
this.$root.uploadBackup(
|
||||
item.target.result,
|
||||
this.importHandle,
|
||||
(res) => {
|
||||
this.processing = false;
|
||||
|
||||
if (res.ok) {
|
||||
toast.success(res.msg);
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../assets/vars.scss";
|
||||
|
||||
.dark {
|
||||
#import-backend {
|
||||
&::file-selector-button {
|
||||
color: $primary;
|
||||
background-color: $dark-bg;
|
||||
}
|
||||
|
||||
&:hover:not(:disabled):not([readonly])::file-selector-button {
|
||||
color: $dark-font-color2;
|
||||
background-color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -293,16 +293,25 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Save the settings */
|
||||
/**
|
||||
* Save the settings
|
||||
* @returns {void}
|
||||
*/
|
||||
saveGeneral() {
|
||||
localStorage.timezone = this.$root.userTimezone;
|
||||
this.saveSettings();
|
||||
},
|
||||
/** Get the base URL of the application */
|
||||
/**
|
||||
* Get the base URL of the application
|
||||
* @returns {void}
|
||||
*/
|
||||
autoGetPrimaryBaseURL() {
|
||||
this.settings.primaryBaseURL = location.protocol + "//" + location.host;
|
||||
},
|
||||
|
||||
/**
|
||||
* Test the chrome executable
|
||||
* @returns {void}
|
||||
*/
|
||||
testChrome() {
|
||||
this.$root.getSocket().emit("testChrome", this.settings.chromeExecutable, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
|
@@ -57,9 +57,6 @@
|
||||
<script>
|
||||
import Confirm from "../../components/Confirm.vue";
|
||||
import { log } from "../../util.ts";
|
||||
import { useToast } from "vue-toastification";
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -94,7 +91,10 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Get the current size of the database */
|
||||
/**
|
||||
* Get the current size of the database
|
||||
* @returns {void}
|
||||
*/
|
||||
loadDatabaseSize() {
|
||||
log.debug("monitorhistory", "load database size");
|
||||
this.$root.getSocket().emit("getDatabaseSize", (res) => {
|
||||
@@ -107,30 +107,39 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Request that the database is shrunk */
|
||||
/**
|
||||
* Request that the database is shrunk
|
||||
* @returns {void}
|
||||
*/
|
||||
shrinkDatabase() {
|
||||
this.$root.getSocket().emit("shrinkDatabase", (res) => {
|
||||
if (res.ok) {
|
||||
this.loadDatabaseSize();
|
||||
toast.success("Done");
|
||||
this.$root.toastSuccess("Done");
|
||||
} else {
|
||||
log.debug("monitorhistory", res);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Show the dialog to confirm clearing stats */
|
||||
/**
|
||||
* Show the dialog to confirm clearing stats
|
||||
* @returns {void}
|
||||
*/
|
||||
confirmClearStatistics() {
|
||||
this.$refs.confirmClearStatistics.show();
|
||||
},
|
||||
|
||||
/** Send the request to clear stats */
|
||||
/**
|
||||
* Send the request to clear stats
|
||||
* @returns {void}
|
||||
*/
|
||||
clearStatistics() {
|
||||
this.$root.clearStatistics((res) => {
|
||||
if (res.ok) {
|
||||
this.$router.go();
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@@ -20,6 +20,39 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="my-4 pt-4">
|
||||
<h5 class="my-4 settings-subheading">{{ $t("monitorToastMessagesLabel") }}</h5>
|
||||
<p>{{ $t("monitorToastMessagesDescription") }}</p>
|
||||
|
||||
<div class="my-4">
|
||||
<label for="toastErrorTimeoutSecs" class="form-label">
|
||||
{{ $t("toastErrorTimeout") }}
|
||||
</label>
|
||||
<input
|
||||
id="toastErrorTimeoutSecs"
|
||||
v-model="toastErrorTimeoutSecs"
|
||||
type="number"
|
||||
class="form-control"
|
||||
min="-1"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<label for="toastSuccessTimeoutSecs" class="form-label">
|
||||
{{ $t("toastSuccessTimeout") }}
|
||||
</label>
|
||||
<input
|
||||
id="toastSuccessTimeoutSecs"
|
||||
v-model="toastSuccessTimeoutSecs"
|
||||
type="number"
|
||||
class="form-control"
|
||||
min="-1"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-4 pt-4">
|
||||
<h5 class="my-4 settings-subheading">{{ $t("settingsCertificateExpiry") }}</h5>
|
||||
<p>{{ $t("certificationExpiryDescription") }}</p>
|
||||
@@ -58,6 +91,8 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
toastSuccessTimeoutSecs: 20,
|
||||
toastErrorTimeoutSecs: -1,
|
||||
/**
|
||||
* Variable to store the input for new certificate expiry day.
|
||||
*/
|
||||
@@ -77,10 +112,31 @@ export default {
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
// Parse, store and apply new timeout settings.
|
||||
toastSuccessTimeoutSecs(newTimeout) {
|
||||
const parsedTimeout = parseInt(newTimeout);
|
||||
if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
|
||||
localStorage.toastSuccessTimeout = newTimeout > 0 ? newTimeout * 1000 : newTimeout;
|
||||
}
|
||||
},
|
||||
toastErrorTimeoutSecs(newTimeout) {
|
||||
const parsedTimeout = parseInt(newTimeout);
|
||||
if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
|
||||
localStorage.toastErrorTimeout = newTimeout > 0 ? newTimeout * 1000 : newTimeout;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.loadToastTimeoutSettings();
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Remove a day from expiry notification days.
|
||||
* @param {number} day The day to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
removeExpiryNotifDay(day) {
|
||||
this.settings.tlsExpiryNotifyDays = this.settings.tlsExpiryNotifyDays.filter(d => d !== day);
|
||||
@@ -93,6 +149,7 @@ export default {
|
||||
* - day is > 0.
|
||||
* - The day is not already in the list.
|
||||
* @param {number} day The day number to add.
|
||||
* @returns {void}
|
||||
*/
|
||||
addExpiryNotifDay(day) {
|
||||
if (day != null && day !== "") {
|
||||
@@ -106,6 +163,28 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads toast timeout settings from storage to component data.
|
||||
* @returns {void}
|
||||
*/
|
||||
loadToastTimeoutSettings() {
|
||||
const successTimeout = localStorage.toastSuccessTimeout;
|
||||
if (successTimeout !== undefined) {
|
||||
const parsedTimeout = parseInt(successTimeout);
|
||||
if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
|
||||
this.toastSuccessTimeoutSecs = parsedTimeout > 0 ? parsedTimeout / 1000 : parsedTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
const errorTimeout = localStorage.toastErrorTimeout;
|
||||
if (errorTimeout !== undefined) {
|
||||
const parsedTimeout = parseInt(errorTimeout);
|
||||
if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
|
||||
this.toastErrorTimeoutSecs = parsedTimeout > 0 ? parsedTimeout / 1000 : parsedTimeout;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@@ -175,17 +175,26 @@ export default {
|
||||
this.$root.getSocket().emit(prefix + "leave");
|
||||
},
|
||||
methods: {
|
||||
/** Start the Cloudflare tunnel */
|
||||
/**
|
||||
* Start the Cloudflare tunnel
|
||||
* @returns {void}
|
||||
*/
|
||||
start() {
|
||||
this.$root.getSocket().emit(prefix + "start", this.cloudflareTunnelToken);
|
||||
},
|
||||
/** Stop the Cloudflare tunnel */
|
||||
/**
|
||||
* Stop the Cloudflare tunnel
|
||||
* @returns {void}
|
||||
*/
|
||||
stop() {
|
||||
this.$root.getSocket().emit(prefix + "stop", this.currentPassword, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
});
|
||||
},
|
||||
/** Remove the token for the Cloudflare tunnel */
|
||||
/**
|
||||
* Remove the token for the Cloudflare tunnel
|
||||
* @returns {void}
|
||||
*/
|
||||
removeToken() {
|
||||
this.$root.getSocket().emit(prefix + "removeToken");
|
||||
this.cloudflareTunnelToken = "";
|
||||
|
@@ -155,7 +155,10 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Check new passwords match before saving them */
|
||||
/**
|
||||
* Check new passwords match before saving them
|
||||
* @returns {void}
|
||||
*/
|
||||
savePassword() {
|
||||
if (this.password.newPassword !== this.password.repeatNewPassword) {
|
||||
this.invalidPassword = true;
|
||||
@@ -173,7 +176,10 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/** Disable authentication for web app access */
|
||||
/**
|
||||
* Disable authentication for web app access
|
||||
* @returns {void}
|
||||
*/
|
||||
disableAuth() {
|
||||
this.settings.disableAuth = true;
|
||||
|
||||
@@ -186,7 +192,10 @@ export default {
|
||||
}, this.password.currentPassword);
|
||||
},
|
||||
|
||||
/** Enable authentication for web app access */
|
||||
/**
|
||||
* Enable authentication for web app access
|
||||
* @returns {void}
|
||||
*/
|
||||
enableAuth() {
|
||||
this.settings.disableAuth = false;
|
||||
this.saveSettings();
|
||||
@@ -194,7 +203,10 @@ export default {
|
||||
location.reload();
|
||||
},
|
||||
|
||||
/** Show confirmation dialog for disable auth */
|
||||
/**
|
||||
* Show confirmation dialog for disable auth
|
||||
* @returns {void}
|
||||
*/
|
||||
confirmDisableAuth() {
|
||||
this.$refs.confirmDisableAuth.show();
|
||||
},
|
||||
|
@@ -28,11 +28,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useToast } from "vue-toastification";
|
||||
import TagEditDialog from "../../components/TagEditDialog.vue";
|
||||
import Tag from "../Tag.vue";
|
||||
import Confirm from "../Confirm.vue";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -86,7 +84,7 @@ export default {
|
||||
if (res.ok) {
|
||||
this.tagsList = res.tags;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -138,7 +136,7 @@ export default {
|
||||
/**
|
||||
* Get monitors which has a specific tag locally
|
||||
* @param {number} tagId id of the tag to filter
|
||||
* @returns {Object[]} list of monitors which has a specific tag
|
||||
* @returns {object[]} list of monitors which has a specific tag
|
||||
*/
|
||||
monitorsByTag(tagId) {
|
||||
return Object.values(this.$root.monitorList).filter((monitor) => {
|
||||
|
@@ -1,4 +1,6 @@
|
||||
# How to translate
|
||||
# Translations
|
||||
|
||||
## How to translate
|
||||
|
||||
(2023-01-24 Updated)
|
||||
|
||||
@@ -7,7 +9,7 @@
|
||||
3. Make sure your GitHub email is matched with Weblate's account, so that it could show you as a contributor on GitHub
|
||||
4. Choose your language on Weblate and start translating.
|
||||
|
||||
# How to add a new language in the dropdown
|
||||
## How to add a new language in the dropdown
|
||||
|
||||
1. Add your language at https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/
|
||||
2. Find the language code (You can find it at the end of the URL)
|
||||
|
@@ -63,7 +63,7 @@
|
||||
"Add one": "أضف واحدا",
|
||||
"wayToGetCloudflaredURL": "(قم بتنزيل CloudFlared من {0})",
|
||||
"cloudflareWebsite": "موقع CloudFlare",
|
||||
"Message:": ":رسالة",
|
||||
"Message:": "رسالة:",
|
||||
"Don't know how to get the token? Please read the guide:": "لا أعرف كيفية الحصول على الرمز المميز؟ يرجى قراءة الدليل:",
|
||||
"telegramSendSilently": "أرسل بصمت",
|
||||
"telegramSendSilentlyDescription": "ترسل الرسالة بصمت ويتلقى المستخدمون إشعارا بدون صوت.",
|
||||
@@ -134,7 +134,7 @@
|
||||
"ignoreTLSError": "تجاهل خطأ TLS/SSL لمواقع HTTPS",
|
||||
"upsideDownModeDescription": "اقلب الحالة رأسًا على عقب. إذا كانت الخدمة قابلة للوصول إلى أسفل.",
|
||||
"maxRedirectDescription": "الحد الأقصى لعدد إعادة التوجيه لمتابعة. ضبط على 0 لتعطيل إعادة التوجيه.",
|
||||
"Upside Down Mode": "وضع أسفل أسفل",
|
||||
"Upside Down Mode": "وضع رأسا على عقب",
|
||||
"Max. Redirects": "الأعلى. إعادة التوجيه",
|
||||
"Accepted Status Codes": "رموز الحالة المقبولة",
|
||||
"Push URL": "دفع عنوان URL",
|
||||
@@ -209,7 +209,7 @@
|
||||
"Indigo": "النيلي",
|
||||
"Purple": "نفسجي",
|
||||
"webhookAdditionalHeadersDesc": "يحدد رؤوس إضافية مرسلة مع webhook.",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"Webhook URL": "عنوان URL للخطاف الإلكتروني",
|
||||
"Pink": "لون القرنفل",
|
||||
"Custom": "العادة",
|
||||
"Status Pages": "صفحات الحالة",
|
||||
@@ -359,10 +359,10 @@
|
||||
"Connection String": "سلسلة الاتصال",
|
||||
"Query": "استفسار",
|
||||
"settingsCertificateExpiry": "شهادة TLS انتهاء الصلاحية",
|
||||
"certificationExpiryDescription": "شاشات HTTPS تضيء عندما تنتهي شهادة TLS في",
|
||||
"certificationExpiryDescription": "تقوم مراقبات HTTPS بتشغيل إشعار عند انتهاء صلاحية شهادة TLS في:",
|
||||
"Setup Docker Host": "إعداد مضيف Docker",
|
||||
"Connection Type": "نوع الاتصال",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
"Docker Daemon": "دُوكر Daemon",
|
||||
"deleteDockerHostMsg": "هل أنت متأكد من حذف مضيف Docker لجميع الشاشات؟",
|
||||
"socket": "قابس كهرباء",
|
||||
"tcp": "TCP / HTTP",
|
||||
@@ -378,20 +378,20 @@
|
||||
"Chat ID": "معرف الدردشة",
|
||||
"telegramMessageThreadID": "معرف المواضيع",
|
||||
"supportTelegramChatID": "دعم الدردشة المباشرة / معرف الدردشة للقناة",
|
||||
"wayToGetTelegramChatID": "يمكنك الحصول على معرف الدردشة الخاص بك عن طريق إرسال رسالة إلى الروبوت والانتقال إلى عنوان URL هذا لعرض Chat_id",
|
||||
"wayToGetTelegramChatID": "يمكنك الحصول على معرف الدردشة الخاص بك عن طريق إرسال رسالة إلى البوت والانتقال إلى عنوان URL هذا لعرض chat_id:",
|
||||
"YOUR BOT TOKEN HERE": "رمز الروبوت الخاص بك هنا",
|
||||
"chatIDNotFound": "لم يتم العثور على معرف الدردشة ؛ الرجاء إرسال رسالة إلى هذا الروبوت أولاً",
|
||||
"disableCloudflaredNoAuthMsg": "أنت في وضع مصادقة لا توجد كلمة مرور غير مطلوبة.",
|
||||
"trustProxyDescription": "ثق في رؤوس \"X-Forwarded- *\". إذا كنت ترغب في الحصول على عنوان IP الصحيح للعميل وكان Uptime Kuma خلف وكيل مثل Nginx أو Apache ، فيجب عليك تمكين هذا.",
|
||||
"wayToGetLineNotifyToken": "يمكنك الحصول على رمز الوصول من {0}",
|
||||
"Examples": "أمثلة",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Home Assistant URL": "عنوان URL لـ Home Assistant",
|
||||
"Long-Lived Access Token": "الرمز المميز للوصول منذ فترة طويلة",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "يمكن إنشاء رمز الوصول منذ فترة طويلة عن طريق النقر على اسم ملف التعريف الخاص بك (أسفل اليسار) والتمرير إلى الأسفل ثم انقر فوق إنشاء الرمز المميز. ",
|
||||
"Notification Service": "خدمة الإخطار",
|
||||
"default: notify all devices": "الافتراضي: إخطار جميع الأجهزة",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "يمكن العثور على قائمة بخدمات الإخطار في المساعد المنزلي ضمن \"Developer Tools > Services\" ابحث عن \"notification\" للعثور على اسم جهازك/هاتفك.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "يمكن تشغيل الأتمتة اختياريًا في Home Assistant:",
|
||||
"Automations can optionally be triggered in Home Assistant:": "الاتمته يمكن اختياريا تحفيزها عبر Home Assistant:",
|
||||
"Trigger type:": "نوع الزناد:",
|
||||
"Event type:": "نوع الحدث:",
|
||||
"Event data:": "بيانات الحدث:",
|
||||
@@ -430,7 +430,7 @@
|
||||
"Display Timezone": "عرض المنطقة الزمنية",
|
||||
"Server Timezone": "المنطقة الزمنية الخادم",
|
||||
"statusPageMaintenanceEndDate": "نهاية",
|
||||
"IconUrl": "url url icon",
|
||||
"IconUrl": "عنوان URL للرمز",
|
||||
"Enable DNS Cache": "تمكين ذاكرة التخزين المؤقت DNS",
|
||||
"Disable": "إبطال",
|
||||
"dnsCacheDescription": "قد لا يعمل في بعض بيئات IPv6 تعطيله إذا واجهت أي مشكلات.",
|
||||
@@ -456,7 +456,7 @@
|
||||
"To Email": "للبريد الإلكتروني",
|
||||
"smtpCC": "نسخة",
|
||||
"smtpBCC": "BCC",
|
||||
"Discord Webhook URL": "Discord Webhook URL",
|
||||
"Discord Webhook URL": "عنوان URL للخّطاف على الويب للديسكورد",
|
||||
"wayToGetDiscordURL": "يمكنك الحصول على هذا بالانتقال إلى إعدادات الخادم -> عمليات التكامل -> عرض الخطافات على الويب -> خطاف ويب جديد",
|
||||
"Bot Display Name": "اسم عرض الروبوت",
|
||||
"Prefix Custom Message": "بادئة رسالة مخصصة",
|
||||
@@ -464,7 +464,7 @@
|
||||
"wayToGetTeamsURL": "يمكنك معرفة كيفية إنشاء عنوان URL webhook {0}.",
|
||||
"wayToGetZohoCliqURL": "يمكنك معرفة كيفية إنشاء عنوان URL webhook {0}.",
|
||||
"needSignalAPI": "تحتاج إلى وجود عميل إشارة مع REST API.",
|
||||
"wayToCheckSignalURL": "يمكنك التحقق من عنوان URL هذا لعرض كيفية إعداد واحد",
|
||||
"wayToCheckSignalURL": "يمكنك التحقق من عنوان URL هذا لعرض كيفية إعداد واحد:",
|
||||
"Number": "رقم",
|
||||
"Recipients": "المستلمين",
|
||||
"Access Token": "رمز وصول",
|
||||
@@ -477,8 +477,8 @@
|
||||
"User ID": "معرف المستخدم",
|
||||
"Messaging API": "واجهة برمجة تطبيقات المراسلة",
|
||||
"wayToGetLineChannelToken": "قم أولاً بالوصول إلى {0} إنشاء مزود وقناة (واجهة برمجة تطبيقات المراسلة) ، ثم يمكنك الحصول على رمز الوصول إلى القناة ومعرف المستخدم من عناصر القائمة المذكورة أعلاه.",
|
||||
"Icon URL": "url url icon",
|
||||
"aboutIconURL": "يمكنك توفير رابط لصورة في \"Icon URL\" لتجاوز صورة الملف الشخصي الافتراضي. لن يتم استخدامه إذا تم تعيين رمز رمز رمز.",
|
||||
"Icon URL": "عنوان URL للرمز",
|
||||
"aboutIconURL": "يمكنك توفير رابط لصورة في \"رمز URL\" لتجاوز صورة الملف الشخصي الافتراضية. لن يتم استخدامه إذا تم تعيين ايقونة اموجي.",
|
||||
"aboutMattermostChannelName": "يمكنك تجاوز القناة الافتراضية التي تنشرها WebHook من خلال إدخال اسم القناة في \"Channel Name\" الحقل. يجب تمكين هذا في إعدادات Webhook Mattern. السابق",
|
||||
"dataRetentionTimeError": "يجب أن تكون فترة الاستبقاء 0 أو أكبر",
|
||||
"infiniteRetention": "ضبط على 0 للاحتفاظ لا نهائي.",
|
||||
@@ -492,7 +492,7 @@
|
||||
"clearEventsMsg": "هل أنت متأكد من حذف جميع الأحداث لهذا الشاشة؟",
|
||||
"clearHeartbeatsMsg": "هل أنت متأكد من حذف جميع دقات القلب لهذا الشاشة؟",
|
||||
"confirmImportMsg": "هل أنت متأكد من أنك تريد استيراد النسخ الاحتياطي؟ يرجى التحقق من أنك حددت خيار الاستيراد الصحيح.",
|
||||
"twoFAVerifyLabel": "الرجاء إدخال الرمز المميز الخاص بك للتحقق من 2FA",
|
||||
"twoFAVerifyLabel": "يرجى إدخال الرمز المميز الخاص بك للتحقق من المصادقة الثنائية (2FA):",
|
||||
"pushoversounds pushover": "سداد (افتراضي)",
|
||||
"pushoversounds bike": "دراجة هوائية",
|
||||
"pushoversounds bugle": "بوق",
|
||||
@@ -550,7 +550,7 @@
|
||||
"SMS Type": "نوع الرسائل القصيرة",
|
||||
"octopushTypePremium": "قسط (سريع - موصى به للتنبيه)",
|
||||
"octopushTypeLowCost": "التكلفة المنخفضة (بطيئة - تم حظرها أحيانًا بواسطة المشغل)",
|
||||
"checkPrice": "تحقق من الأسعار {0}",
|
||||
"checkPrice": "تحقق من أسعار {0}:",
|
||||
"apiCredentials": "بيانات اعتماد API",
|
||||
"octopushLegacyHint": "هل تستخدم الإصدار القديم من Octopush (2011-2020) أو الإصدار الجديد؟",
|
||||
"Check octopush prices": "تحقق من أسعار Octopush {0}.",
|
||||
@@ -581,7 +581,7 @@
|
||||
"Base URL": "عنوان URL الأساسي",
|
||||
"goAlertInfo": "الهدف هو تطبيق مفتوح المصدر لجدولة الجدولة التلقائية والإشعارات (مثل الرسائل القصيرة أو المكالمات الصوتية). إشراك الشخص المناسب تلقائيًا بالطريقة الصحيحة وفي الوقت المناسب! {0}",
|
||||
"goAlertIntegrationKeyInfo": "احصل على مفتاح تكامل API العام للخدمة في هذا التنسيق \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" عادةً قيمة المعلمة الرمزية لعنوان url المنسق.",
|
||||
"TemplateCode": "TemplateCode",
|
||||
"TemplateCode": "رمز القالب",
|
||||
"SignName": "اسم تسجيل الدخول",
|
||||
"Sms template must contain parameters: ": "يجب أن يحتوي قالب الرسائل القصيرة على معلمات: ",
|
||||
"Bark Endpoint": "نقطة نهاية اللحاء",
|
||||
@@ -613,10 +613,10 @@
|
||||
"Feishu WebHookUrl": "Feishu Webhookurl",
|
||||
"matrixHomeserverURL": "عنوان URL HomeServer (مع HTTP (S)",
|
||||
"Internal Room Id": "معرف الغرفة الداخلية",
|
||||
"matrixDesc1": "يمكنك العثور على معرف الغرفة الداخلي من خلال البحث في القسم المتقدم من إعدادات الغرفة في عميل Matrix الخاص بك. يجب أن تبدو مثل! QMDRCPUIFLWSFJXYE6",
|
||||
"matrixDesc1": "يمكنك العثور على معرف الغرفة الداخلي من خلال البحث في القسم المتقدم لإعدادات الغرفة في عميل Matrix الخاص بك. ينبغي أن يبدو مثل QMdRCpUIfLwsfjxye6:home.server!.",
|
||||
"Uptime Kuma URL": "UPTIME KUMA URL",
|
||||
"Icon Emoji": "أيقونة الرموز التعبيرية",
|
||||
"signalImportant": "مهم",
|
||||
"signalImportant": "هام: لا يمكنك المزج بين المجموعات والأرقام في المستلمين!",
|
||||
"aboutWebhooks": "مزيد من المعلومات حول Webhooks ON",
|
||||
"aboutChannelName": "أدخل اسم القناة في حقل اسم القناة {0} إذا كنت تريد تجاوز قناة WebHook. السابق",
|
||||
"aboutKumaURL": "إذا تركت حقل URL في وقت التشغيل KUMA فارغًا ، فسيتم افتراضيًا إلى صفحة GitHub Project.",
|
||||
@@ -679,10 +679,13 @@
|
||||
"deleteAPIKeyMsg": "هل أنت متأكد أنك تريد حذف مفتاح API هذا؟",
|
||||
"Auto Get": "الحصول التلقائي",
|
||||
"Auto resolve or acknowledged": "",
|
||||
"backupDescription2": "ملحوظة",
|
||||
"backupDescription2": "ملحوظة: لم يتم تضمين بيانات السجل والأحداث.",
|
||||
"languageName": "العربية",
|
||||
"Game": "الألعاب",
|
||||
"List": "القائمة",
|
||||
"statusMaintenance": "الصيانة",
|
||||
"Home": "الرئيسة"
|
||||
"Home": "الرئيسة",
|
||||
"setupDatabaseChooseDatabase": "ما هي قاعدة البيانات التي تريد استخدامها؟",
|
||||
"setupDatabaseEmbeddedMariaDB": "لا تحتاج إلى تعيين أي شيء. قامت نسخة دُوكر بتضمين MariaDB لك تلقائيًا. سيتصل (آب تايم كارما) بقاعدة البيانات هذه عبر مقبس Unix.",
|
||||
"setupDatabaseMariaDB": "للاتصال بقاعدة بيانات MariaDB خارجية. تحتاج إلى تعيين معلومات اتصال قاعدة البيانات."
|
||||
}
|
||||
|
@@ -644,7 +644,7 @@
|
||||
"IconUrl": "Икона URL адрес",
|
||||
"webhookAdditionalHeadersTitle": "Допълнителни хедъри",
|
||||
"webhookAdditionalHeadersDesc": "Задава допълнителни хедъри, изпратени с уеб куката. Всеки хедър трябва да бъде дефиниран като JSON ключ/стойност.",
|
||||
"Enable DNS Cache": "Активирай DNS кеширане за HTTP(S) монитори",
|
||||
"Enable DNS Cache": "(Отпаднала) Активирай DNS кеширане за HTTP(S) монитори",
|
||||
"Enable": "Активирай",
|
||||
"Disable": "Деактивирай",
|
||||
"dnsCacheDescription": "Възможно е да не работи в IPv6 среда - деактивирайте, ако срещнете проблеми.",
|
||||
@@ -838,5 +838,37 @@
|
||||
"styleElapsedTimeShowNoLine": "Покажи (без ред)",
|
||||
"gamedigGuessPort": "Gamedig: Познай порт",
|
||||
"gamedigGuessPortDescription": "Портът, използван от Valve Server Query Protocol, може да е различен от клиентския порт. Опитайте това, ако мониторът не може да се свърже с вашия сървър.",
|
||||
"styleElapsedTimeShowWithLine": "Покажи (с ред)"
|
||||
"styleElapsedTimeShowWithLine": "Покажи (с ред)",
|
||||
"enableNSCD": "Активирай NSCD (Name Service Cache Daemon) за кеширане на всички DNS заявки",
|
||||
"dbName": "Име на базата данни",
|
||||
"setupDatabaseChooseDatabase": "Коя база данни желаете да използвате?",
|
||||
"Saved.": "Запазено.",
|
||||
"toastErrorTimeout": "Време за изчакване на известията при грешка",
|
||||
"toastSuccessTimeout": "Време за изчакване на известията при успех",
|
||||
"monitorToastMessagesDescription": "Известието за състояние на монитора изчезва след определено време в секунди. Задаване на -1, деактивира времето за изчакване. Задаване на 0 деактивира тост известията.",
|
||||
"monitorToastMessagesLabel": "Мониторинг на известията при промяна на състоянието",
|
||||
"setupDatabaseEmbeddedMariaDB": "Не е нужно да настройвате нищо. Този Docker имидж автоматично е вградил и конфигурирал MariaDB за Вас. Uptime Kuma ще се свърже с тази база данни чрез Unix сокет.",
|
||||
"setupDatabaseMariaDB": "Свързване към външна MariaDB база данни. Трябва да зададете информацията за връзка с базата данни.",
|
||||
"setupDatabaseSQLite": "Обикновен файл с база данни, препоръчително при маломащабен тип внедрявания. Преди v2.0.0 Uptime Kuma използва SQLite като база данни по подразбиране.",
|
||||
"Bark API Version": "Версия на Bark API",
|
||||
"pushViewCode": "Как да използвате Push монитор? (Вижте кода)",
|
||||
"pushOthers": "Други",
|
||||
"programmingLanguages": "Програмни езици",
|
||||
"authInvalidToken": "Невалиден токен.",
|
||||
"authUserInactiveOrDeleted": "Потребителят е неактивен или изтрит.",
|
||||
"authIncorrectCreds": "Неправилно потребителско име или парола.",
|
||||
"2faAlreadyEnabled": "2FA вече е активирано.",
|
||||
"2faEnabled": "2FA е активирано.",
|
||||
"2faDisabled": "2FA е деактивирано.",
|
||||
"successAdded": "Добавен успешно.",
|
||||
"successPaused": "Успешно поставен на пауза.",
|
||||
"successDeleted": "Успешно изтрит.",
|
||||
"successEdited": "Успешно редактиран.",
|
||||
"successBackupRestored": "Резервното копие е възстановено успешно.",
|
||||
"successDisabled": "Успешно деактивиран.",
|
||||
"successEnabled": "Успешно активиран.",
|
||||
"tagNotFound": "Етикетът не е намерен.",
|
||||
"successResumed": "Успешно възобновен.",
|
||||
"successAuthChangePassword": "Паролата е актуализирана успешно.",
|
||||
"foundChromiumVersion": "Намерен Chromium/Chrome. Версия: {0}"
|
||||
}
|
||||
|
@@ -653,7 +653,7 @@
|
||||
"Server Timezone": "Časové pásmo serveru",
|
||||
"statusPageMaintenanceEndDate": "Konec",
|
||||
"IconUrl": "Adresa URL ikony",
|
||||
"Enable DNS Cache": "Povolit DNS Cache pro HTTP(s) dohledy",
|
||||
"Enable DNS Cache": "(Zastaralé) Povolit DNS Cache pro HTTP(s) dohledy",
|
||||
"Enable": "Povolit",
|
||||
"Disable": "Zakázat",
|
||||
"dnsCacheDescription": "V některých IPv6 prostředích nemusí fungovat. Pokud narazíte na nějaké problémy, tuto možnost vypněte.",
|
||||
@@ -838,5 +838,37 @@
|
||||
"styleElapsedTimeShowWithLine": "Zobrazit (s linkou)",
|
||||
"gamedigGuessPortDescription": "Port používaný protokolem Valve Server Query Protocol se může lišit od portu klienta. Pokud se monitor nemůže připojit k serveru, zkuste to.",
|
||||
"styleElapsedTimeShowNoLine": "Zobrazit (bez linky)",
|
||||
"gamedigGuessPort": "Gamedig: Guess Port"
|
||||
"gamedigGuessPort": "Gamedig: Guess Port",
|
||||
"Saved.": "Uloženo.",
|
||||
"setupDatabaseChooseDatabase": "Kterou databázi chcete použít?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Nemusíte nic nastavovat. Tento Docker obraz pro vás automaticky vložil a nakonfiguroval databázi MariaDB. Uptime Kuma se k této databázi připojí prostřednictvím unixového socketu.",
|
||||
"setupDatabaseMariaDB": "Připojení k externí databázi MariaDB. Je třeba nastavit informace o připojení k databázi.",
|
||||
"setupDatabaseSQLite": "Jednoduchý databázový soubor, doporučený pro malé instalace. Před verzí 2.0.0 používal Uptime Kuma jako výchozí databázi SQLite.",
|
||||
"dbName": "Název databáze",
|
||||
"enableNSCD": "Povolit NSCD (Name Service Cache Daemon) pro cachování všech DNS požadavků",
|
||||
"toastErrorTimeout": "Časový limit pro oznámení o chybách",
|
||||
"toastSuccessTimeout": "Časový limit pro oznámení o úspěchu",
|
||||
"Bark API Version": "Verze API Bark",
|
||||
"authInvalidToken": "Neplatný token.",
|
||||
"2faAlreadyEnabled": "2FA je již aktivní.",
|
||||
"2faEnabled": "2FA aktivní.",
|
||||
"2faDisabled": "2FA neaktivní.",
|
||||
"successResumed": "Úspěšně obnoveno.",
|
||||
"successPaused": "Úspěšně pozastaveno.",
|
||||
"successDeleted": "Úspěšně smazáno.",
|
||||
"successEdited": "Úspěšně upraveno.",
|
||||
"successBackupRestored": "Záloha byla úspěšně obnovena.",
|
||||
"successDisabled": "Úspěšně zakázáno.",
|
||||
"successEnabled": "Úspěšně povoleno.",
|
||||
"tagNotFound": "Štítek nebyl nalezen.",
|
||||
"foundChromiumVersion": "Nalezeno Chromium/Chrom. Verze: {0}",
|
||||
"authUserInactiveOrDeleted": "Uživatel je neaktivní nebo smazaný.",
|
||||
"authIncorrectCreds": "Nesprávné uživatelské jméno nebo heslo.",
|
||||
"successAdded": "Úspěšně přidáno.",
|
||||
"successAuthChangePassword": "Heslo bylo úspěšně aktualizováno.",
|
||||
"pushOthers": "Ostatní",
|
||||
"programmingLanguages": "Programovací jazyky",
|
||||
"monitorToastMessagesLabel": "Upozornění Monitor Toast",
|
||||
"monitorToastMessagesDescription": "Upozornění Toast zmizí po uplynutí nastaveného času. Časový limit vypnete nastavením -1. Upozornění vypnete nastavením 0.",
|
||||
"pushViewCode": "Jak používat Push monitor? (Zobrazit kód)"
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"languageName": "Danish (Danmark)",
|
||||
"languageName": "Dansk",
|
||||
"Settings": "Indstillinger",
|
||||
"Dashboard": "Betjeningspanel",
|
||||
"New Update": "Opdatering tilgængelig",
|
||||
@@ -8,10 +8,10 @@
|
||||
"Theme": "Tema",
|
||||
"General": "Generelt",
|
||||
"Version": "Version",
|
||||
"Check Update On GitHub": "Tjek efter opdateringer på Github",
|
||||
"Check Update On GitHub": "Tjek efter opdateringer på GitHub",
|
||||
"List": "Liste",
|
||||
"Add": "Tilføj",
|
||||
"Add New Monitor": "Tilføj ny Overvåger",
|
||||
"Add New Monitor": "Tilføj ny overvågning",
|
||||
"Quick Stats": "Oversigt",
|
||||
"Up": "Aktiv",
|
||||
"Down": "Inaktiv",
|
||||
@@ -25,7 +25,7 @@
|
||||
"Message": "Beskeder",
|
||||
"No important events": "Ingen vigtige begivenheder",
|
||||
"Resume": "Fortsæt",
|
||||
"Edit": "Rediger",
|
||||
"Edit": "Redigér",
|
||||
"Delete": "Slet",
|
||||
"Current": "Aktuelt",
|
||||
"Uptime": "Oppetid",
|
||||
@@ -37,7 +37,7 @@
|
||||
"checkEverySecond": "Tjek hvert {0} sekund",
|
||||
"Response": "Respons",
|
||||
"Ping": "Ping",
|
||||
"Monitor Type": "Overvåger type",
|
||||
"Monitor Type": "Overvågningstype",
|
||||
"Keyword": "Nøgleord",
|
||||
"Friendly Name": "Visningsnavn",
|
||||
"URL": "URL",
|
||||
@@ -47,7 +47,7 @@
|
||||
"Retries": "Gentagelser",
|
||||
"retriesDescription": "Maksimalt antal gentagelser, før tjenesten markeres som inaktiv og sender en meddelelse.",
|
||||
"Advanced": "Avanceret",
|
||||
"ignoreTLSError": "Ignorere TLS/SSL web fejl",
|
||||
"ignoreTLSError": "Ignorér TLS/SSL fejl for HTTPS websteder",
|
||||
"Upside Down Mode": "Omvendt tilstand",
|
||||
"upsideDownModeDescription": "Håndter tilstanden omvendt. Hvis tjenesten er tilgængelig, vises den som inaktiv.",
|
||||
"Max. Redirects": "Maks. Omdirigeringer",
|
||||
@@ -69,17 +69,17 @@
|
||||
"Search Engine Visibility": "Søgemaskine synlighed",
|
||||
"Allow indexing": "Tillad indeksering",
|
||||
"Discourage search engines from indexing site": "Frabed søgemaskiner at indeksere webstedet",
|
||||
"Change Password": "Ændre adgangskode",
|
||||
"Change Password": "Skift adgangskode",
|
||||
"Current Password": "Nuværende adgangskode",
|
||||
"New Password": "Ny adgangskode",
|
||||
"Repeat New Password": "Gentag den nye adgangskode",
|
||||
"passwordNotMatchMsg": "Adgangskoderne er ikke ens.",
|
||||
"Update Password": "Opdater adgangskode",
|
||||
"Disable Auth": "Deaktiver autentificering",
|
||||
"Enable Auth": "Aktiver autentificering",
|
||||
"Update Password": "Opdatér adgangskode",
|
||||
"Disable Auth": "Deaktivér autentifikation",
|
||||
"Enable Auth": "Aktivér autentifikation",
|
||||
"Logout": "Log ud",
|
||||
"notificationDescription": "Tildel underretninger til Overvåger(e), så denne funktion træder i kraft.",
|
||||
"Leave": "Verlassen",
|
||||
"Leave": "Forlad",
|
||||
"I understand, please disable": "Jeg er indforstået, deaktiver venligst",
|
||||
"Confirm": "Bekræft",
|
||||
"Yes": "Ja",
|
||||
@@ -88,7 +88,7 @@
|
||||
"Password": "Adgangskode",
|
||||
"Remember me": "Husk mig",
|
||||
"Login": "Log ind",
|
||||
"No Monitors, please": "Ingen Overvågere",
|
||||
"No Monitors, please": "Ingen overvågninger",
|
||||
"add one": "tilføj en",
|
||||
"Notification Type": "Underretningstype",
|
||||
"Email": "E-Mail",
|
||||
@@ -101,7 +101,7 @@
|
||||
"Resolver Server": "Navne-server",
|
||||
"rrtypeDescription": "Vælg den type RR, du vil overvåge.",
|
||||
"Last Result": "Seneste resultat",
|
||||
"pauseMonitorMsg": "Er du sikker på, at du vil standse Overvågeren?",
|
||||
"pauseMonitorMsg": "Er du sikker på at du vil standse overvågningen?",
|
||||
"Create your admin account": "Opret din administratorkonto",
|
||||
"Repeat Password": "Gentag adgangskoden",
|
||||
"Resource Record Type": "Resource Record Type",
|
||||
@@ -130,14 +130,14 @@
|
||||
"confirmEnableTwoFAMsg": "Er du sikker på at du vil aktivere 2FA?",
|
||||
"confirmDisableTwoFAMsg": "Er du sikker på at du vil deaktivere 2FA?",
|
||||
"Apply on all existing monitors": "Anvend på alle eksisterende overvågere",
|
||||
"Verify Token": "Verificere Token",
|
||||
"Verify Token": "Bekræft nøgle",
|
||||
"Setup 2FA": "Opsæt 2FA",
|
||||
"Enable 2FA": "Aktiver 2FA",
|
||||
"Disable 2FA": "Deaktiver 2FA",
|
||||
"2FA Settings": "2FA Indstillinger",
|
||||
"Two Factor Authentication": "To-Faktor Autentificering",
|
||||
"Active": "Aktive",
|
||||
"Inactive": "Inaktive",
|
||||
"Active": "Aktiv",
|
||||
"Inactive": "Inaktiv",
|
||||
"Token": "Token",
|
||||
"Show URI": "Vis URI",
|
||||
"Clear all statistics": "Ryd alle Statistikker",
|
||||
@@ -145,16 +145,16 @@
|
||||
"importHandleDescription": "Vælg 'Spring over eksisterende', hvis du vil springe over hver overvåger eller underretning med samme navn. 'Overskriv' sletter alle eksisterende overvågere og underretninger.",
|
||||
"confirmImportMsg": "Er du sikker på at importere sikkerhedskopien? Sørg for, at du har valgt den rigtige importindstilling.",
|
||||
"Heartbeat Retry Interval": "Hjerteslag gentagelsesinterval",
|
||||
"Import Backup": "Importer Backup",
|
||||
"Export Backup": "Eksporter Backup",
|
||||
"Import Backup": "Importér Backup",
|
||||
"Export Backup": "Eksportér Backup",
|
||||
"Skip existing": "Spring over eksisterende",
|
||||
"Overwrite": "Overskriv",
|
||||
"Options": "Valgmuligheder",
|
||||
"Keep both": "Behold begge",
|
||||
"Tags": "Etiketter",
|
||||
"Add New below or Select...": "Tilføj Ny nedenfor eller Vælg…",
|
||||
"Tag with this name already exist.": "Et Tag med dette navn findes allerede.",
|
||||
"Tag with this value already exist.": "Et Tag med denne værdi findes allerede.",
|
||||
"Tag with this name already exist.": "En etiket med dette navn findes allerede.",
|
||||
"Tag with this value already exist.": "En etiket med denne værdi findes allerede.",
|
||||
"color": "farve",
|
||||
"value (optional)": "værdi (valgfri)",
|
||||
"Gray": "Grå",
|
||||
@@ -175,8 +175,8 @@
|
||||
"Partially Degraded Service": "Delvist forringet service",
|
||||
"Degraded Service": "Forringet service",
|
||||
"Add Group": "Tilføj Gruppe",
|
||||
"Add a monitor": "Tilføj en Overvåger",
|
||||
"Edit Status Page": "Rediger Statusside",
|
||||
"Add a monitor": "Tilføj en overvågning",
|
||||
"Edit Status Page": "Redigér Statusside",
|
||||
"Go to Dashboard": "Gå til Betjeningspanel",
|
||||
"Status Page": "Statusside",
|
||||
"Status Pages": "Statusside",
|
||||
@@ -228,7 +228,7 @@
|
||||
"wayToGetDiscordURL": "Du kan få dette ved at gå til Serverindstillinger -> Integrationer -> Opret webhook",
|
||||
"Bot Display Name": "Bot Visningsnavn",
|
||||
"Prefix Custom Message": "Præfiks Brugerdefineret Besked",
|
||||
"Hello @everyone is...": "Hello {'@'}everyone is...",
|
||||
"Hello @everyone is...": "Hej {'@'}alle er…",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"wayToGetTeamsURL": "Du kan lære, hvordan du laver en webhook URL {0}.",
|
||||
"Number": "Nummer",
|
||||
@@ -239,7 +239,7 @@
|
||||
"Application Token": "Program Token",
|
||||
"Server URL": "Server URL",
|
||||
"Priority": "Prioritet",
|
||||
"Icon Emoji": "Icon Emoji",
|
||||
"Icon Emoji": "Ikon Emoji",
|
||||
"Channel Name": "Kanalnavn",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||
"aboutWebhooks": "Mere info om Webhooks på: {0}",
|
||||
@@ -271,8 +271,8 @@
|
||||
"Read more": "Læs mere",
|
||||
"appriseInstalled": "Apprise er installeret.",
|
||||
"appriseNotInstalled": "Apprise er ikke installeret. {0}",
|
||||
"Access Token": "Access Token",
|
||||
"Channel access token": "kanaladgangstoken",
|
||||
"Access Token": "Adgangsnøgle",
|
||||
"Channel access token": "Kanal adgangsnøgle",
|
||||
"Line Developers Console": "Line Udviklerkonsol",
|
||||
"lineDevConsoleTo": "Line Udviklerkonsol - {0}",
|
||||
"Basic Settings": "Basisindstillinger",
|
||||
@@ -300,7 +300,7 @@
|
||||
"PushUrl": "Push URL",
|
||||
"HeadersInvalidFormat": "\"request headers\"-erne er ikke gyldige JSON: ",
|
||||
"BodyInvalidFormat": "\"request body\"-en er ikke gyldige JSON: ",
|
||||
"Monitor History": "Overvåger Historik",
|
||||
"Monitor History": "Overvågningshistorik",
|
||||
"clearDataOlderThan": "Gem overvågningshistorikdata i {0} dage.",
|
||||
"PasswordsDoNotMatch": "Adgangskoderne stemmer ikke overens.",
|
||||
"records": "forekomster",
|
||||
@@ -337,7 +337,7 @@
|
||||
"Show Tags": "Vis Etiketter",
|
||||
"Hide Tags": "Skjul Etiketter",
|
||||
"Description": "Beskrivelse",
|
||||
"No monitors available.": "No monitors available.",
|
||||
"No monitors available.": "Ingen tilgængelige overvågninger.",
|
||||
"Add one": "Tilføj en",
|
||||
"No Monitors": "Ingen Overvågere",
|
||||
"Untitled Group": "Unavngivet Gruppe",
|
||||
@@ -360,7 +360,7 @@
|
||||
"From Name/Number": "Fra Navn/Nummer",
|
||||
"Help": "Hjælp",
|
||||
"Please use this option carefully!": "Brug venligst denne funktion med forsigtighed!",
|
||||
"disableauth.message1": "Er du sikker på, at du vil <strong>deaktivere authentication</strong>?",
|
||||
"disableauth.message1": "Er du sikker på, at du vil <strong>deaktivere autentifikation</strong>?",
|
||||
"successMessage": "Succesmeddelelse",
|
||||
"error": "fejl",
|
||||
"critical": "kritisk",
|
||||
@@ -386,15 +386,15 @@
|
||||
"Notification Service": "Notifikationstjeneste",
|
||||
"Domain": "Domæne",
|
||||
"Google Analytics ID": "Google Analytics ID",
|
||||
"Edit Tag": "Ændre Tag",
|
||||
"Edit Tag": "Redigér etiket",
|
||||
"Learn More": "Lær mere",
|
||||
"Schedule maintenance": "Planlæg vedligeholdelse",
|
||||
"Invalid": "Ugyldig",
|
||||
"User": "Bruger",
|
||||
"Installed": "Installeret",
|
||||
"Not installed": "Ikke installeret",
|
||||
"Running": "Køre",
|
||||
"Not running": "Køre ikke",
|
||||
"Running": "Kører",
|
||||
"Not running": "Kører ikke",
|
||||
"Remove Token": "Fjern Token",
|
||||
"Start": "Start",
|
||||
"Stop": "Stop",
|
||||
@@ -412,7 +412,7 @@
|
||||
"Trust Proxy": "Trust Proxy",
|
||||
"For example: nginx, Apache and Traefik.": "For eksempel: nginx, Apache og Traefik.",
|
||||
"Please read": "Læs venligst",
|
||||
"Show Powered By": "Vis Powered By",
|
||||
"Show Powered By": "Vis Drevet af",
|
||||
"Domain Names": "Domænenavne",
|
||||
"signedInDisp": "Logget ind som {0}",
|
||||
"Certificate Expiry Notification": "Meddelelse om udløbsdato for certifikatet",
|
||||
@@ -448,7 +448,7 @@
|
||||
"loadingError": "Kan ikke hente dataene, prøv igen senere.",
|
||||
"Custom": "Brugerdefineret",
|
||||
"Monitor": "Overvåger | Overvågere",
|
||||
"Specific Monitor Type": "Specifik monitor-type",
|
||||
"Specific Monitor Type": "Specifik overvågningstype",
|
||||
"topic": "Emne",
|
||||
"Fingerprint:": "Fingerprint:",
|
||||
"Issuer:": "Udsteder:",
|
||||
@@ -472,23 +472,23 @@
|
||||
"Display Timezone": "Vis tidszone",
|
||||
"Server Timezone": "Serverens tidszone",
|
||||
"IconUrl": "Ikon URL",
|
||||
"Enable DNS Cache": "Aktiver DNS Cache",
|
||||
"Enable": "Aktiver",
|
||||
"Disable": "Deaktiver",
|
||||
"Enable DNS Cache": "Aktivér DNS Cache",
|
||||
"Enable": "Aktivér",
|
||||
"Disable": "Deaktivér",
|
||||
"dnsCacheDescription": "Det fungerer muligvis ikke i alle IPv6-miljøer, så deaktiver det, hvis du støder på problemer.",
|
||||
"Maintenance Time Window of a Day": "Tidsvindue for vedligeholdelse af en dag",
|
||||
"Schedule Maintenance": "Planlæg vedligeholdelse",
|
||||
"Date and Time": "Dato og klokkeslæt",
|
||||
"plugin": "Plugin | Plugins",
|
||||
"install": "Installer",
|
||||
"uninstall": "Afinstaller",
|
||||
"install": "Installér",
|
||||
"uninstall": "Afinstallér",
|
||||
"uninstalling": "Afinstallerer",
|
||||
"confirmUninstallPlugin": "Er du sikker på, at du vil afinstallere dette plugin?",
|
||||
"installing": "Installerer",
|
||||
"markdownSupported": "Markdown syntax understøttet",
|
||||
"Affected Monitors": "Berørte monitors",
|
||||
"Affected Monitors": "Berørte overvågninger",
|
||||
"All Status Pages": "Alle statussider",
|
||||
"Pick Affected Monitors...": "Vælg berørte monitors…",
|
||||
"Pick Affected Monitors...": "Vælg berørte overvågninger…",
|
||||
"Select status pages...": "Vælg statusside…",
|
||||
"proxyDescription": "Proxyer skal være tilknyttet en monitor for at fungere.",
|
||||
"Accept characters:": "Accepter tegn:",
|
||||
@@ -581,5 +581,44 @@
|
||||
"deleteAPIKeyMsg": "Er du sikker på du vil slette denne API nøgle?",
|
||||
"pagertreeDoNothing": "Gør intet",
|
||||
"Start of maintenance": "Start på vedligeholdelse",
|
||||
"Add New Tag": "Tilføj nyt tag"
|
||||
"Add New Tag": "Tilføj ny etiket",
|
||||
"setupDatabaseChooseDatabase": "Hvilken database vil du gerne bruge?",
|
||||
"Saved.": "Gemt.",
|
||||
"authUserInactiveOrDeleted": "Denne bruger er inaktiv eller er blevet slettet.",
|
||||
"webhookBodyPresetOption": "Forudindstilling - {0}",
|
||||
"filterActive": "Aktiv",
|
||||
"filterActivePaused": "På pause",
|
||||
"Select": "Vælg",
|
||||
"selectedMonitorCount": "Valgte: {0}",
|
||||
"chromeExecutableAutoDetect": "Autodetektér",
|
||||
"pushyToken": "Enhedsnøgle",
|
||||
"You can divide numbers with": "Du kan dividere numre med",
|
||||
"alertaEnvironment": "Miljø",
|
||||
"promosmsAllowLongSMS": "Tillad lang SMS",
|
||||
"smseagleToken": "API Adgangsnøgle",
|
||||
"twilioFromNumber": "Fra nummer",
|
||||
"twilioToNumber": "Til nummer",
|
||||
"twilioApiKey": "API nøgle (valgfrit)",
|
||||
"ntfyUsernameAndPassword": "Brugernavn og adgangskode",
|
||||
"lunaseaUserID": "Bruger ID",
|
||||
"lunaseaDeviceID": "Enheds ID",
|
||||
"lunaseaTarget": "Mål",
|
||||
"Expiry": "Udløber",
|
||||
"pushDeerServerDescription": "Efterlad blank for at bruge den officielle server",
|
||||
"Close": "Luk",
|
||||
"Group": "Gruppe",
|
||||
"Device Token": "Enhedsnøgle",
|
||||
"dbName": "Database navn",
|
||||
"Monitor Group": "Overvågningsgruppe",
|
||||
"telegramSendSilently": "Send lydløst",
|
||||
"smseagleRecipientType": "Modtager type",
|
||||
"smseagleRecipient": "Modtager(e) (Adskil med komma)",
|
||||
"statusPageRefreshIn": "Genopfrisk om: {0}",
|
||||
"Home": "Hjem",
|
||||
"tagNotFound": "Etiket blev ikke fundet.",
|
||||
"pushOthers": "Andre",
|
||||
"confirmDeleteTagMsg": "Er du sikker på at du vil slette denne etiket? Overvågninger med denne etiket vil ikke blive slettet.",
|
||||
"resendEveryXTimes": "Gensend hver {0} gang",
|
||||
"resendDisabled": "Gensendelse deaktiveret",
|
||||
"Reconnecting...": "Genforbinder..."
|
||||
}
|
||||
|
@@ -658,7 +658,7 @@
|
||||
"webhookAdditionalHeadersDesc": "Legt zusätzliche Kopfzeilen fest, die mit dem Webhook gesendet werden. Jede Kopfzeile sollte als JSON Schlüssel/Wert definiert werden.",
|
||||
"Packet Size": "Paketgrösse",
|
||||
"IconUrl": "Symbol URL",
|
||||
"Enable DNS Cache": "DNS-Cache für HTTP(s)-Monitore aktivieren",
|
||||
"Enable DNS Cache": "(Veraltet) DNS-Cache für HTTP(s)-Monitore aktivieren",
|
||||
"Help": "Hilfe",
|
||||
"Game": "Spiel",
|
||||
"General Monitor Type": "Allgemeiner Monitortyp",
|
||||
@@ -824,7 +824,7 @@
|
||||
"nostrRelays": "Nostr relays",
|
||||
"nostrRelaysHelp": "Eine Relay-URL pro Zeile",
|
||||
"nostrRecipients": "Öffentliche Schlüssel des Empfängers (npub)",
|
||||
"gamedigGuessPort": "Gamedig: Guess Port",
|
||||
"gamedigGuessPort": "Gamedig: Vermuteter Port",
|
||||
"Request Timeout": "Zeitüberschreitung der Anfrage",
|
||||
"styleElapsedTimeShowNoLine": "Anzeigen (keine Zeile)",
|
||||
"styleElapsedTimeShowWithLine": "Anzeigen (mit Zeile)",
|
||||
@@ -835,5 +835,37 @@
|
||||
"gamedigGuessPortDescription": "Der vom Valve Server Query Protocol verwendete Port kann sich vom Port des Clients unterscheiden. Versuche dies, wenn der Monitor keine Verbindung zum Server herstellen kann.",
|
||||
"timeoutAfter": "Zeitüberschreitung nach {0} Sekunden",
|
||||
"styleElapsedTime": "Verstrichene Zeit unter der Prüfintervallleiste",
|
||||
"Check/Uncheck": "Aktivieren/Deaktivieren"
|
||||
"Check/Uncheck": "Aktivieren/Deaktivieren",
|
||||
"enableNSCD": "Aktiviere NSCD (Name Service Cache Daemon) zur Zwischenspeicherung aller DNS-Anfragen",
|
||||
"setupDatabaseChooseDatabase": "Welche Datenbank möchtest du verwenden?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Du brauchst nichts einzustellen. Dieses Docker-Image hat automatisch eine MariaDB für dich eingerichtet und konfiguriert. Uptime Kuma wird sich mit dieser Datenbank über einen Unix-Socket verbinden.",
|
||||
"dbName": "Datenbank Name",
|
||||
"setupDatabaseMariaDB": "Mit externer MariaDB-Datenbank verbinden. Du musst die Verbindungsinformationen für die Datenbank festlegen.",
|
||||
"setupDatabaseSQLite": "Eine einfache Datenbankdatei, empfohlen für kleinere Bereitstellungen. Vor v2.0.0 verwendete Uptime Kuma SQLite als Standarddatenbank.",
|
||||
"Saved.": "Gespeichert.",
|
||||
"monitorToastMessagesLabel": "Toast-Benachrichtigungen überwachen",
|
||||
"toastSuccessTimeout": "Zeitüberschreitung für Erfolgsbenachrichtigungen",
|
||||
"toastErrorTimeout": "Zeitüberschreitung für Fehlerbenachrichtigungen",
|
||||
"monitorToastMessagesDescription": "Toast-Benachrichtigungen für Monitore verschwinden nach einer bestimmten Zeit in Sekunden. Auf -1 setzen, um die Zeitüberschreitung zu deaktivieren. Der Wert 0 deaktiviert die Toast-Benachrichtigungen.",
|
||||
"Bark API Version": "Bark API Version",
|
||||
"pushViewCode": "Wie verwendet man den Push-Monitor? (Code anzeigen)",
|
||||
"pushOthers": "Sonstige",
|
||||
"programmingLanguages": "Programmiersprachen",
|
||||
"authInvalidToken": "Ungültiges Token.",
|
||||
"authIncorrectCreds": "Falscher Benutzername oder falsches Passwort.",
|
||||
"2faAlreadyEnabled": "2FA ist bereits aktiviert.",
|
||||
"2faEnabled": "2FA ist aktiviert.",
|
||||
"2faDisabled": "2FA ist deaktiviert.",
|
||||
"successResumed": "Erfolgreich wiederaufgenommen.",
|
||||
"successPaused": "Erfolgreich pausiert.",
|
||||
"successDeleted": "Erfolgreich gelöscht.",
|
||||
"successEdited": "Erfolgreich bearbeitet.",
|
||||
"successBackupRestored": "Sicherung erfolgreich wiederhergestellt.",
|
||||
"successEnabled": "Erfolgreich aktiviert.",
|
||||
"tagNotFound": "Tag nicht gefunden.",
|
||||
"foundChromiumVersion": "Gefunden Chromium/Chrome. Version: {0}",
|
||||
"authUserInactiveOrDeleted": "Der Benutzer ist inaktiv oder gelöscht.",
|
||||
"successAdded": "Erfolgreich hinzugefügt.",
|
||||
"successAuthChangePassword": "Das Passwort wurde erfolgreich aktualisiert.",
|
||||
"successDisabled": "Erfolgreich deaktiviert."
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"languageName": "Deutsch (Deutschland)",
|
||||
"languageName": "Englisch",
|
||||
"Settings": "Einstellungen",
|
||||
"Dashboard": "Dashboard",
|
||||
"New Update": "Aktualisierung verfügbar",
|
||||
@@ -253,7 +253,7 @@
|
||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||
"aboutWebhooks": "Weitere Informationen zu Webhooks auf: {0}",
|
||||
"aboutChannelName": "Gebe den Kanalnamen ein in {0} Feld Kanalname, falls du den Webhook-Kanal umgehen möchtest. Ex: #other-channel",
|
||||
"aboutKumaURL": "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird standardmäßig die GitHub Projekt Seite verwendet.",
|
||||
"aboutKumaURL": "Wenn Sie das Feld für die Uptime Kuma URL leer lassen, wird es standardmäßig auf die Projekt-GitHub-Seite gesetzt.",
|
||||
"emojiCheatSheet": "Emoji Cheat Sheet: {0}",
|
||||
"User Key": "Benutzerschlüssel",
|
||||
"Device": "Gerät",
|
||||
@@ -600,7 +600,7 @@
|
||||
"Optional": "Optional",
|
||||
"squadcast": "Squadcast",
|
||||
"SendKey": "SendKey",
|
||||
"SMSManager API Docs": "SMSManager API Dokumente",
|
||||
"SMSManager API Docs": "SMSManager API Dokumente ",
|
||||
"Gateway Type": "Gateway Typ",
|
||||
"SMSManager": "SMSManager",
|
||||
"You can divide numbers with": "Du kannst Zahlen teilen mit",
|
||||
@@ -644,7 +644,7 @@
|
||||
"Help": "Hilfe",
|
||||
"Game": "Spiel",
|
||||
"Custom": "Benutzerdefiniert",
|
||||
"Enable DNS Cache": "DNS-Cache für HTTP(s)-Monitore aktivieren",
|
||||
"Enable DNS Cache": "(Veraltet) Aktivieren Sie den DNS-Cache für HTTP(s)-Überwachungen",
|
||||
"Enable": "Aktivieren",
|
||||
"Disable": "Deaktivieren",
|
||||
"Custom Monitor Type": "Benutzerdefinierter Monitortyp",
|
||||
@@ -821,7 +821,7 @@
|
||||
"pushDeerServerDescription": "Leer lassen um den offiziellen Server zu verwenden",
|
||||
"FlashDuty Severity": "Schweregrad",
|
||||
"nostrRelays": "Nostr relays",
|
||||
"gamedigGuessPort": "Gamedig: Guess Port",
|
||||
"gamedigGuessPort": "Gamedig: Vermuteter Port",
|
||||
"Request Timeout": "Zeitüberschreitung der Anfrage",
|
||||
"styleElapsedTimeShowNoLine": "Anzeigen (keine Zeile)",
|
||||
"Select": "Auswählen",
|
||||
@@ -838,5 +838,37 @@
|
||||
"nostrRecipients": "Öffentliche Schlüssel des Empfängers (npub)",
|
||||
"nostrRecipientsHelp": "npub-Format, eine pro Zeile",
|
||||
"showCertificateExpiry": "Ablauf des Zertifikats anzeigen",
|
||||
"noOrBadCertificate": "Kein/schlechtes Zertifikat"
|
||||
"noOrBadCertificate": "Kein/schlechtes Zertifikat",
|
||||
"enableNSCD": "Aktivieren Sie NSCD (Name Service Cache Daemon) zur Zwischenspeicherung aller DNS-Anfragen",
|
||||
"setupDatabaseChooseDatabase": "Welche Datenbank möchtest du verwenden?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Du brauchst nichts einzustellen. Dieses Docker-Image hat automatisch eine MariaDB für dich eingerichtet und konfiguriert. Uptime Kuma wird sich mit dieser Datenbank über einen Unix-Socket verbinden.",
|
||||
"dbName": "Datenbank Name",
|
||||
"setupDatabaseMariaDB": "Mit externer MariaDB-Datenbank verbinden. Du musst die Verbindungsinformationen für die Datenbank festlegen.",
|
||||
"setupDatabaseSQLite": "Eine einfache Datenbankdatei, empfohlen für kleinere Bereitstellungen. Vor v2.0.0 verwendete Uptime Kuma SQLite als Standarddatenbank.",
|
||||
"Saved.": "Gespeichert.",
|
||||
"toastSuccessTimeout": "Zeitüberschreitung für Erfolgsbenachrichtigungen",
|
||||
"toastErrorTimeout": "Zeitüberschreitung für Fehlerbenachrichtigungen",
|
||||
"monitorToastMessagesLabel": "Toast-Benachrichtigungen überwachen",
|
||||
"monitorToastMessagesDescription": "Toast-Benachrichtigungen für Monitore verschwinden nach einer bestimmten Zeit in Sekunden. Auf -1 setzen, um die Zeitüberschreitung zu deaktivieren. Der Wert 0 deaktiviert die Toast-Benachrichtigungen.",
|
||||
"Bark API Version": "Bark API Version",
|
||||
"pushViewCode": "Wie verwendet man den Push-Monitor? (Code anzeigen)",
|
||||
"pushOthers": "Sonstige",
|
||||
"programmingLanguages": "Programmiersprachen",
|
||||
"authInvalidToken": "Ungültiges Token.",
|
||||
"authIncorrectCreds": "Falscher Benutzername oder falsches Passwort.",
|
||||
"2faAlreadyEnabled": "2FA ist bereits aktiviert.",
|
||||
"2faEnabled": "2FA ist aktiviert.",
|
||||
"2faDisabled": "2FA ist deaktiviert.",
|
||||
"successResumed": "Erfolgreich wiederaufgenommen.",
|
||||
"successPaused": "Erfolgreich pausiert.",
|
||||
"successDeleted": "Erfolgreich gelöscht.",
|
||||
"successEdited": "Erfolgreich bearbeitet.",
|
||||
"successBackupRestored": "Sicherung erfolgreich wiederhergestellt.",
|
||||
"successDisabled": "Erfolgreich deaktiviert.",
|
||||
"successEnabled": "Erfolgreich aktiviert.",
|
||||
"tagNotFound": "Tag nicht gefunden.",
|
||||
"authUserInactiveOrDeleted": "Der Benutzer ist inaktiv oder gelöscht.",
|
||||
"successAdded": "Erfolgreich hinzugefügt.",
|
||||
"successAuthChangePassword": "Das Passwort wurde erfolgreich aktualisiert.",
|
||||
"foundChromiumVersion": "Gefunden Chromium/Chrome. Version: {0}"
|
||||
}
|
||||
|
@@ -1,5 +1,10 @@
|
||||
{
|
||||
"languageName": "English",
|
||||
"setupDatabaseChooseDatabase": "Which database do you want to use?",
|
||||
"setupDatabaseEmbeddedMariaDB": "You don't need to set anything. This docker image have embedded and configured a MariaDB for you automatically. Uptime Kuma will connect to this database via unix socket.",
|
||||
"setupDatabaseMariaDB": "Connect to an external MariaDB database. You need to set the database connection information.",
|
||||
"setupDatabaseSQLite": "A simple database file, recommended for small-scale deployments. Prior to v2.0.0, Uptime Kuma used SQLite as the default database.",
|
||||
"dbName": "Database Name",
|
||||
"Settings": "Settings",
|
||||
"Dashboard": "Dashboard",
|
||||
"Help": "Help",
|
||||
@@ -79,6 +84,9 @@
|
||||
"Push URL": "Push URL",
|
||||
"needPushEvery": "You should call this URL every {0} seconds.",
|
||||
"pushOptionalParams": "Optional parameters: {0}",
|
||||
"pushViewCode": "How to use Push monitor? (View Code)",
|
||||
"pushOthers": "Others",
|
||||
"programmingLanguages": "Programming Languages",
|
||||
"Save": "Save",
|
||||
"Notifications": "Notifications",
|
||||
"Not available, please setup.": "Not available, please setup.",
|
||||
@@ -205,7 +213,12 @@
|
||||
"Content Type": "Content Type",
|
||||
"webhookJsonDesc": "{0} is good for any modern HTTP servers such as Express.js",
|
||||
"webhookFormDataDesc": "{multipart} is good for PHP. The JSON will need to be parsed with {decodeFunction}",
|
||||
"webhookCustomBodyDesc": "Define a custom HTTP Body for the request. Template variables {msg}, {heartbeat}, {monitor} are accepted.",
|
||||
"liquidIntroduction": "Templatability is achieved via the Liquid templating language. Please refer to the {0} for usage instructions. These are the available variables:",
|
||||
"templateMsg": "message of the notification",
|
||||
"templateHeartbeatJSON": "object describing the heartbeat",
|
||||
"templateMonitorJSON": "object describing the monitor",
|
||||
"templateLimitedToUpDownCertNotifications": "only available for UP/DOWN/Certificate expiry notifications",
|
||||
"templateLimitedToUpDownNotifications": "only available for UP/DOWN notifications",
|
||||
"webhookAdditionalHeadersTitle": "Additional Headers",
|
||||
"webhookAdditionalHeadersDesc": "Sets additional headers sent with the webhook. Each header should be defined as a JSON key/value.",
|
||||
"webhookBodyPresetOption": "Preset - {0}",
|
||||
@@ -236,6 +249,7 @@
|
||||
"successMessage": "Success Message",
|
||||
"successMessageExplanation": "MQTT message that will be considered as success",
|
||||
"recent": "Recent",
|
||||
"Reset Token": "Reset Token",
|
||||
"Done": "Done",
|
||||
"Info": "Info",
|
||||
"Security": "Security",
|
||||
@@ -482,7 +496,19 @@
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
"Ignore TLS Error": "Ignore TLS Error",
|
||||
"From Email": "From Email",
|
||||
"emailCustomisableContent": "Customisable content",
|
||||
"smtpLiquidIntroduction": "The following two fields are templatable via the Liquid templating Language. Please refer to the {0} for usage instructions. These are the available variables:",
|
||||
"emailCustomSubject": "Custom Subject",
|
||||
"leave blank for default subject": "leave blank for default subject",
|
||||
"emailCustomBody": "Custom Body",
|
||||
"leave blank for default body": "leave blank for default body",
|
||||
"emailTemplateServiceName": "Service Name",
|
||||
"emailTemplateHostnameOrURL": "Hostname or URL",
|
||||
"emailTemplateStatus": "Status",
|
||||
"emailTemplateMonitorJSON": "object describing the monitor",
|
||||
"emailTemplateHeartbeatJSON": "object describing the heartbeat",
|
||||
"emailTemplateMsg": "message of the notification",
|
||||
"emailTemplateLimitedToUpDownNotification": "only available for UP/DOWN heartbeats, otherwise null",
|
||||
"To Email": "To Email",
|
||||
"smtpCC": "CC",
|
||||
"smtpBCC": "BCC",
|
||||
@@ -623,6 +649,7 @@
|
||||
"TemplateCode": "TemplateCode",
|
||||
"SignName": "SignName",
|
||||
"Sms template must contain parameters: ": "Sms template must contain parameters: ",
|
||||
"Bark API Version": "Bark API Version",
|
||||
"Bark Endpoint": "Bark Endpoint",
|
||||
"Bark Group": "Bark Group",
|
||||
"Bark Sound": "Bark Sound",
|
||||
@@ -782,6 +809,10 @@
|
||||
"Badge URL": "Badge URL",
|
||||
"Group": "Group",
|
||||
"Monitor Group": "Monitor Group",
|
||||
"monitorToastMessagesLabel": "Monitor Toast notifications",
|
||||
"monitorToastMessagesDescription": "Toast notifications for monitors disappear after given time in seconds. Set to -1 disables timeout. Set to 0 disables toast notifications.",
|
||||
"toastErrorTimeout": "Timeout for Error Notifications",
|
||||
"toastSuccessTimeout": "Timeout for Success Notifications",
|
||||
"Kafka Brokers": "Kafka Brokers",
|
||||
"Enter the list of brokers": "Enter the list of brokers",
|
||||
"Press Enter to add broker": "Press Enter to add broker",
|
||||
@@ -799,8 +830,8 @@
|
||||
"noGroupMonitorMsg": "Not Available. Create a Group Monitor First.",
|
||||
"Close": "Close",
|
||||
"Request Body": "Request Body",
|
||||
"wayToGetFlashDutyKey":"You can go to Channel -> (Select a Channel) -> Integrations -> Add a new integration' page, add a 'Custom Event' to get a push address, copy the Integration Key in the address. For more information, please visit",
|
||||
"FlashDuty Severity":"Severity",
|
||||
"wayToGetFlashDutyKey": "You can go to Channel -> (Select a Channel) -> Integrations -> Add a new integration' page, add a 'Custom Event' to get a push address, copy the Integration Key in the address. For more information, please visit",
|
||||
"FlashDuty Severity": "Severity",
|
||||
"nostrRelays": "Nostr relays",
|
||||
"nostrRelaysHelp": "One relay URL per line",
|
||||
"nostrSender": "Sender Private Key (nsec)",
|
||||
@@ -809,5 +840,24 @@
|
||||
"showCertificateExpiry": "Show Certificate Expiry",
|
||||
"noOrBadCertificate": "No/Bad Certificate",
|
||||
"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."
|
||||
"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.",
|
||||
"Saved.": "Saved.",
|
||||
"authUserInactiveOrDeleted": "The user is inactive or deleted.",
|
||||
"authInvalidToken": "Invalid Token.",
|
||||
"authIncorrectCreds": "Incorrect username or password.",
|
||||
"2faAlreadyEnabled": "2FA is already enabled.",
|
||||
"2faEnabled": "2FA Enabled.",
|
||||
"2faDisabled": "2FA Disabled.",
|
||||
"successAdded": "Added Successfully.",
|
||||
"successResumed": "Resumed Successfully.",
|
||||
"successPaused": "Paused Successfully.",
|
||||
"successDeleted": "Deleted Successfully.",
|
||||
"successEdited": "Edited Successfully.",
|
||||
"successAuthChangePassword": "Password has been updated successfully.",
|
||||
"successBackupRestored": "Backup successfully restored.",
|
||||
"successDisabled": "Disabled Successfully.",
|
||||
"successEnabled": "Enabled Successfully.",
|
||||
"tagNotFound": "Tag not found.",
|
||||
"foundChromiumVersion": "Found Chromium/Chrome. Version: {0}",
|
||||
"GrafanaOncallUrl": "Grafana Oncall URL"
|
||||
}
|
||||
|
@@ -270,7 +270,7 @@
|
||||
"Display Timezone": "Mostrar Zona Horaria",
|
||||
"Server Timezone": "Servidor de Zona Horaria",
|
||||
"statusPageMaintenanceEndDate": "Finaliza",
|
||||
"Enable DNS Cache": "Habilitar Cache DNS de monitores HTTP(s)",
|
||||
"Enable DNS Cache": "(Obsoleto) Habilitar caché DNS para monitores HTTP(s)",
|
||||
"No Maintenance": "Sin Mantenimiento",
|
||||
"weekdayShortSun": "Dom",
|
||||
"dayOfWeek": "Día de la Semana",
|
||||
@@ -556,11 +556,11 @@
|
||||
"affectedMonitorsDescription": "Selecciona los monitores que se ven afectados por el mantenimiento actual",
|
||||
"affectedStatusPages": "Muestra este mensaje de mantenimiento en las páginas de estado seleccionadas",
|
||||
"atLeastOneMonitor": "Selecciona al menos un monitor afectado",
|
||||
"endpoint": "punto final",
|
||||
"endpoint": "endpoint",
|
||||
"promosmsPassword": "Contraseña API",
|
||||
"pushoversounds pushover": "Pushover (predeterminado)",
|
||||
"pushoversounds bike": "Bicicleta",
|
||||
"pushoversounds bugle": "Bugle",
|
||||
"pushoversounds bugle": "Trompeta",
|
||||
"pushoversounds cashregister": "Caja Registradora",
|
||||
"pushoversounds classical": "Clásica",
|
||||
"pushoversounds cosmic": "Cósmico",
|
||||
@@ -653,18 +653,18 @@
|
||||
"gorush": "Gorush",
|
||||
"squadcast": "Squadcast",
|
||||
"Maintenance Time Window of a Day": "Ventana de tiempo de mantenimiento de un día",
|
||||
"Effective Date Range": "Rango de Fecha Efectivo (Opcional)",
|
||||
"Effective Date Range": "Rango de Fecha Vigente (Opcional)",
|
||||
"Free Mobile User Identifier": "Identificador de Usuario de Free Mobile",
|
||||
"Gateway Type": "Tipo de Puerta de Enlace",
|
||||
"Gateway Type": "Tipo de puerta de enlace",
|
||||
"SMSManager": "SMSManager",
|
||||
"goAlertInfo": "GoAlert es una aplicación de código abierto para la programación de guardias, escaladas automatizadas y notificaciones (como SMS o llamadas de voz). ¡Involucre automáticamente a la persona adecuada, de la manera correcta y en el momento adecuado! {0}",
|
||||
"Free Mobile API Key": "Clave API de Free Mobile",
|
||||
"high": "alto",
|
||||
"SMSManager API Docs": "Documentación API de SMSManager ",
|
||||
"smseagleContact": "Nombre(s) de contacto de Guía Telefónica",
|
||||
"smseagleContact": "Nombre(s) de contacto en la guía telefónica",
|
||||
"smseagleToken": "Token de Acceso a la API",
|
||||
"smseagleUrl": "URL del dispositivo SMSEagle",
|
||||
"Legacy Octopush-DM": "Octopush-DM heredado",
|
||||
"Legacy Octopush-DM": "Octopush-DM (legacy)",
|
||||
"HomeAssistant": "Home Assistant",
|
||||
"goAlertIntegrationKeyInfo": "Obtenga la clave de integración API genérica para el servicio en este formato \"aaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\", generalmente el valor del parámetro token de la URL copiada.",
|
||||
"Topic": "Tema",
|
||||
@@ -676,23 +676,23 @@
|
||||
"alertaRecoverState": "Estado de Recuperación",
|
||||
"serwersms": "SerwerSMS.pl",
|
||||
"serwersmsAPIUser": "Nombre de usuario de API (inc. webapi_ prefix)",
|
||||
"smseagleGroup": "Nombre(s) de grupo de Guía Telefónica",
|
||||
"smseagleGroup": "Nombre/s del grupo de la guía telefónica",
|
||||
"Unpin": "Dejar de Fijar",
|
||||
"Prefix Custom Message": "Prefijo personalizado",
|
||||
"markdownSupported": "Sintaxis de Markdown soportada",
|
||||
"Server Address": "Dirección del Servidor",
|
||||
"Learn More": "Aprende Más",
|
||||
"Pick a RR-Type...": "Seleccione un Tipo RR",
|
||||
"Pick a RR-Type...": "Seleccione un Tipo RR…",
|
||||
"onebotHttpAddress": "Dirección HTTP OneBot",
|
||||
"SendKey": "Clave de Envío",
|
||||
"octopushAPIKey": "\"Clave API\" desde credenciales API HTTP en panel de control",
|
||||
"octopushLogin": "\"Inicio de Sesión\" a partir de las credenciales API HTTP en el panel de control",
|
||||
"octopushLogin": "\"Inicio de sesión\" desde credenciales API HTTP en panel de control",
|
||||
"ntfy Topic": "Tema ntfy",
|
||||
"Google Analytics ID": "ID Analíticas de Google",
|
||||
"Edit Tag": "Editar Etiqueta",
|
||||
"SignName": "Firma",
|
||||
"Bark Endpoint": "Endpoint Bark",
|
||||
"WebHookUrl": "WebHookUrl",
|
||||
"WebHookUrl": "URL del WebHook",
|
||||
"High": "Alto",
|
||||
"alertaApiEndpoint": "Endpoint API",
|
||||
"Body Encoding": "Codificación del cuerpo",
|
||||
@@ -700,7 +700,7 @@
|
||||
"Expiry": "Expiración",
|
||||
"API Keys": "Claves API",
|
||||
"Key Added": "Clave añadida",
|
||||
"Add Another": "Añadir otro",
|
||||
"Add Another": "Agregar otro/a",
|
||||
"Continue": "Continuar",
|
||||
"Don't expire": "No caduca",
|
||||
"apiKey-inactive": "Inactivo",
|
||||
@@ -713,7 +713,7 @@
|
||||
"cloneOf": "Clon de {0}",
|
||||
"pagertreeDoNothing": "No hacer nada",
|
||||
"pagertreeResolve": "Resolución automática",
|
||||
"pagertreeCritical": "Crítico",
|
||||
"pagertreeCritical": "Crítico/a",
|
||||
"pagertreeHigh": "Alto",
|
||||
"pagertreeMedium": "Medio",
|
||||
"pagertreeLow": "Bajo",
|
||||
@@ -728,7 +728,7 @@
|
||||
"telegramMessageThreadIDDescription": "Opcional Identificador único para el hilo de mensajes de destino (asunto) del foro; solo para supergrupos de foros",
|
||||
"telegramProtectContent": "Proteger Forwarding/Saving",
|
||||
"telegramProtectContentDescription": "Si se activa, los mensajes del bot en Telegram estarán protegidos contra el reenvío y el guardado.",
|
||||
"notificationRegional": "Regional",
|
||||
"notificationRegional": "Regionales",
|
||||
"Clone Monitor": "Clonar Monitor",
|
||||
"telegramSendSilently": "Enviar en silencio",
|
||||
"telegramSendSilentlyDescription": "Envía el mensaje en silencio. Los usuarios recibirán una notificación sin sonido.",
|
||||
@@ -747,7 +747,7 @@
|
||||
"cronSchedule": "Cronograma: ",
|
||||
"invalidCronExpression": "Expresión Cron invalida:{0}",
|
||||
"statusPageRefreshIn": "Reinicio en: {0}",
|
||||
"twilioAuthToken": "Token de Autentificación",
|
||||
"twilioAuthToken": "Token de autenticación / Secreto de clave API",
|
||||
"ntfyUsernameAndPassword": "Nombre de Usuario y Contraseña",
|
||||
"ntfyAuthenticationMethod": "Método de Autenticación",
|
||||
"Cannot connect to the socket server": "No se puede conectar al servidor socket",
|
||||
@@ -766,5 +766,88 @@
|
||||
"filterActivePaused": "Pausado",
|
||||
"Home": "Inicio",
|
||||
"Expected Value": "Valor esperado",
|
||||
"Json Query": "Consulta Json"
|
||||
"Json Query": "Consulta Json",
|
||||
"invertKeywordDescription": "Comprobar si la palabra clave está ausente en vez de presente.",
|
||||
"enableNSCD": "Habilitar NSCD (Demonio de Caché de Servicio de Nombres) para almacenar en caché todas las solicitudes DNS",
|
||||
"jsonQueryDescription": "Realiza una consulta JSON contra la respuesta y verifica el valor esperado (el valor de retorno se convertirá a una cadena para la comparación). Consulta <a href='https://jsonata.org/'>jsonata.org</a> para obtener documentación sobre el lenguaje de consulta. Puede encontrar un espacio de prueba <a href='https://try.jsonata.org/'>aquí</a>.",
|
||||
"Request Timeout": "Tiempo de espera máximo de petición",
|
||||
"timeoutAfter": "Expirar después de {0} segundos",
|
||||
"chromeExecutableDescription": "Para usuarios de Docker, si Chromium no está instalado, puede que tarde unos minutos en ser instalado y mostrar el resultado de la prueba. Usa 1GB de espacio.",
|
||||
"chromeExecutable": "Ejecutable de Chrome/Chromium",
|
||||
"Monitor Setting": "Ajustes del monitor de {0}",
|
||||
"Show Clickable Link": "Mostrar enlace clickeable",
|
||||
"Open Badge Generator": "Abrir generador de insignias",
|
||||
"Badge Generator": "Generador de insignias de {0}",
|
||||
"Badge Type": "Tipo de insignia",
|
||||
"Badge Label": "Etiqueta de la insignia",
|
||||
"Badge Label Color": "Color de la etiqueta de la insignia",
|
||||
"Badge Color": "Color de la insignia",
|
||||
"Badge Label Prefix": "Prefijo de la etiqueta de insignia",
|
||||
"Badge Preview": "Vista previa de la insignia",
|
||||
"Badge Up Color": "Color de la insignia superior",
|
||||
"Badge Down Color": "Color de la insignia inferior",
|
||||
"Badge Pending Color": "Color de la insignia pendiente",
|
||||
"Badge Maintenance Color": "Color de mantenimiento de la insignia",
|
||||
"Badge Warn Days": "Días de advertencia de insignia",
|
||||
"Badge Down Days": "Días sin insignia",
|
||||
"Badge Style": "Estilo de insignia",
|
||||
"Badge URL": "URL de la insignia",
|
||||
"Group": "Grupo",
|
||||
"Monitor Group": "Grupo de Monitoreo",
|
||||
"Kafka Brokers": "Brokers de Kafka",
|
||||
"Enter the list of brokers": "Ingrese a la lista de brokers",
|
||||
"Press Enter to add broker": "Presione Enter para agregar un broker",
|
||||
"Kafka Topic Name": "Nombre del tema Kafka",
|
||||
"Kafka Producer Message": "Mensaje del Productor de Kafka",
|
||||
"Enable Kafka SSL": "Habilitar Kafka SSL",
|
||||
"Kafka SASL Options": "Opciones de Kafka SASL",
|
||||
"Mechanism": "Mecanismo",
|
||||
"Pick a SASL Mechanism...": "Elija un mecanismo SASL...",
|
||||
"Authorization Identity": "Identidad de autorización",
|
||||
"AccessKey Id": "ID de clave de acceso",
|
||||
"Secret AccessKey": "Secreto de la clave de acceso",
|
||||
"Session Token": "Token de sesión",
|
||||
"Close": "Cerrar",
|
||||
"Request Body": "Cuerpo de solicitud",
|
||||
"FlashDuty Severity": "Gravedad",
|
||||
"nostrRelays": "Relays de Nostr",
|
||||
"nostrRelaysHelp": "Una URL de retransmisión por línea",
|
||||
"nostrSender": "Clave Privada del remitente (nsec)",
|
||||
"nostrRecipients": "Claves públicas de destinatarios (npub)",
|
||||
"nostrRecipientsHelp": "formato npub, uno por línea",
|
||||
"showCertificateExpiry": "Mostrar caducidad del certificado",
|
||||
"noOrBadCertificate": "Certificado Nulo/Incorrecto",
|
||||
"aboutNotifyChannel": "Notificar canal activará una notificación de escritorio o móvil para todos los miembros del canal, ya sea que su disponibilidad esté activa o ausente.",
|
||||
"Server URL should not contain the nfty topic": "La URL del servidor no debe contener el tema nfty",
|
||||
"PushDeer Server": "Servidor PushDeer",
|
||||
"pushDeerServerDescription": "Dejar en blanco para usar el servidor oficial",
|
||||
"Badge Duration (in hours)": "Duración de la insignia (en horas)",
|
||||
"Badge Prefix": "Prefijo del valor de la insignia",
|
||||
"Badge Suffix": "Sufijo del valor de la insignia",
|
||||
"Badge Label Suffix": "Sufijo de la etiqueta de insignia",
|
||||
"Badge Warn Color": "Color de advertencia de insignia",
|
||||
"Badge value (For Testing only.)": "Valor de la insignia (Solo para pruebas.)",
|
||||
"Enable Kafka Producer Auto Topic Creation": "Habilitar la Creación Automática de Temas del Productor de Kafka",
|
||||
"noGroupMonitorMsg": "No disponible. Cree primero un monitor de grupo.",
|
||||
"wayToGetFlashDutyKey": "Puede ir a Canal -> (Seleccionar un canal) -> Integraciones -> Agregar una nueva página de integración, agregar un 'Evento personalizado' para obtener una dirección push, copiar la clave de integración en la dirección. Para mayor información por favor visite",
|
||||
"gamedigGuessPort": "Gamedig: Adivinar el puerto",
|
||||
"gamedigGuessPortDescription": "El puerto utilizado por Valve Server Query Protocol puede ser diferente del puerto del cliente. Pruebe esto si el monitor no puede conectarse a su servidor.",
|
||||
"twilioApiKey": "Clave de la API (opcional)",
|
||||
"styleElapsedTime": "Tiempo transcurrido en la barra de latidos",
|
||||
"styleElapsedTimeShowNoLine": "Mostrar (sin línea)",
|
||||
"styleElapsedTimeShowWithLine": "Mostrar (Con línea)",
|
||||
"webhookCustomBodyDesc": "Define un cuerpo HTTP personalizado para la petición. Las variables que puedes usar como plantillas son {msg}, {heartbeat}, y {monitor}.",
|
||||
"webhookBodyPresetOption": "Preajuste- {0}",
|
||||
"tailscalePingWarning": "Para utilizar el monitor Tailscale Ping, debe instalar Uptime Kuma sin Docker y también instalar el cliente Tailscale en su servidor.",
|
||||
"Bark API Version": "Versión de la API Bark",
|
||||
"monitorToastMessagesDescription": "Las notificaciones Toast para monitores desaparecen después de un tiempo dado en segundos. Establecer a -1 desactiva el tiempo de espera. Si se establece en 0, se desactivan las notificaciones.",
|
||||
"Saved.": "Guardado.",
|
||||
"monitorToastMessagesLabel": "Monitorizar las notificaciones Toast",
|
||||
"toastSuccessTimeout": "Tiempo de espera para notificaciones de éxito",
|
||||
"toastErrorTimeout": "Tiempo de espera para notificaciones de error",
|
||||
"setupDatabaseChooseDatabase": "¿Qué base de datos desea utilizar?",
|
||||
"setupDatabaseEmbeddedMariaDB": "No necesitas configurar nada. Esta imagen docker ha incrustado y configurado un MariaDB para ti automáticamente. Uptime Kuma se conectará a esta base de datos a través de un socket unix.",
|
||||
"setupDatabaseMariaDB": "Conectarse a una base de datos MariaDB externa. Debe configurar la información de conexión a la base de datos.",
|
||||
"setupDatabaseSQLite": "Un archivo de base de datos simple, recomendado para despliegues a pequeña escala. Antes de la versión 2.0.0, Uptime Kuma utilizaba SQLite como base de datos predeterminada.",
|
||||
"dbName": "Nombre de la base de datos"
|
||||
}
|
||||
|
@@ -672,7 +672,7 @@
|
||||
"Server Timezone": "منطقه زمانی در سرور",
|
||||
"statusPageMaintenanceEndDate": "پایان",
|
||||
"IconUrl": "URL آیکون",
|
||||
"Enable DNS Cache": "فعال سازی کش DNS برای مانیتور های HTTP",
|
||||
"Enable DNS Cache": "(منسوخ شده) فعال سازی کش DNS برای مانیتور های HTTP",
|
||||
"Access Token": "توکن دسترسی",
|
||||
"smtp": "ایمیل (SMTP)",
|
||||
"Device": "دستگاه",
|
||||
@@ -808,5 +808,37 @@
|
||||
"noOrBadCertificate": "بدون سرتیفیکت یا بد",
|
||||
"Invert Keyword": "کلمه کلیدی معکوس",
|
||||
"Expected Value": "مقدار مورد انتظار",
|
||||
"Json Query": "کوئری جیسون"
|
||||
"Json Query": "کوئری جیسون",
|
||||
"Saved.": "ذخیره شده.",
|
||||
"setupDatabaseChooseDatabase": "از چه دیتابیسی میخواهید استفاده کنید؟",
|
||||
"setupDatabaseEmbeddedMariaDB": "شما نیازی نیست چیزی را تنظیم کنید . این Image داکر یک MariaDB را به طور خودکار برای شما جاسازی و پیکربندی کرده است. آپتایم کوما از طریق سوکت یونیکس به این دیتابیس متصل می شود.",
|
||||
"setupDatabaseSQLite": "یک فایل دیتابیس ساده که برای استقرار در مقیاس کوچک توصیه می شود. قبل از نسخه 2.0.0، Uptime Kuma از SQLite به عنوان دیتابیس پیش فرض استفاده می کرد.",
|
||||
"enableNSCD": "فعال سازی NSCD (Name Service Cache Daemon) برای کش کردن تمام ریکوئست های DNS",
|
||||
"setupDatabaseMariaDB": "به یک دیتابیس خارجی MariaDB متصل شوید. شما باید اطلاعات اتصال دیتابیس را تنظیم کنید.",
|
||||
"dbName": "نام دیتابیس",
|
||||
"Bark API Version": "نسخه API Bark",
|
||||
"monitorToastMessagesDescription": "پیام های Toasy برای مانیتورها پس از زمان معین در چند ثانیه ناپدید میشوند. با تنظیم آن بر روی -1 باعث غیرفعال شدن مهلت زمانی می شود. تنظیم بر روی 0 پیام های Toastرا غیرفعال میکند.",
|
||||
"monitorToastMessagesLabel": "پیام های Monitor Toast",
|
||||
"toastErrorTimeout": "تایم اوت برای پیام های خطا",
|
||||
"toastSuccessTimeout": "تایم اوت برای پیام های موفقیت آمیز",
|
||||
"authInvalidToken": "توکن نامعتبر است.",
|
||||
"authIncorrectCreds": "نام کاربری یا رمز عبور اشتباه است.",
|
||||
"2faEnabled": "تایید دو مرحله ای فعال است.",
|
||||
"2faDisabled": "تایید دو مرحله ای غیرفعال است.",
|
||||
"successPaused": "با موفقیت متوقف شد.",
|
||||
"successDeleted": "با موفقیت حذف شد.",
|
||||
"successEdited": "با موفقیت ویرایش شد.",
|
||||
"successBackupRestored": "بکاپ با موفقیت بازیابی شد.",
|
||||
"successDisabled": "با موفقیت غیرفعال شد.",
|
||||
"successEnabled": "با موفقیت فعال شد.",
|
||||
"tagNotFound": "برچسب پیدا نشد.",
|
||||
"foundChromiumVersion": "کرومیوم/کروم پیدا شد. نسخه: {0}",
|
||||
"pushViewCode": "چگونه از پوش مانیتور استفاده شود؟ (نگاه به کد)",
|
||||
"programmingLanguages": "زبان های برنامه نویسی",
|
||||
"authUserInactiveOrDeleted": "کاربر غیرفعال یا حذف شده است.",
|
||||
"2faAlreadyEnabled": "تایید دومرحله ای قبلاً فعال شده است.",
|
||||
"successAdded": "با موفقیت اضافه شد.",
|
||||
"successResumed": "با موفقیت از سر گرفته شد.",
|
||||
"successAuthChangePassword": "رمز عبور با موفقیت به روز رسانی شد.",
|
||||
"pushOthers": "غیره"
|
||||
}
|
||||
|
@@ -650,7 +650,7 @@
|
||||
"Server Timezone": "Fuseau horaire du serveur",
|
||||
"statusPageMaintenanceEndDate": "Fin",
|
||||
"IconUrl": "URL vers l'icône",
|
||||
"Enable DNS Cache": "Activer le cache DNS pour les sondes HTTP(s)",
|
||||
"Enable DNS Cache": "(Obsolète) Activer le cache DNS pour les sondes HTTP(s)",
|
||||
"Enable": "Activer",
|
||||
"Disable": "Désactiver",
|
||||
"dnsCacheDescription": "Il peut ne pas fonctionner dans certains environnements IPv6, désactivez-le si vous rencontrez des problèmes.",
|
||||
@@ -677,7 +677,7 @@
|
||||
"infiniteRetention": "Définissez la valeur à 0 pour une durée de conservation infinie.",
|
||||
"Monitor": "Sonde | Sondes",
|
||||
"Custom": "Personnalisé",
|
||||
"confirmDeleteTagMsg": "Voulez-vous vraiment supprimer cette étiquettes ? Les moniteurs associés ne seront pas supprimés.",
|
||||
"confirmDeleteTagMsg": "Voulez-vous vraiment supprimer cette étiquette ? Les sondes associées ne seront pas supprimées.",
|
||||
"promosmsAllowLongSMS": "Autoriser les longs SMS",
|
||||
"Help": "Aide",
|
||||
"Game": "Jeux",
|
||||
@@ -752,7 +752,7 @@
|
||||
"ntfyAuthenticationMethod": "Méthode d'authentification",
|
||||
"pushoverMessageTtl": "TTL Message (Secondes)",
|
||||
"Show Clickable Link": "Afficher le lien cliquable",
|
||||
"Show Clickable Link Description": "Si cette case est cochée, tous ceux qui ont accès à cette page d'état peuvent accéder à l'URL du moniteur.",
|
||||
"Show Clickable Link Description": "Si cette case est cochée, tous ceux qui ont accès à cette page d'état peuvent accéder à l'URL de la sonde.",
|
||||
"Open Badge Generator": "Ouvrir le générateur de badges",
|
||||
"Badge Type": "Type de badge",
|
||||
"Badge Duration": "Durée du badge",
|
||||
@@ -834,9 +834,41 @@
|
||||
"wayToGetFlashDutyKey": "Vous pouvez aller dans Canal -> (Sélectionner un canal) -> Intégrations -> Ajouter une nouvelle page d'intégration, ajouter un \"événement personnalisé\" pour obtenir une adresse push, copier la clé d'intégration dans l'adresse. Pour plus d'informations, veuillez visiter",
|
||||
"Request Timeout": "Délai d'expiration de la demande",
|
||||
"timeoutAfter": "Délai dépassé après {0} secondes",
|
||||
"gamedigGuessPort": "Gamedig: Devinez le port",
|
||||
"gamedigGuessPort": "Gamedig : Devinez le port",
|
||||
"gamedigGuessPortDescription": "Le port utilisé par Valve Server Query Protocol peut être différent du port client. Essayez ceci si la sonde ne peut pas se connecter à votre serveur.",
|
||||
"styleElapsedTimeShowNoLine": "Afficher (pas de ligne)",
|
||||
"styleElapsedTimeShowWithLine": "Afficher (avec ligne)",
|
||||
"styleElapsedTime": "Temps écoulé sous la barre d'état"
|
||||
"styleElapsedTime": "Temps écoulé sous la barre d'état",
|
||||
"enableNSCD": "Activer NSCD (Name Service Cache Daemon) pour mettre en cache toutes les demandes DNS",
|
||||
"setupDatabaseChooseDatabase": "Quelle base de données souhaitez-vous utiliser ?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Vous n'avez pas besoin de régler quoi que ce soit. Cette image docker a intégré et configuré automatiquement une MariaDB pour vous. Uptime Kuma se connectera à cette base de données via la socket unix.",
|
||||
"setupDatabaseSQLite": "Un fichier de base de données simple, recommandé pour les déploiements à petite échelle. Avant la v2.0.0, Uptime Kuma utilisait SQLite comme base de données par défaut.",
|
||||
"setupDatabaseMariaDB": "Connectez-vous à une base de données MariaDB externe. Vous devez définir les informations de connexion à la base de données.",
|
||||
"dbName": "Nom de la base de données",
|
||||
"Saved.": "Enregistré.",
|
||||
"toastErrorTimeout": "Délai d'attente pour les notifications d'erreur",
|
||||
"toastSuccessTimeout": "Délai d'attente pour les notifications de réussite",
|
||||
"monitorToastMessagesLabel": "Surveiller les notifications Toast",
|
||||
"monitorToastMessagesDescription": "Les notifications Toast pour les sondes disparaissent après un délai donné en secondes. La valeur -1 désactive le délai d'attente. La valeur 0 désactive les notifications toast.",
|
||||
"Bark API Version": "Version de l'API Bark",
|
||||
"pushViewCode": "Comment utiliser une sonde type « Push » (voir le code)",
|
||||
"pushOthers": "Autres",
|
||||
"programmingLanguages": "Langages de programmation",
|
||||
"authInvalidToken": "Jeton invalide.",
|
||||
"authIncorrectCreds": "Nom d'utilisateur ou mot de passe incorrects.",
|
||||
"2faAlreadyEnabled": "L'authentification à deux facteurs (2FA) est déjà activée.",
|
||||
"2faDisabled": "Authentification à deux facteurs (2FA) désactivée.",
|
||||
"successAdded": "Ajouté avec succès.",
|
||||
"successEdited": "Modifié avec succès.",
|
||||
"successBackupRestored": "Sauvegarde restaurée avec succès.",
|
||||
"successDisabled": "Désactivé avec succès.",
|
||||
"successEnabled": "Activé avec succès.",
|
||||
"tagNotFound": "Étiquette non trouvée.",
|
||||
"foundChromiumVersion": "Version de Chromium/Chrome trouvée : {0}",
|
||||
"successResumed": "Reprise avec succès.",
|
||||
"successPaused": "Mis en pause avec succès.",
|
||||
"authUserInactiveOrDeleted": "L'utilisateur est inactif ou a été supprimé.",
|
||||
"2faEnabled": "Authentification à deux facteurs (2FA) activée.",
|
||||
"successDeleted": "Supprimé avec succès.",
|
||||
"successAuthChangePassword": "Le mot de passe a bien été mis à jour."
|
||||
}
|
||||
|
@@ -102,7 +102,7 @@
|
||||
"Enable Auth": "Omogući autentikaciju",
|
||||
"disableauth.message1": "Jeste li sigurni da želite <strong>isključiti autentikaciju</strong>?",
|
||||
"disableauth.message2": "To je za <strong>korisnike koji imaju vanjsku autentikaciju stranice</strong> ispred Uptime Kume, poput usluge Cloudflare Access.",
|
||||
"Please use this option carefully!": "Pažljivo koristite ovu opciju.",
|
||||
"Please use this option carefully!": "Pažljivo koristite ovu opciju!",
|
||||
"Logout": "Odjava",
|
||||
"Leave": "Poništi",
|
||||
"I understand, please disable": "Razumijem, svejedno onemogući",
|
||||
@@ -158,8 +158,8 @@
|
||||
"Token": "Token",
|
||||
"Show URI": "Pokaži URI",
|
||||
"Tags": "Oznake",
|
||||
"Add New below or Select...": "Dodajte novu oznaku ispod ili odaberite...",
|
||||
"Tag with this name already exist.": "Oznaka s tim nazivom već postoji",
|
||||
"Add New below or Select...": "Dodajte novu oznaku ispod ili odaberite…",
|
||||
"Tag with this name already exist.": "Oznaka s tim nazivom već postoji.",
|
||||
"Tag with this value already exist.": "Oznaka s tom vrijednošću već postoji.",
|
||||
"color": "Boja",
|
||||
"value (optional)": "Vrijednost (neobavezno)",
|
||||
@@ -171,7 +171,7 @@
|
||||
"Indigo": "Indigo",
|
||||
"Purple": "Ljubičasta",
|
||||
"Pink": "Ružičasta",
|
||||
"Search...": "Pretraga...",
|
||||
"Search...": "Pretraga…",
|
||||
"Avg. Ping": "Prosječni odziv",
|
||||
"Avg. Response": "Prosječni odgovor",
|
||||
"Entry Page": "Početna stranica",
|
||||
@@ -213,10 +213,10 @@
|
||||
"smtpBCC": "Bcc",
|
||||
"discord": "Discord",
|
||||
"Discord Webhook URL": "URL Discord webhooka",
|
||||
"wayToGetDiscordURL": "Ovo možete dobiti tako da odete na Postavke servera -> Integracije -> Napravi webhook",
|
||||
"wayToGetDiscordURL": "Ovo možete dobiti tako da odete na Postavke servera -> Integracije -> Pogledaj webhookove -> Novi webhook",
|
||||
"Bot Display Name": "Nadimak Bota unutar servera",
|
||||
"Prefix Custom Message": "Prefiks prilagođene poruke",
|
||||
"Hello @everyone is...": "Pozdrav {'@'}everyone...",
|
||||
"Hello @everyone is...": "Pozdrav {'@'}everyone…",
|
||||
"teams": "Microsoft Teams",
|
||||
"Webhook URL": "URL webhooka",
|
||||
"wayToGetTeamsURL": "Više informacija o Teams webhookovima možete pročitati {0}.",
|
||||
@@ -315,8 +315,8 @@
|
||||
"Info": "Informacije",
|
||||
"Security": "Sigurnost",
|
||||
"Shrink Database": "Smanji bazu podataka",
|
||||
"Pick a RR-Type...": "Odaberite vrstu DNS zapisa od navedenih...",
|
||||
"Pick Accepted Status Codes...": "Odaberite HTTP statusne kodove koji će biti prihvaćeni...",
|
||||
"Pick a RR-Type...": "Odaberite vrstu DNS zapisa od navedenih…",
|
||||
"Pick Accepted Status Codes...": "Odaberite HTTP statusne kodove koji će biti prihvaćeni…",
|
||||
"Steam API Key": "Steam API ključ",
|
||||
"Default": "Zadano",
|
||||
"HTTP Options": "HTTP Postavke",
|
||||
@@ -348,7 +348,7 @@
|
||||
"Discard": "Odbaci",
|
||||
"Cancel": "Otkaži",
|
||||
"Powered by": "Pokreće",
|
||||
"Saved": "Spremljeno",
|
||||
"Saved.": "Spremljeno.",
|
||||
"PushByTechulus": "Push by Techulus",
|
||||
"GoogleChat": "Google Chat (preko platforme Google Workspace)",
|
||||
"shrinkDatabaseDescription": "Pokreni VACUUM operaciju za SQLite. Ako je baza podataka kreirana nakon inačice 1.10.0, AUTO_VACUUM opcija već je uključena te ova akcija nije nužna.",
|
||||
@@ -385,7 +385,7 @@
|
||||
"successMessageExplanation": "MQTT poruka koja se smatra uspješnom",
|
||||
"error": "greška",
|
||||
"critical": "kritično",
|
||||
"Customize": "Customize",
|
||||
"Customize": "Prilagodi",
|
||||
"Custom Footer": "Prilagođeno podnožje",
|
||||
"Custom CSS": "Prilagođeni CSS",
|
||||
"wayToGetPagerDutyKey": "Ključ možete dobiti odlaskom na \"Service -> Service Directory -> (Odabrani servis) -> Integrations -> Add integration\". Ovdje pretražite za \"Events API V2\". Više informacija {0}",
|
||||
@@ -406,7 +406,7 @@
|
||||
"Certificate Chain": "Lanac certifikata",
|
||||
"Valid": "Važeći",
|
||||
"Invalid": "Nevažeći",
|
||||
"AccessKeyId": "AccessKey ID",
|
||||
"AccessKeyId": "AccessKey identifikator",
|
||||
"SecretAccessKey": "AccessKey tajni ključ",
|
||||
"PhoneNumbers": "Telefonski brojevi",
|
||||
"TemplateCode": "Predložak koda",
|
||||
@@ -415,7 +415,7 @@
|
||||
"Bark Endpoint": "Bark krajnja točka (endpoint)",
|
||||
"Bark Group": "Bark grupa",
|
||||
"Bark Sound": "Bark zvuk",
|
||||
"WebHookUrl": "WebHookUrl",
|
||||
"WebHookUrl": "URL webhooka",
|
||||
"SecretKey": "Tajni ključ",
|
||||
"For safety, must use secret key": "Korištenje tajnog ključa je obavezno",
|
||||
"Device Token": "Token uređaja",
|
||||
@@ -447,7 +447,7 @@
|
||||
"The slug is already taken. Please choose another slug.": "Slug je zauzet. Odaberite novi slug.",
|
||||
"No Proxy": "Bez proxy poslužitelja",
|
||||
"Authentication": "Autentikacija",
|
||||
"HTTP Basic Auth": "HTTP Basic Auth",
|
||||
"HTTP Basic Auth": "HTTP \"Basic\" autentifikacija",
|
||||
"New Status Page": "Dodaj statusnu stranicu",
|
||||
"Page Not Found": "Stranica nije pronađena",
|
||||
"Reverse Proxy": "Reverzni proxy",
|
||||
@@ -497,36 +497,36 @@
|
||||
"Recipient Number": "Broj primatelja",
|
||||
"From Name/Number": "Naziv/broj pošiljatelja",
|
||||
"Leave blank to use a shared sender number.": "Ostaviti prazno za korištenje dijeljenog broja pošiljatelja.",
|
||||
"Octopush API Version": "Octopush verzija API-ja",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"Octopush API Version": "Verzija Octopush API-ja",
|
||||
"Legacy Octopush-DM": "Zastarijela Octopush-DM",
|
||||
"endpoint": "krajnja točka (endpoint)",
|
||||
"octopushAPIKey": "\"API ključ\" iz HTTP API postavki",
|
||||
"octopushAPIKey": "\"API ključ\" iz HTTP API postavki na upravljačkoj ploči",
|
||||
"octopushLogin": "\"Korisničko ime\" iz HTTP API postavki",
|
||||
"promosmsLogin": "API korisničko ime",
|
||||
"promosmsPassword": "API lozinka",
|
||||
"pushoversounds pushover": "Pushover (default)",
|
||||
"pushoversounds bike": "Bike",
|
||||
"pushoversounds bugle": "Bugle",
|
||||
"pushoversounds cashregister": "Cash Register",
|
||||
"pushoversounds pushover": "Pushover (zadano)",
|
||||
"pushoversounds bike": "Bicikl",
|
||||
"pushoversounds bugle": "Truba",
|
||||
"pushoversounds cashregister": "Blagajna",
|
||||
"pushoversounds classical": "Classical",
|
||||
"pushoversounds cosmic": "Cosmic",
|
||||
"pushoversounds falling": "Falling",
|
||||
"pushoversounds cosmic": "Kozmički",
|
||||
"pushoversounds falling": "Padanje",
|
||||
"pushoversounds gamelan": "Gamelan",
|
||||
"pushoversounds incoming": "Incoming",
|
||||
"pushoversounds intermission": "Intermission",
|
||||
"pushoversounds magic": "Magic",
|
||||
"pushoversounds mechanical": "Mechanical",
|
||||
"pushoversounds pianobar": "Piano Bar",
|
||||
"pushoversounds siren": "Siren",
|
||||
"pushoversounds spacealarm": "Space Alarm",
|
||||
"pushoversounds tugboat": "Tug Boat",
|
||||
"pushoversounds alien": "Alien Alarm (long)",
|
||||
"pushoversounds climb": "Climb (long)",
|
||||
"pushoversounds persistent": "Persistent (long)",
|
||||
"pushoversounds echo": "Pushover Echo (long)",
|
||||
"pushoversounds updown": "Up Down (long)",
|
||||
"pushoversounds vibrate": "Vibrate Only",
|
||||
"pushoversounds none": "None (silent)",
|
||||
"pushoversounds incoming": "Dolazno",
|
||||
"pushoversounds intermission": "Intermisija",
|
||||
"pushoversounds magic": "Čarolija",
|
||||
"pushoversounds mechanical": "Mehanički",
|
||||
"pushoversounds pianobar": "Bar s klavirom",
|
||||
"pushoversounds siren": "Sirena",
|
||||
"pushoversounds spacealarm": "Svemirski alarm",
|
||||
"pushoversounds tugboat": "Remorker",
|
||||
"pushoversounds alien": "Vanzemaljski alarm (dugačko)",
|
||||
"pushoversounds climb": "Penjanje (dugačko)",
|
||||
"pushoversounds persistent": "Uporno (dugačko)",
|
||||
"pushoversounds echo": "Pushover jeka (dugačko)",
|
||||
"pushoversounds updown": "Gore-dolje (dugačko)",
|
||||
"pushoversounds vibrate": "Samo vibracija",
|
||||
"pushoversounds none": "Utišano (bez zvuka)",
|
||||
"pushyAPIKey": "Tajni API ključ",
|
||||
"pushyToken": "Token uređaja",
|
||||
"Show update if available": "Pokaži moguću nadogradnju",
|
||||
@@ -575,5 +575,294 @@
|
||||
"Event data:": "Podaci eventa:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Potrebno je i odabrati akciju za izvođenje na Home Assistantu.",
|
||||
"Frontend Version": "Inačica sučelja",
|
||||
"Frontend Version do not match backend version!": "Inačica sučelja ne odgovara poslužitelju!"
|
||||
"Frontend Version do not match backend version!": "Inačica sučelja ne odgovara poslužitelju!",
|
||||
"monitorToastMessagesLabel": "Skočne obavijesti Monitora",
|
||||
"toastSuccessTimeout": "Vrijeme isteka skočnih obavijesti o uspjehu",
|
||||
"toastErrorTimeout": "Vrijeme isteka skočnih obavijesti o pogrešci",
|
||||
"Enter the list of brokers": "Upišite popis brokera",
|
||||
"Press Enter to add broker": "Pritisnite Enter za dodavanje brokera",
|
||||
"Kafka Topic Name": "Naziv Kafka teme",
|
||||
"Kafka Producer Message": "Poruka Kafka producera",
|
||||
"Enable Kafka SSL": "Omogući SSL",
|
||||
"Enable Kafka Producer Auto Topic Creation": "Omogući automatsku izradu teme za Kafka producera",
|
||||
"Kafka SASL Options": "Kafka SASL opcije",
|
||||
"Mechanism": "Mehanizam",
|
||||
"Pick a SASL Mechanism...": "Odaberite SASL mehanizam...",
|
||||
"AccessKey Id": "ID pristupnog ključa",
|
||||
"Secret AccessKey": "Tajni pristupni ključ",
|
||||
"Session Token": "Token sesije",
|
||||
"Schedule maintenance": "Zakaži održavanje",
|
||||
"Select status pages...": "Odaberi statusne stranice…",
|
||||
"webhookAdditionalHeadersTitle": "Dodatna zaglavlja",
|
||||
"webhookAdditionalHeadersDesc": "Postavlja dodatna polja zaglavlja koja se šalju s webhookom. Svako zaglavlje treba se definirati kao JSON par ključ-vrijednost.",
|
||||
"Packet Size": "Veličina paketa",
|
||||
"backupRecommend": "Umjesto toga napravite ručnu sigurnosnu kopiju cijelog volumena ili izravno direktorija s podacima (./data/).",
|
||||
"No Maintenance": "Ne postoje zakazana održavanja",
|
||||
"Server Timezone": "Vremenska zona poslužitelja",
|
||||
"dnsCacheDescription": "Možda ne radi kako spada u nekim IPv6 okruženjima. Onemogućite ako naiđete na probleme.",
|
||||
"Select": "Odaberi",
|
||||
"tailscalePingWarning": "Kako biste koristili Tailscale Ping monitor, trebate instalirati Uptime Kuma bez Dockera te također instalirati Tailscale klijent na svoj poslužitelj.",
|
||||
"telegramProtectContentDescription": "Ako je omogućeno, poruke bota će biti zaštićene od prosljeđivanja i spremanja.",
|
||||
"enableNSCD": "Omogući NSCD (Name Service Cache Daemon) za sve DNS zahtjeve",
|
||||
"chromeExecutableDescription": "Za korisnike Dockera, ako Chromium još nije instaliran, instalacija i prikaz rezultata testa može potrajati nekoliko minuta. Zauzima 1 GB prostora na disku.",
|
||||
"grpcMethodDescription": "Naziv metode automatski se pretvara u camelCase format. Primjerice, \"say hello\" će se pretvoriti u \"sayHello\".",
|
||||
"wayToGetKookBotToken": "Kreirajte aplikaciju i preuzmite token svog bota na {0}",
|
||||
"wayToGetKookGuildID": "Uključite 'Developer Mode' za Kook u postavkama i desnom tipkom miša kliknite na guild kako biste dobili njegov ID",
|
||||
"Lowcost": "Niskotarifni",
|
||||
"SendKey": "Ključ za slanje (SendKey)",
|
||||
"You can divide numbers with": "Možete odvojiti brojeve pomoću",
|
||||
"goAlertInfo": "GoAlert je aplikacija otvorenog koda za zakazivanje poziva, automatiziranu eskalaciju i slanje obavijesti (poput SMS-a ili glasovnih poziva). Automatski obavijestite pravu osobu, na pravi način i u pravo vrijeme! {0}",
|
||||
"smseagleTo": "Broj(evi) telefona",
|
||||
"smseagleGroup": "Nazivi grupa telefonskog imenika",
|
||||
"smseagleRecipient": "Primatelj(i) (višestruke vrijednosti moraju se odvojiti zarezom)",
|
||||
"pushDeerServerDescription": "Ostavite prazno za korištenje službenog poslužitelja",
|
||||
"Edit Tag": "Uredi oznaku",
|
||||
"Expiry date": "Datum isteka",
|
||||
"Schedule Maintenance": "Zakazivanje održavanja",
|
||||
"Edit Maintenance": "Uređivanje održavanja",
|
||||
"uninstall": "Deinstaliraj",
|
||||
"uninstalling": "Deinstalacija",
|
||||
"Badge Type": "Tip značke",
|
||||
"apiKeyAddedMsg": "Vaš API ključ je dodan. Spremite ga sada jer se više neće prikazivati.",
|
||||
"pagertreeDoNothing": "Ne čini ništa",
|
||||
"wayToGetPagerTreeIntegrationURL": "Nakon što stvorite Uptime Kuma integraciju u aplikaciji PagerTree, kopirajte krajnju točku (endpoint). Pogledajte sve pojedinosti {0}",
|
||||
"Show Clickable Link Description": "Ako je označeno, svi koji imaju pristup ovoj statusnoj stranici mogu imati pristup URL-u Monitora.",
|
||||
"monitorToastMessagesDescription": "Skočne obavijesti za monitore nestaju nakon zadanog vremena u sekundama. Vrijednost od -1 onemogućuje vremensko ograničenje, 0 onemogućuje skočne obavijesti.",
|
||||
"Authorization Identity": "Identitet autorizacije",
|
||||
"weekdayShortThu": "Čet",
|
||||
"setupDatabaseChooseDatabase": "Koju bazu podataka želite koristiti?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Ne morate ništa dodatno postavljati. Ovaj docker image ima ugrađenu i konfiguriranu MariaDB bazu podataka za Vas. Uptime Kuma će se spojiti na ovu bazu preko UNIX socketa.",
|
||||
"setupDatabaseMariaDB": "Spojite vanjsku MariaDB bazu podataka. Morate unijeti informacije o konekciji prema bazi.",
|
||||
"setupDatabaseSQLite": "Jednostavna datoteka s bazom podataka, preporuča se samo za manje implementacije. Prije inačice v2.0.0, Uptime Kuma je koristila SQLite kao zadanu bazu podataka.",
|
||||
"dbName": "Naziv baze podataka",
|
||||
"Start of maintenance": "Početak održavanja",
|
||||
"All Status Pages": "Sve statusne stranice",
|
||||
"Affected Monitors": "Zahvaćeni Monitori",
|
||||
"Pick Affected Monitors...": "Odaberi zahvaćene Monitore…",
|
||||
"filterActivePaused": "Pauzirano",
|
||||
"Add New Tag": "Dodaj novu oznaku",
|
||||
"statusPageRefreshIn": "Osvježavanje za: {0}",
|
||||
"webhookCustomBodyDesc": "Prilagodite tijelo HTTP zahtjeva. Dozvoljene varijable predloška: {msg}, {heartbeat}, {monitor}.",
|
||||
"webhookBodyPresetOption": "Unaprijed postavljeno - {0}",
|
||||
"webhookBodyCustomOption": "Prilagođeno tijelo zahtjeva",
|
||||
"selectedMonitorCount": "Odabrano: {0}",
|
||||
"Check/Uncheck": "Označi/odznači",
|
||||
"telegramMessageThreadID": "(Neobavezno) ID dretve poruka",
|
||||
"telegramMessageThreadIDDescription": "Neobavezni jedinstveni identifikator za dretvu poruka (temu) foruma; samo za forumske supergrupe",
|
||||
"telegramSendSilently": "Pošalji nečujno",
|
||||
"telegramSendSilentlyDescription": "Šalje poruku nečujno. Primatelji će dobiti obavijest bez zvuka.",
|
||||
"telegramProtectContent": "Zaštiti od prosljeđivanja i spremanja",
|
||||
"Optional": "Neobavezno",
|
||||
"or": "ili",
|
||||
"weekdayShortTue": "Uto",
|
||||
"weekdayShortWed": "Sri",
|
||||
"weekdayShortFri": "Pet",
|
||||
"weekdayShortSat": "Sub",
|
||||
"dayOfWeek": "Dan u tjednu",
|
||||
"dayOfMonth": "Dan u mjesecu",
|
||||
"lastDay": "Posljednji dan",
|
||||
"lastDay1": "Posljednji dan mjeseca",
|
||||
"lastDay2": "Pretposljednji dan mjeseca",
|
||||
"lastDay3": "Treći do posljednjeg dana u mjesecu",
|
||||
"lastDay4": "Četvrti do posljednjeg dana u mjesecu",
|
||||
"pauseMaintenanceMsg": "Jeste li sigurni da želite pauzirati?",
|
||||
"maintenanceStatus-under-maintenance": "Održavanje u tijeku",
|
||||
"maintenanceStatus-inactive": "Neaktivno",
|
||||
"maintenanceStatus-scheduled": "Zakazano",
|
||||
"maintenanceStatus-ended": "Završeno",
|
||||
"maintenanceStatus-unknown": "Nepoznato",
|
||||
"Display Timezone": "Prikaži vremensku zonu",
|
||||
"statusPageMaintenanceEndDate": "Kraj",
|
||||
"IconUrl": "URL ikone",
|
||||
"Enable": "Omogući",
|
||||
"Disable": "Onemogući",
|
||||
"sameAsServerTimezone": "Ista kao i vremenska zona poslužitelja",
|
||||
"chromeExecutable": "Izvršna datoteka za Chrome/Chromium",
|
||||
"chromeExecutableAutoDetect": "Automatska detekcija",
|
||||
"Single Maintenance Window": "Jednokratno održavanje",
|
||||
"Maintenance Time Window of a Day": "Vrijeme održavanja u danu",
|
||||
"Effective Date Range": "Efektivan raspon datuma (neobavezno)",
|
||||
"Clone": "Kloniraj",
|
||||
"dataRetentionTimeError": "Razdoblje zadržavanja mora biti 0 ili veće",
|
||||
"infiniteRetention": "Postavite na 0 za beskonačno zadržavanje.",
|
||||
"confirmDeleteTagMsg": "Jeste li sigurni da želite izbrisati ovu oznaku? Monitori povezani s ovom oznakom neće biti izbrisani.",
|
||||
"enableGRPCTls": "Omogući sigurno slanje gRPC zahtjeva koristeći TLS",
|
||||
"deleteMaintenanceMsg": "Jeste li sigurni da želite izbrisati ovo održavanje?",
|
||||
"Guild ID": "ID za guild",
|
||||
"pushoverMessageTtl": "Vrijeme isteka poruke (u sekundama)",
|
||||
"Proto Method": "Metoda poziva",
|
||||
"Proto Content": "Proto sadržaj",
|
||||
"Economy": "Ekonomski",
|
||||
"high": "visoko",
|
||||
"SMSManager API Docs": "Dokumentacija SMSManager API-ja ",
|
||||
"Gateway Type": "Tip poveznika (gateway)",
|
||||
"Base URL": "Osnovni URL",
|
||||
"goAlertIntegrationKeyInfo": "Nabavite generički integracijski API ključ za ovu uslugu u formatu \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\", koji je obično vrijednost token parametra kopiranog URL-a.",
|
||||
"aboutNotifyChannel": "Ova opcija će poslati mobilnu ili desktop obavijest za sve članove kanala, bez obzira na to jesu li trenutno dostupni ili ne.",
|
||||
"smseagleContact": "Nazivi kontakata telefonskog imenika",
|
||||
"smseagleRecipientType": "Tip primatelja",
|
||||
"smseagleToken": "Token za pristup API-ju",
|
||||
"smseagleUrl": "URL Vašeg SMSEagle uređaja",
|
||||
"smseagleEncoding": "Pošalji kao Unicode",
|
||||
"smseaglePriority": "Prioritet poruke (0-9, zadana vrijednost je 0)",
|
||||
"Server URL should not contain the nfty topic": "URL poslužitelja ne smije sadržavati temu nfty",
|
||||
"PushDeer Server": "PushDeer poslužitelj",
|
||||
"Custom Monitor Type": "Prilagođeni tip Monitora",
|
||||
"Google Analytics ID": "Google Analytics identifikator",
|
||||
"Server Address": "Adresa poslužitelja",
|
||||
"Learn More": "Saznaj više",
|
||||
"Body Encoding": "Vrsta sadržaja u tijelu zahtjeva",
|
||||
"API Keys": "API ključevi",
|
||||
"Expiry": "Istek",
|
||||
"Don't expire": "Bez isteka",
|
||||
"Continue": "Nastavi",
|
||||
"Add Another": "Dodaj još jedan",
|
||||
"Key Added": "Ključ dodan",
|
||||
"Add API Key": "Dodaj API ključ",
|
||||
"No API Keys": "Nema dodanih API ključeva",
|
||||
"apiKey-active": "Aktivan",
|
||||
"apiKey-expired": "Istekao",
|
||||
"apiKey-inactive": "Neaktivan",
|
||||
"Expires": "Ističe",
|
||||
"disableAPIKeyMsg": "Jeste li sigurni da želite onemogućiti ovaj API ključ?",
|
||||
"Generate": "Generiraj",
|
||||
"pagertreeIntegrationUrl": "URL integracije",
|
||||
"pagertreeUrgency": "Hitnost",
|
||||
"pagertreeSilent": "Utišano",
|
||||
"pagertreeLow": "Niska",
|
||||
"pagertreeMedium": "Srednja",
|
||||
"pagertreeHigh": "Visoka",
|
||||
"pagertreeCritical": "Kritična",
|
||||
"pagertreeResolve": "Automatsko rješavanje",
|
||||
"lunaseaTarget": "Cilj",
|
||||
"lunaseaDeviceID": "ID uređaja",
|
||||
"lunaseaUserID": "Korisnički ID",
|
||||
"ntfyAuthenticationMethod": "Metoda provjere autentičnosti",
|
||||
"ntfyUsernameAndPassword": "Korisničko ime i lozinka",
|
||||
"twilioAccountSID": "SID korisničkog računa",
|
||||
"twilioAuthToken": "Token za autentifikaciju / tajni API ključ",
|
||||
"twilioFromNumber": "Broj pošiljatelja",
|
||||
"twilioToNumber": "Broj primatelja",
|
||||
"Show Clickable Link": "Pokaži poveznicu",
|
||||
"Open Badge Generator": "Otvori generator znački",
|
||||
"Badge Duration (in hours)": "Trajanje značke (u satima)",
|
||||
"Badge Prefix": "Prefiks vrijednosti značke",
|
||||
"Badge Suffix": "Sufiks vrijednosti značke",
|
||||
"Badge Label": "Natpis značke",
|
||||
"Badge Label Color": "Boja natpisa značke",
|
||||
"Badge Color": "Boja značke",
|
||||
"Badge Label Prefix": "Prefiks natpisa značke",
|
||||
"Badge Preview": "Pretpregled značke",
|
||||
"Badge Label Suffix": "Sufiks natpisa značke",
|
||||
"Badge Up Color": "Boja značke za dostupnost",
|
||||
"Badge Down Color": "Boja značke za nedostupnost",
|
||||
"Badge Pending Color": "Boja značke za monitore u tijeku",
|
||||
"Badge Maintenance Color": "Boja značke za monitore u održavanju",
|
||||
"Badge Warn Color": "Boja značke za upozorenje",
|
||||
"Badge Warn Days": "Dani značke za upozorenje",
|
||||
"Badge Down Days": "Dani značke za nedostupnost",
|
||||
"Badge value (For Testing only.)": "Vrijednost značke (samo za testiranje)",
|
||||
"Badge URL": "URL značke",
|
||||
"Group": "Grupa",
|
||||
"Monitor Group": "Grupa Monitora",
|
||||
"Badge Style": "Stil značke",
|
||||
"Custom": "Prilagođeno",
|
||||
"styleElapsedTime": "Vremenske oznake ispod trake dostupnosti",
|
||||
"styleElapsedTimeShowNoLine": "Pokaži (bez linije)",
|
||||
"styleElapsedTimeShowWithLine": "Pokaži (s linijom)",
|
||||
"recurringInterval": "Periodično",
|
||||
"Recurring": "Ponavljajući",
|
||||
"strategyManual": "Ručno aktivan/neaktivan",
|
||||
"warningTimezone": "Koristi vremensku zonu poslužitelja",
|
||||
"weekdayShortMon": "Pon",
|
||||
"weekdayShortSun": "Ned",
|
||||
"startDateTime": "Vrijeme početka",
|
||||
"endDateTime": "Vrijeme završetka",
|
||||
"cronExpression": "Cron izraz",
|
||||
"cronSchedule": "Raspored: ",
|
||||
"invalidCronExpression": "Nevaljali Cron izraz: {0}",
|
||||
"Date and Time": "Datum i vrijeme",
|
||||
"DateTime Range": "Vremenski raspon",
|
||||
"loadingError": "Nije moguće dohvatiti podatke, pokušajte ponovno kasnije.",
|
||||
"plugin": "Dodatak | Dodaci",
|
||||
"install": "Instaliraj",
|
||||
"installing": "Instaliranje",
|
||||
"confirmUninstallPlugin": "Jeste li sigurni da želite deinstalirati ovaj dodatak?",
|
||||
"notificationRegional": "Specifično za regiju",
|
||||
"Clone Monitor": "Kloniraj Monitor",
|
||||
"cloneOf": "Klon monitora {0}",
|
||||
"wayToGetZohoCliqURL": "Možete naučiti kako kreirati URL za webhook {0}.",
|
||||
"affectedMonitorsDescription": "Odaberite monitore koji će biti zahvaćeni održavanjem",
|
||||
"recurringIntervalMessage": "Pokreni jednom svaki dan | Pokreni jednom svakih {0} dana",
|
||||
"affectedStatusPages": "Prikazuje poruku o održavanju na odabranim statusnim stranicama",
|
||||
"atLeastOneMonitor": "Odaberite barem jedan zahvaćeni Monitor",
|
||||
"invertKeywordDescription": "Postavi da ključna riječ mora biti odsutna umjesto prisutna.",
|
||||
"jsonQueryDescription": "Izvršite JSON upit nad primljenim odgovorom i provjerite očekivanu povrtanu vrijednost. Ona će se za usporedbu pretvoriti u niz znakova (string). Pogledajte stranicu <a href='https://jsonata.org/'>jsonata.org</a> za dokumentaciju o jeziku upita. Testno okruženje možete pronaći <a href='https://try.jsonata.org/'>ovdje</a>.",
|
||||
"Strategy": "Strategija",
|
||||
"Free Mobile User Identifier": "Besplatni mobilni korisnički identifikator",
|
||||
"Free Mobile API Key": "Besplatni mobilni ključ za API",
|
||||
"Enable TLS": "Omogući TLS",
|
||||
"Proto Service Name": "Naziv servisa",
|
||||
"promosmsAllowLongSMS": "Dozvoli dugačke SMS-ove",
|
||||
"Notify Channel": "Obavijesti cijeli kanal",
|
||||
"Request Timeout": "Vrijeme isteka zahtjeva",
|
||||
"timeoutAfter": "Istek nakon {0} sekundi",
|
||||
"backupOutdatedWarning": "Zastarjelo: Budući da je dodano puno značajki, a ova je pomalo neodržavana, ne može generirati niti vratiti potpunu sigurnosnu kopiju.",
|
||||
"Enable DNS Cache": "(Zastarijelo) Omogući DNS privremenu memoriju (cache) za HTTP(s) monitore",
|
||||
"Home": "Početna",
|
||||
"deleteAPIKeyMsg": "Jeste li sigurni da želite obrisati ovaj API ključ?",
|
||||
"twilioApiKey": "API ključ (neobavezno)",
|
||||
"Kafka Brokers": "Kafka brokeri",
|
||||
"Game": "Igra",
|
||||
"Passive Monitor Type": "Pasivni tip Monitora",
|
||||
"markdownSupported": "Podržana je Markdown sintaksa",
|
||||
"statusMaintenance": "Održavanje",
|
||||
"General Monitor Type": "Općeniti tip Monitora",
|
||||
"Maintenance": "Održavanje",
|
||||
"Specific Monitor Type": "Određeni tip Monitora",
|
||||
"Monitor": "Monitor | Monitori",
|
||||
"Invert Keyword": "Obrni ključnu riječ",
|
||||
"filterActive": "Aktivnost",
|
||||
"Cannot connect to the socket server": "Nije moguće spojiti se na socket poslužitelj",
|
||||
"Reconnecting...": "Ponovno povezivanje...",
|
||||
"Expected Value": "Očekivana vrijednost",
|
||||
"Json Query": "JSON upit",
|
||||
"Help": "Pomoć",
|
||||
"noGroupMonitorMsg": "Nije dostupno. Prvo kreirajte grupu Monitora.",
|
||||
"Close": "Zatvori",
|
||||
"Request Body": "Tijelo zahtjeva",
|
||||
"wayToGetFlashDutyKey": "Možete otići na 'Channel' -> (Odaberite kanal) -> 'Integrations' -> 'Add a new integration' i odaberite 'Custom Event' da biste dobili push adresu. Zatim kopirajte integracijski ključ u adresu. Za više informacija posjetite",
|
||||
"FlashDuty Severity": "Stupanj ozbiljnosti",
|
||||
"nostrRelays": "Nostr releji",
|
||||
"nostrRelaysHelp": "Jedan URL releja po liniji",
|
||||
"nostrSender": "Privatni ključ pošiljatelja (nsec)",
|
||||
"nostrRecipients": "Javni ključevi primatelja (npub)",
|
||||
"nostrRecipientsHelp": "U formatu npub, jedan ključ po liniji",
|
||||
"showCertificateExpiry": "Pokaži istek certifikata",
|
||||
"noOrBadCertificate": "Nepostojeći ili nevaljali certifikat",
|
||||
"gamedigGuessPort": "Gamedig: Pogodi vrijednost porta",
|
||||
"gamedigGuessPortDescription": "Port koji koristi Valve Server Query Protocol može se razlikovati od klijentskog porta. Pokušajte uključiti ovu opciju ako Monitor ne može uspostaviti vezu s vašim poslužiteljem.",
|
||||
"Monitor Setting": "Postavka monitora korisnika {0}",
|
||||
"Badge Generator": "Generator znački korisnika {0}",
|
||||
"Bark API Version": "Verzija Bark API-ja",
|
||||
"authInvalidToken": "Nevažeći token.",
|
||||
"authIncorrectCreds": "Pogrešno korisničko ime ili lozinka.",
|
||||
"2faAlreadyEnabled": "Dvofaktorska autentifikacija je već omogućena.",
|
||||
"2faDisabled": "Dvofaktorska autentifikacija je onemogućena.",
|
||||
"successAdded": "Uspješno dodano.",
|
||||
"successPaused": "Uspješno pauzirano.",
|
||||
"successEdited": "Uspješno uređeno.",
|
||||
"successAuthChangePassword": "Lozinka je uspješno ažurirana.",
|
||||
"successBackupRestored": "Sigurnosna kopija je uspješno vraćena.",
|
||||
"successDisabled": "Uspješno onemogućeno.",
|
||||
"successEnabled": "Uspješno omogućeno.",
|
||||
"foundChromiumVersion": "Pronađen program Chromium ili Chrome. Inačica: {0}",
|
||||
"pushViewCode": "Kako koristiti Monitor Push? (Prikaži kôd)",
|
||||
"programmingLanguages": "Programski jezici",
|
||||
"authUserInactiveOrDeleted": "Korisnik je neaktivan ili obrisan.",
|
||||
"2faEnabled": "Dvofaktorska autentifikacija je omogućena.",
|
||||
"successResumed": "Uspješno nastavljeno.",
|
||||
"successDeleted": "Uspješno obrisano.",
|
||||
"tagNotFound": "Oznaka nije pronađena.",
|
||||
"pushOthers": "Ostali"
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@
|
||||
"confirmDisableTwoFAMsg": "Apakah Anda yakin ingin menonaktifkan 2FA?",
|
||||
"Settings": "Pengaturan",
|
||||
"Dashboard": "Dasbor",
|
||||
"New Update": "Update terbaru",
|
||||
"New Update": "Pembaruan Baru",
|
||||
"Language": "Bahasa",
|
||||
"Appearance": "Tampilan",
|
||||
"Theme": "Tema",
|
||||
@@ -584,7 +584,7 @@
|
||||
"Game": "Permainan",
|
||||
"markdownSupported": "Dukungan sintaks markdown",
|
||||
"statusMaintenance": "Pemeliharaan",
|
||||
"Maintenance": "Pemeliharaan",
|
||||
"Maintenance": "Tidak Ada Pemeliharaan",
|
||||
"General Monitor Type": "Tipe Monitor Umum",
|
||||
"Passive Monitor Type": "Tipe Monitor Pasif",
|
||||
"Specific Monitor Type": "Tipe Monitor Spesifik",
|
||||
@@ -788,5 +788,10 @@
|
||||
"Badge Pending Color": "Warna Lencana Tertunda",
|
||||
"Monitor Group": "Monitor Grup",
|
||||
"Expected Value": "Value yang diharapkan",
|
||||
"Json Query": "Json Query"
|
||||
"Json Query": "Json Query",
|
||||
"setupDatabaseSQLite": "File database sederhana, direkomendasikan untuk penerapan skala kecil. Sebelum v2.0.0, Uptime Kuma menggunakan SQLite sebagai database default.",
|
||||
"setupDatabaseMariaDB": "Hubungkan ke database MariaDB eksternal. Anda perlu mengatur informasi koneksi database.",
|
||||
"setupDatabaseEmbeddedMariaDB": "Anda tidak perlu mengatur apa pun. Docker Image ini telah menyematkan dan mengonfigurasi MariaDB untuk Anda secara otomatis. Uptime Kuma akan terhubung ke database ini melalui soket unix.",
|
||||
"setupDatabaseChooseDatabase": "Database mana yang ingin Anda gunakan?",
|
||||
"dbName": "Nama Database"
|
||||
}
|
||||
|
@@ -610,5 +610,6 @@
|
||||
"Expected Value": "Valore atteso",
|
||||
"Json Query": "Query Json",
|
||||
"deleteMaintenanceMsg": "Sei sicuro di voler cancellare questa attività di manutenzione?",
|
||||
"dnsPortDescription": "Porta server DNS. Default 53. Puoi cambiare questa porta in ogni momento."
|
||||
"dnsPortDescription": "Porta server DNS. Default 53. Puoi cambiare questa porta in ogni momento.",
|
||||
"setupDatabaseChooseDatabase": "Quale database vuoi usare?"
|
||||
}
|
||||
|
@@ -552,5 +552,18 @@
|
||||
"Lowcost": "低コスト",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "通知サービスの一覧からデバイス名を見つけるには、Home Assistantの「開発者ツール > サービス」から通知で検索してください。",
|
||||
"Notify Channel": "通知チャンネル",
|
||||
"Icon Emoji": "絵文字アイコン"
|
||||
"Icon Emoji": "絵文字アイコン",
|
||||
"setupDatabaseChooseDatabase": "どのデータベースを利用しますか?",
|
||||
"setupDatabaseEmbeddedMariaDB": "何も設定する必要はありません。この Docker イメージは設定済みの MariaDB が組み込まれています。Uptime Kuma はこのデータベースに unix ソケットを通じて接続します。",
|
||||
"setupDatabaseSQLite": "小規模な開発のために推奨される小さなデータベースファイルです。v2.0.0 以前は、Uptime Kuma は SQLite を標準のデータベースとして使用していました。",
|
||||
"tailscalePingWarning": "Tailscale Ping モニターを使用するためには、Uptime Kuma を Docker を利用せずインストールし、そのうえで Tailscale Client をサーバーにインストールしてください。",
|
||||
"invertKeywordDescription": "キーワードが含まれているものではなく、含まれないものを探します。",
|
||||
"setupDatabaseMariaDB": "外部の MariaDB データベースに接続するためには、データベースの接続情報を設定する必要があります。",
|
||||
"dbName": "データベース名",
|
||||
"Request Timeout": "リクエストタイムアウト",
|
||||
"timeoutAfter": "{0} 秒後にタイムアウト",
|
||||
"selectedMonitorCount": "選択済み: {0}",
|
||||
"Long-Lived Access Token": "Long-Lived Access Token",
|
||||
"Invert Keyword": "「含まない」キーワード",
|
||||
"Expected Value": "期待値"
|
||||
}
|
||||
|
@@ -54,7 +54,7 @@
|
||||
"Delete": "삭제",
|
||||
"Current": "현재",
|
||||
"Uptime": "업타임",
|
||||
"Cert Exp.": "인증서 만료",
|
||||
"Cert Exp.": "인증서 만료.",
|
||||
"day": "일",
|
||||
"-day": "-일",
|
||||
"hour": "시간",
|
||||
@@ -84,7 +84,7 @@
|
||||
"Theme - Heartbeat Bar": "테마 - 하트비트 바",
|
||||
"Normal": "기본값",
|
||||
"Bottom": "가운데",
|
||||
"None": "없애기",
|
||||
"None": "없음",
|
||||
"Timezone": "시간대",
|
||||
"Search Engine Visibility": "검색 엔진 활성화",
|
||||
"Allow indexing": "인덱싱 허용",
|
||||
@@ -749,5 +749,15 @@
|
||||
"lunaseaDeviceID": "기기 ID",
|
||||
"statusPageRefreshIn": "{0} 후 새로고침",
|
||||
"telegramMessageThreadIDDescription": "포럼의 대상 메시지 쓰레드(주제)에 대한 선택적 고유 식별인, 포럼 관리자 그룹에만 해당",
|
||||
"pagertreeSilent": "없음"
|
||||
"pagertreeSilent": "없음",
|
||||
"setupDatabaseChooseDatabase": "어떤 데이터베이스를 사용하시겠습니까?",
|
||||
"setupDatabaseEmbeddedMariaDB": "추가 설정은 필요 없습니다. 이 도커 이미지는 MariaDB가 내장되어 구성되어 있습니다. Uptime Kuma는 Unix Socket을 통해 데이터베이스에 연결합니다.",
|
||||
"setupDatabaseMariaDB": "외부 MariaDB 데이터베이스에 연결합니다. 데이터베이스 연결 정보를 설정해야 합니다.",
|
||||
"setupDatabaseSQLite": "소규모 배포에 권장되는 간단한 데이터베이스 파일입니다. v2.0.0 이전에는 Uptime Kuma가 SQLite를 기본 데이터베이스로 사용했습니다.",
|
||||
"dbName": "데이터베이스 이름",
|
||||
"filterActive": "활성화",
|
||||
"filterActivePaused": "일시중지",
|
||||
"Home": "홈",
|
||||
"Cannot connect to the socket server": "소켓 서버에 연결 할 수 없습니다",
|
||||
"Reconnecting...": "재 연결중..."
|
||||
}
|
||||
|
@@ -24,5 +24,30 @@
|
||||
"Dashboard": "Papan pemuka",
|
||||
"Language": "Bahasa",
|
||||
"Add New Monitor": "Tambah monitor baharu",
|
||||
"Passive Monitor Type": "Jenis monitor pasif"
|
||||
"Passive Monitor Type": "Jenis monitor pasif",
|
||||
"No Services": "Tiada Servis",
|
||||
"Add a monitor": "Tambah Monitor",
|
||||
"High": "Tinggi",
|
||||
"Normal": "Biasa",
|
||||
"Bottom": "Bawah",
|
||||
"None": "None",
|
||||
"All Systems Operational": "Semua Sistem Baik",
|
||||
"Partially Degraded Service": "Perkhidmatan Separa Tergendala",
|
||||
"Degraded Service": "Perkhidmatan Tergendala",
|
||||
"Add Group": "Tambah Kumpulan",
|
||||
"Edit Status Page": "Ubah Laman Status",
|
||||
"Go to Dashboard": "Ke Dashboard",
|
||||
"Status Page": "Laman Status",
|
||||
"Status Pages": "Laman Status",
|
||||
"Avg. Ping": "Ping Purata",
|
||||
"Avg. Response": "Respons Purata",
|
||||
"color": "Warna",
|
||||
"Active": "Aktif",
|
||||
"Inactive": "Nyahaktif",
|
||||
"Blue": "Biru",
|
||||
"Red": "MErah",
|
||||
"Content Type": "Jenis Content",
|
||||
"Home": "Laman Utama",
|
||||
"Settings": "Tetapan",
|
||||
"Save": "Simpan"
|
||||
}
|
||||
|
@@ -659,7 +659,7 @@
|
||||
"Disable": "Wyłącz",
|
||||
"Date and Time": "Data i czas",
|
||||
"IconUrl": "URL ikony",
|
||||
"Enable DNS Cache": "Włącz pamięć podręczną DNS dla monitorów HTTP",
|
||||
"Enable DNS Cache": "(Przestarzałe) Włącz pamięć podręczną DNS dla monitorów HTTP",
|
||||
"Single Maintenance Window": "Pojedyncze okno konserwacji",
|
||||
"Effective Date Range": "Zakres dat obowiązywania (opcjonalnie)",
|
||||
"Schedule Maintenance": "Planowanie konserwacji",
|
||||
@@ -838,5 +838,37 @@
|
||||
"noOrBadCertificate": "Brak/zły certyfikat",
|
||||
"Invert Keyword": "Odwróć słowo kluczowe",
|
||||
"Expected Value": "Oczekiwana wartość",
|
||||
"Json Query": "Zapytanie Json"
|
||||
"Json Query": "Zapytanie Json",
|
||||
"enableNSCD": "Włącz NSCD (Name Service Cache Daemon) do buforowania wszystkich żądań DNS",
|
||||
"Saved.": "Zapisano.",
|
||||
"setupDatabaseChooseDatabase": "Której bazy danych chcesz użyć?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Nie musisz niczego ustawiać. Ten obraz docker automatycznie osadził i skonfigurował MariaDB. Uptime Kuma połączy się z tą bazą danych za pośrednictwem gniazda Unix.",
|
||||
"setupDatabaseMariaDB": "Połącz z zewnętrzną bazą danych MariaDB. Należy ustawić informacje o połączeniu z bazą danych.",
|
||||
"setupDatabaseSQLite": "Prosty plik bazy danych, zalecany do wdrożeń na małą skalę. Przed wersją 2.0.0 Uptime Kuma używała SQLite jako domyślnej bazy danych.",
|
||||
"dbName": "Nazwa bazy danych",
|
||||
"toastErrorTimeout": "Limit czasu dla powiadomień o błędach",
|
||||
"monitorToastMessagesLabel": "Powiadomienie Toast Monitora",
|
||||
"monitorToastMessagesDescription": "Powiadomienia toast dla monitorów znikają po określonym czasie w sekundach. Ustawienie -1 wyłącza limit czasu. Ustawienie 0 wyłącza powiadomienia toast.",
|
||||
"authInvalidToken": "Nieprawidłowy token.",
|
||||
"authIncorrectCreds": "Nieprawidłowa nazwa użytkownika lub hasło.",
|
||||
"2faAlreadyEnabled": "2FA jest już włączone.",
|
||||
"2faEnabled": "2FA włączone.",
|
||||
"2faDisabled": "2FA wyłączone.",
|
||||
"successAdded": "Pomyślnie dodano.",
|
||||
"successPaused": "Wstrzymano pomyślnie.",
|
||||
"successDeleted": "Usunięto pomyślnie.",
|
||||
"successEdited": "Edytowano pomyślnie.",
|
||||
"successAuthChangePassword": "Hasło zostało pomyślnie zaktualizowane.",
|
||||
"successDisabled": "Wyłączono pomyślnie.",
|
||||
"successEnabled": "Włączono pomyślnie.",
|
||||
"tagNotFound": "Nie znaleziono tagu.",
|
||||
"foundChromiumVersion": "Znaleziono Chromium/Chrome. Wersja: {0}",
|
||||
"authUserInactiveOrDeleted": "Użytkownik jest nieaktywny lub usunięty.",
|
||||
"successResumed": "Wznowiono pomyślnie.",
|
||||
"successBackupRestored": "Kopia zapasowa została pomyślnie przywrócona.",
|
||||
"pushViewCode": "Jak korzystać z monitora Push? (wyświetl kod)",
|
||||
"Bark API Version": "Wersja API Bark",
|
||||
"pushOthers": "Inne",
|
||||
"programmingLanguages": "Języki programowania",
|
||||
"toastSuccessTimeout": "Limit czasu dla powiadomień o powodzeniu"
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
"passwordNotMatchMsg": "A senha repetida não corresponde.",
|
||||
"notificationDescription": "Atribua uma notificação ao (s) monitor (es) para que funcione.",
|
||||
"keywordDescription": "Pesquise a palavra-chave em html simples ou resposta JSON e diferencia maiúsculas de minúsculas.",
|
||||
"pauseDashboardHome": "Pausar",
|
||||
"pauseDashboardHome": "Pausado",
|
||||
"deleteMonitorMsg": "Tem certeza de que deseja excluir este monitor?",
|
||||
"deleteNotificationMsg": "Tem certeza de que deseja excluir esta notificação para todos os monitores?",
|
||||
"resolverserverDescription": "Cloudflare é o servidor padrão, você pode alterar o servidor resolvedor a qualquer momento.",
|
||||
@@ -63,7 +63,7 @@
|
||||
"Ping": "Ping",
|
||||
"Monitor Type": "Tipo de Monitor",
|
||||
"Keyword": "Palavra-Chave",
|
||||
"Friendly Name": "Nome Amigável",
|
||||
"Friendly Name": "Apelido",
|
||||
"URL": "URL",
|
||||
"Hostname": "Hostname",
|
||||
"Port": "Porta",
|
||||
@@ -196,7 +196,7 @@
|
||||
"Required": "Requerido",
|
||||
"webhookJsonDesc": "{0} é bom para qualquer servidor HTTP moderno, como Express.js",
|
||||
"webhookAdditionalHeadersTitle": "Cabeçalhos Adicionais",
|
||||
"webhookAdditionalHeadersDesc": "Define cabeçalhos adicionais enviados com o webhook.",
|
||||
"webhookAdditionalHeadersDesc": "Define cabeçalhos adicionais enviados com o webhook. Cada cabeçalho deve ser definido como uma chave/valor JSON.",
|
||||
"Webhook URL": "URL Do Webhook",
|
||||
"Priority": "Prioridade",
|
||||
"Read more": "Ver mais",
|
||||
@@ -306,11 +306,11 @@
|
||||
"Notification Service": "Serviço De Notificação",
|
||||
"default: notify all devices": "padrão: notificar todos os dispositivos",
|
||||
"Trigger type:": "Tipo Do Acionamento:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Em seguida, escolha uma ação, por exemplo, alterar a cena onde uma luz RGB está vermelha.",
|
||||
"Enable": "Habilitado",
|
||||
"Disable": "Desabilitado",
|
||||
"IconUrl": "URL Do Ícone",
|
||||
"Enable DNS Cache": "Habilitar Cache Do DNS",
|
||||
"Enable DNS Cache": "(Descontinuado) Habilitar o Cache DNS para monitores HTTP(s)",
|
||||
"Single Maintenance Window": "Janela Única De Manutenção",
|
||||
"dnsCacheDescription": "Pode não funcionar em alguns ambientes com IPv6, desabita caso encontre qualquer problema.",
|
||||
"Messaging API": "API Da Mensageira",
|
||||
@@ -588,5 +588,206 @@
|
||||
"wayToGetDiscordURL": "Voce pode configurar isso indo à Configurações do Servidor -> Integrações -> Ver Webhooks -> Novo Webhook",
|
||||
"Home": "Início",
|
||||
"Reconnecting...": "Reconectando...",
|
||||
"Cannot connect to the socket server": "Não foi possível conectar ao servidor socket"
|
||||
"Cannot connect to the socket server": "Não foi possível conectar ao servidor socket",
|
||||
"Uptime Kuma URL": "URL do Uptime Kuma",
|
||||
"Saved.": "Salvo.",
|
||||
"Feishu WebHookUrl": "URL de Webhook do Feishu",
|
||||
"serwersmsAPIUser": "Nome de usuário da API (incluindo o prefixo webapi_)",
|
||||
"setupDatabaseEmbeddedMariaDB": "Você não precisa configurar nada. Esta imagem Docker possui o MariaDB incorporado e configurado automaticamente para você. O Uptime Kuma se conectará a este banco de dados através do soquete Unix.",
|
||||
"Select": "Selecione",
|
||||
"supportTelegramChatID": "Suporte para o ID de bate-papo direto / grupo / canal do chat",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Uma lista de Serviços de Notificação pode ser encontrada no Home Assistant em \"Ferramentas de Desenvolvimento > Serviços\". Pesquise por \"notificação\" para encontrar o nome do seu dispositivo/telefone.",
|
||||
"chromeExecutableAutoDetect": "Auto Detectar",
|
||||
"chromeExecutableDescription": "Para os usuários do Docker, se o Chromium ainda não estiver instalado, pode demorar alguns minutos para instalar e exibir o resultado do teste. Ele ocupa 1GB de espaço em disco.",
|
||||
"wayToCheckSignalURL": "Você pode checar esse link para ver como configurar um:",
|
||||
"wayToGetLineChannelToken": "Primeiro acesse o {0}, crie um provedor e um canal (API de Mensagens), então você pode obter o token de acesso do canal e o ID do usuário nos itens de menu mencionados acima.",
|
||||
"aboutMattermostChannelName": "Você pode substituir o canal padrão para o qual o Webhook envia postagens, inserindo o nome do canal no campo \"Nome do Canal\". Isso precisa ser habilitado nas configurações do Webhook do Mattermost. Por exemplo: #outro-canal",
|
||||
"invertKeywordDescription": "Procure pela palavra-chave estar ausente em vez de presente.",
|
||||
"jsonQueryDescription": "Faça uma consulta JSON na resposta e verifique o valor esperado (o valor de retorno será convertido em uma string para comparação). Confira <a href='https://jsonata.org/'>jsonata.org</a> para a documentação sobre a linguagem de consulta. Você pode encontrar um playground <a href='https://try.jsonata.org/'>aqui</a>.",
|
||||
"octopushTypePremium": "Premium (Rápido - recomendado para alertas)",
|
||||
"octopushTypeLowCost": "Baixo Custo (Lento - às vezes bloqueado pelo operador)",
|
||||
"octopushSMSSender": "Nome do Remetente de SMS: 3-11 caracteres alfanuméricos e espaço (a-zA-Z0-9)",
|
||||
"pushoversounds pianobar": "Piano Bar",
|
||||
"SendKey": "\"SendKey\" é uma palavra usada para notificação do ServerChan",
|
||||
"goAlertInfo": "GoAlert é uma aplicação de código aberto para escalas de plantão, escalonamentos automatizados e notificações (como SMS ou chamadas de voz). Engage automaticamente a pessoa certa, da maneira certa e no momento certo! {0}",
|
||||
"promosmsTypeFlash": "SMS FLASH - A mensagem será exibida automaticamente no dispositivo do destinatário. Limitado apenas aos destinatários poloneses.",
|
||||
"promosmsTypeSpeed": "SMS SPEED - Maior prioridade no sistema. Muito rápido e confiável, mas custoso (cerca de duas vezes o preço do SMS FULL).",
|
||||
"matrixDesc1": "Você pode encontrar o ID da sala interna olhando na seção avançada das configurações da sala em seu cliente Matrix. Deve parecer algo como !QMdRCpUIfLwsfjxye6:home.server.",
|
||||
"matrixDesc2": "É altamente recomendado que você crie um novo usuário e não use o token de acesso do seu próprio usuário Matrix, pois isso permitirá acesso total à sua conta e todas as salas às quais você se juntou. Em vez disso, crie um novo usuário e convide-o apenas para a sala na qual você deseja receber a notificação. Você pode obter o token de acesso executando {0}.",
|
||||
"aboutChannelName": "Digite o nome do canal no campo Nome do Canal em {0} se você deseja ignorar o canal do Webhook. Exemplo: #outro-canal",
|
||||
"wayToGetPagerDutyKey": "Você pode obter isso indo para Serviço -> Diretório de Serviço -> (Selecionar um serviço) -> Integrações -> Adicionar integração. Aqui você pode procurar por \"Events API V2\". Mais informações {0}.",
|
||||
"From Name/Number": "Nome/Número de Origem",
|
||||
"Server URL should not contain the nfty topic": "A URL do servidor não deve conter o tópico do nfty",
|
||||
"pushDeerServerDescription": "Deixe em branco para usar o servidor oficial",
|
||||
"wayToGetPagerTreeIntegrationURL": "Após criar a integração do Uptime Kuma no PagerTree, copie o Endpoint. Veja detalhes completos {0}",
|
||||
"setupDatabaseChooseDatabase": "Qual banco de dados você deseja usar?",
|
||||
"setupDatabaseMariaDB": "Conectar a um banco de dados MariaDB externo. Você precisa definir as informações de conexão com o banco de dados.",
|
||||
"setupDatabaseSQLite": "Um arquivo de banco de dados simples, recomendado para implantações de pequena escala. Antes da versão 2.0.0, o Uptime Kuma usava o SQLite como banco de dados padrão.",
|
||||
"dbName": "Nome do Banco de Dados",
|
||||
"styleElapsedTimeShowNoLine": "Mostrar (Sem Linha)",
|
||||
"styleElapsedTimeShowWithLine": "Mostrar (Com Linha)",
|
||||
"filterActive": "Ativo",
|
||||
"filterActivePaused": "Pausado",
|
||||
"selectedMonitorCount": "Selecione: {0}",
|
||||
"enableNSCD": "Habilitar o NSCD (Name Service Cache Daemon) para o cache de todas as solicitações DNS",
|
||||
"chromeExecutable": "Executável do Chrome/Chromium",
|
||||
"Edit Maintenance": "Editar Manutenção",
|
||||
"aboutIconURL": "Você pode fornecer um link para uma imagem em \"URL do Ícone\" para substituir a imagem de perfil padrão. Não será usado se o \"Ícone Emoji\" estiver configurado.",
|
||||
"octopushAPIKey": "\"Chave API\" das credenciais da API HTTP no painel de controle.",
|
||||
"octopushLogin": "\"Login\" das credenciais da API HTTP no painel de controle.",
|
||||
"pushoversounds pushover": "Pushover (padrão)",
|
||||
"pushoversounds bike": "Bicicleta",
|
||||
"pushoversounds bugle": "Corneta",
|
||||
"pushoversounds cashregister": "Caixa registradora",
|
||||
"pushoversounds classical": "Clássico",
|
||||
"pushoversounds cosmic": "Cósmico",
|
||||
"pushoversounds falling": "Cair",
|
||||
"pushoversounds gamelan": "Gamelão",
|
||||
"pushoversounds incoming": "Entrada",
|
||||
"checkPrice": "Verifique os preços de {0}:",
|
||||
"Check octopush prices": "Verifique os preços da octopush {0}.",
|
||||
"octopushPhoneNumber": "Número de telefone (formato internacional, por exemplo: +33612345678) ",
|
||||
"LunaSea Device ID": "ID do Dispositivo LunaSea",
|
||||
"Apprise URL": "URL do Apprise",
|
||||
"Strategy": "Estratégia",
|
||||
"Free Mobile User Identifier": "Identificador de Usuário Free Mobile",
|
||||
"Free Mobile API Key": "Chave da API Free Mobile",
|
||||
"Enable TLS": "Habilitar TLS",
|
||||
"Proto Service Name": "Nome do Serviço Proto",
|
||||
"Proto Method": "Método Proto",
|
||||
"Proto Content": "Conteúdo Proto",
|
||||
"Economy": "Economia",
|
||||
"Lowcost": "Baixo Custo",
|
||||
"high": "alto",
|
||||
"pushoversounds intermission": "Intervalo",
|
||||
"pushoversounds magic": "Mágico",
|
||||
"pushoversounds mechanical": "Mecânico",
|
||||
"pushoversounds siren": "Sirene",
|
||||
"pushoversounds spacealarm": "Alarme Espacial",
|
||||
"pushoversounds tugboat": "Rebocador",
|
||||
"pushoversounds alien": "Alarme Alienígena (longo)",
|
||||
"pushoversounds climb": "Subir (longo)",
|
||||
"pushoversounds persistent": "Persistente (longo)",
|
||||
"pushoversounds echo": "Eco pushover (longo)",
|
||||
"pushoversounds updown": "Up Down (longo)",
|
||||
"SMSManager API Docs": "Docs da API SMSManager ",
|
||||
"Gateway Type": "Tipo de gateway",
|
||||
"You can divide numbers with": "Você pode dividir números com",
|
||||
"Base URL": "URL base",
|
||||
"goAlertIntegrationKeyInfo": "Obtenha a chave de integração genérica da API para o serviço neste formato \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\", geralmente o valor do parâmetro token da URL copiada.",
|
||||
"AccessKeyId": "ID da Chave de Acesso",
|
||||
"promosmsTypeFull": "SMS FULL - Nível premium de SMS, você pode usar o seu Nome do Remetente (é necessário registrar o nome primeiro). Confiável para alertas.",
|
||||
"promosmsPhoneNumber": "Número de telefone (para destinatários poloneses, você pode pular os códigos de área)",
|
||||
"promosmsSMSSender": "Nome do Remetente de SMS: Nome pré-registrado ou um dos padrões: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||
"matrixHomeserverURL": "URL do Servidor (com http(s):// e opcionalmente a porta)",
|
||||
"Notify Channel": "Canal de Notificação",
|
||||
"aboutNotifyChannel": "O canal de notificação acionará uma notificação na área de trabalho ou no dispositivo móvel para todos os membros do canal, independentemente de sua disponibilidade estar definida como ativa ou ausente.",
|
||||
"signalImportant": "IMPORTANTE: Você não pode misturar grupos e números nos destinatários!",
|
||||
"aboutKumaURL": "Se você deixar o campo URL do Uptime Kuma em branco, ele será definido como padrão para a página do GitHub do projeto.",
|
||||
"smtpDkimDesc": "Por favor, consulte o DKIM do Nodemailer em {0} para obter instruções de uso.",
|
||||
"Auto resolve or acknowledged": "Auto resolva ou reconhecido",
|
||||
"auto acknowledged": "reconhecimento automático",
|
||||
"auto resolve": "resolução automática",
|
||||
"alertaApiEndpoint": "Endpoint da API",
|
||||
"serwersmsSenderName": "Nome do Remetente de SMS (registrado via portal do cliente)",
|
||||
"smseagleGroup": "Nome(s) do grupo(s) da agenda telefônica",
|
||||
"smseagleContact": "Nome(s) do(s) contato(s) da agenda telefônica",
|
||||
"smseagleRecipientType": "Tipo de destinatário",
|
||||
"smseagleRecipient": "Destinatário(s) (múltiplos devem ser separados por vírgula)",
|
||||
"smseagleUrl": "URL do seu dispositivo SMSEagle",
|
||||
"Recipient Number": "Número do Destinatário",
|
||||
"Leave blank to use a shared sender number.": "Deixe em branco para usar um número de remetente compartilhado.",
|
||||
"Octopush API Version": "Versão da API Octopush",
|
||||
"Legacy Octopush-DM": "Octopush-DM Legado",
|
||||
"ntfy Topic": "Tópico do ntfy",
|
||||
"onebotHttpAddress": "Endereço HTTP do OneBot",
|
||||
"onebotMessageType": "Tipo de Mensagem do OneBot",
|
||||
"PushDeer Server": "Servidor PushDeer",
|
||||
"PushDeer Key": "Chave PushDeer",
|
||||
"wayToGetClickSendSMSToken": "Você pode obter o Nome de Usuário da API e a Chave da API em {0}.",
|
||||
"Custom Monitor Type": "Tipo de Monitor Personalizado",
|
||||
"Body Encoding": "Codificação do Corpo",
|
||||
"API Keys": "Chaves da API",
|
||||
"pagertreeSilent": "Silencioso",
|
||||
"pagertreeLow": "Baixo",
|
||||
"pagertreeMedium": "Médio",
|
||||
"pagertreeHigh": "Alto",
|
||||
"pagertreeCritical": "Crítico",
|
||||
"pagertreeResolve": "Resolução Automática",
|
||||
"pagertreeDoNothing": "Não fazer nada",
|
||||
"lunaseaTarget": "Alvo",
|
||||
"lunaseaDeviceID": "ID do Dispositivo",
|
||||
"lunaseaUserID": "ID do Usuário",
|
||||
"ntfyAuthenticationMethod": "Método de Autenticação",
|
||||
"ntfyUsernameAndPassword": "Usuário e Senha",
|
||||
"twilioAccountSID": "SID da Conta",
|
||||
"twilioApiKey": "Chave da API (opcional)",
|
||||
"twilioAuthToken": "Token de Autenticação / Segredo da Chave da API",
|
||||
"twilioFromNumber": "Número de origem",
|
||||
"twilioToNumber": "Número de destino",
|
||||
"Monitor Setting": "Configuração do monitor de {0}",
|
||||
"Show Clickable Link Description": "Se marcada, todos que têm acesso a esta página de status podem ter acesso ao URL do monitor.",
|
||||
"Group": "Grupo",
|
||||
"Monitor Group": "Grupo do Monitor",
|
||||
"Request Timeout": "Tempo Limite da Solicitação",
|
||||
"timeoutAfter": "Tempo limite após {0} segundos",
|
||||
"webhookBodyPresetOption": "Predefinição - {0}",
|
||||
"webhookBodyCustomOption": "Corpo Customizado",
|
||||
"Check/Uncheck": "Marcar/Desmarcar",
|
||||
"tailscalePingWarning": "Para usar o monitor Tailscale Ping, você precisa instalar o Uptime Kuma sem o Docker e também instalar o cliente Tailscale em seu servidor.",
|
||||
"telegramMessageThreadIDDescription": "Identificador único opcional para o tópico da mensagem alvo do fórum; apenas para supergrupos de fóruns.",
|
||||
"pushoversounds none": "Nenhum (silencioso)",
|
||||
"pushyAPIKey": "Chave de API Secreta",
|
||||
"pushyToken": "Token do Dispositivo",
|
||||
"GoogleChat": "Google Chat (Apenas para Google Workspace)",
|
||||
"wayToGetKookGuildID": "Ative o 'Modo Desenvolvedor' nas configurações do Kook e clique com o botão direito do mouse no servidor para obter seu ID.",
|
||||
"Guild ID": "ID do Servidor (Guild)",
|
||||
"pushoverDesc1": "A prioridade de emergência (2) possui um intervalo de 30 segundos entre as tentativas padrão e expirará após 1 hora.",
|
||||
"pushoverDesc2": "Se você deseja enviar notificações para diferentes dispositivos, preencha o campo \"Dispositivo\".",
|
||||
"pushoverMessageTtl": "Tempo de Vida da Mensagem (Segundos)",
|
||||
"pushoversounds vibrate": "Somente vibrar",
|
||||
"SecretAccessKey": "Segredo da Chave de Acesso",
|
||||
"PhoneNumbers": "Números de Telefone",
|
||||
"TemplateCode": "Código de Modelo",
|
||||
"SignName": "Nome de Assinatura",
|
||||
"Sms template must contain parameters: ": "O modelo de SMS deve conter parâmetros: ",
|
||||
"Bark Endpoint": "Endpoint do Bark",
|
||||
"Bark Group": "Grupo do Bark",
|
||||
"Bark Sound": "Som do Bark",
|
||||
"WebHookUrl": "URL de Webhook",
|
||||
"SecretKey": "Chave Secreta",
|
||||
"High": "Alto",
|
||||
"WeCom Bot Key": "Chave do Bot do WeCom",
|
||||
"promosmsTypeEco": "SMS ECO - barato, mas lento e frequentemente sobrecarregado. Limitado apenas aos destinatários poloneses.",
|
||||
"styleElapsedTime": "Tempo decorrido abaixo da barra de pulsação",
|
||||
"Expected Value": "Valor Esperado",
|
||||
"webhookCustomBodyDesc": "Defina um corpo HTTP personalizado para a solicitação. Variáveis de modelo {msg}, {heartbeat}, {monitor} são aceitas.",
|
||||
"Invert Keyword": "Palavra-chave de Inversão",
|
||||
"Json Query": "Consulta JSON",
|
||||
"toastErrorTimeout": "Tempo limite para Notificações de Erro",
|
||||
"toastSuccessTimeout": "Tempo limite para Notificações de Sucesso",
|
||||
"monitorToastMessagesLabel": "Monitorar notificações Toast",
|
||||
"monitorToastMessagesDescription": "As notificações Toast para monitores desaparecem após um determinado tempo em segundos. Definir como -1 desativa o tempo limite. Definir como 0 desativa as notificações Toast.",
|
||||
"Open Badge Generator": "Gerador de Distintivo",
|
||||
"Badge Label Color": "Cor do Nome do Distintivo",
|
||||
"Badge Color": "Cor do Distintivo",
|
||||
"Badge Label Prefix": "Prefixo do Nome do Distintivo",
|
||||
"Badge Preview": "Prévia do Distintivo",
|
||||
"Badge Label Suffix": "Sufixo do Nome do Distintivo",
|
||||
"Badge Up Color": "Cor de Cima do Distintivo",
|
||||
"Badge Down Color": "Cor de Baixo do Distintivo",
|
||||
"Badge Pending Color": "Cor do Distintivo Pendente",
|
||||
"Badge Maintenance Color": "Cor do Distintivo Em Manutenção",
|
||||
"Badge Warn Color": "Cor do Distintivo de Aviso",
|
||||
"Badge Warn Days": "Dias de Aviso do Distintivo",
|
||||
"Badge Down Days": "Dias Desligado do Distintivo",
|
||||
"Badge Style": "Estilo do Distintivo",
|
||||
"Badge value (For Testing only.)": "Valor do Distintivo (Apenas para Testes).",
|
||||
"Badge URL": "URL do Distintivo",
|
||||
"Badge Generator": "Gerador de Distintivo de {0}",
|
||||
"Badge Type": "Tipo de Distintivo",
|
||||
"Badge Duration (in hours)": "Duração do Distintivo (em horas)",
|
||||
"Badge Label": "Nome do Distintivo",
|
||||
"Badge Prefix": "Prefixo do Valor do Distintivo",
|
||||
"Badge Suffix": "Sufixo do Valor do Distintivo"
|
||||
}
|
||||
|
@@ -639,7 +639,7 @@
|
||||
"Server Timezone": "Часовой пояс сервера",
|
||||
"statusPageMaintenanceEndDate": "Конец",
|
||||
"IconUrl": "URL иконки",
|
||||
"Enable DNS Cache": "Включить DNS кэш для мониторов HTTP(S)",
|
||||
"Enable DNS Cache": "(Устарело) Включить DNS кэш для мониторов HTTP(S)",
|
||||
"Enable": "Включить",
|
||||
"Disable": "Отключить",
|
||||
"Single Maintenance Window": "Единое окно техбслуживания",
|
||||
@@ -847,5 +847,20 @@
|
||||
"nostrRecipientsHelp": "формат npub, по одному в строке",
|
||||
"FlashDuty Severity": "Серьёзность",
|
||||
"nostrRelays": "Реле Nostr",
|
||||
"nostrRelaysHelp": "Один URL-адрес ретрансляции в каждой строке"
|
||||
"nostrRelaysHelp": "Один URL-адрес ретрансляции в каждой строке",
|
||||
"enableNSCD": "Включить NSCD (Name Service Cache Daemon) для кэширования всех DNS-запросов",
|
||||
"Saved.": "Сохранено",
|
||||
"setupDatabaseChooseDatabase": "Какую базу данных Вы хотите использовать?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Вам не нужно ничего настраивать. В этот докер-образ автоматически встроена и настроена MariaDB. Uptime Kuma будет подключаться к этой базе данных через unix-сокет.",
|
||||
"setupDatabaseSQLite": "Простой файл базы данных, рекомендуемый для небольших развертываний. До версии 2.0.0 Uptime Kuma использовал SQLite в качестве базы данных по умолчанию.",
|
||||
"setupDatabaseMariaDB": "Подключитесь к внешней базе данных MariaDB. Необходимо задать информацию о подключении к базе данных.",
|
||||
"dbName": "Имя базы данных",
|
||||
"pushViewCode": "Как использовать монитор Push? (Посмотреть код)",
|
||||
"programmingLanguages": "Языки программирования",
|
||||
"Bark API Version": "Версия Bark API",
|
||||
"monitorToastMessagesDescription": "Уведомления для мониторов исчезают через заданное время в секундах. Значение -1 отключает тайм-аут. Значение 0 отключает уведомления.",
|
||||
"monitorToastMessagesLabel": "Уведомления",
|
||||
"toastErrorTimeout": "Таймаут для уведомлений об ошибках",
|
||||
"toastSuccessTimeout": "Таймаут для уведомлений об успехе",
|
||||
"pushOthers": "Другие"
|
||||
}
|
||||
|
@@ -137,5 +137,239 @@
|
||||
"resendDisabled": "Omsändning inaktiverat",
|
||||
"Pick Affected Monitors...": "Välj påverkade övervakare…",
|
||||
"Select status pages...": "Välj statussidor…",
|
||||
"General Monitor Type": "Allmänna övervakare"
|
||||
"General Monitor Type": "Allmänna övervakare",
|
||||
"webhookFormDataDesc": "{multipart} är bra för PHP. Den JSON kommer att bli analyserat med {decodeFunction}",
|
||||
"appriseInstalled": "Apprise är installerad.",
|
||||
"clearDataOlderThan": "Behåll övervakare historik data i {0} dagar.",
|
||||
"steamApiKeyDescription": "För att övervaka en Steam Game Server behöver man en Steam Web-API nyckel. Du kan registrera din API nyckel här: ",
|
||||
"No Monitors": "Inga Övervaktare",
|
||||
"shrinkDatabaseDescription": "Utlösa databas VACUUM för SQLite. Om din databas skappades efter 1.10.0, AUTO_VACUUM är redan aktiverat och denna aktion behövs inte.",
|
||||
"proxyDescription": "Proxyservrar måste tilldelas en övervakare för att fungera.",
|
||||
"setAsDefaultProxyDescription": "Denna proxyserver kommer att aktiveras som standard för nya övervakare. Du kan fortfarande inaktivera proxyserven var för sig övervakare.",
|
||||
"Content Type": "Innehållstyp",
|
||||
"webhookAdditionalHeadersDesc": "Ställer in ytterligare headers skickat med webhooken. Varenda header skulle definieras som ett JSON nyckel/värde par.",
|
||||
"RadiusCallingStationIdDescription": "Kallande Enhetsidentifierare",
|
||||
"Slug": "Slugg",
|
||||
"Invert Keyword": "Invertera Nyckelord",
|
||||
"Degraded Service": "Försämrad Tjänst",
|
||||
"Request Timeout": "Request Timeout",
|
||||
"timeoutAfter": "Timeout efter {0} sekunder",
|
||||
"styleElapsedTime": "Förfluten tid under den heartbeat indikatorn",
|
||||
"styleElapsedTimeShowNoLine": "Visa (Utan Linje)",
|
||||
"styleElapsedTimeShowWithLine": "Visa (Med Linje)",
|
||||
"Create": "Skapa",
|
||||
"Clear Data": "Radera Data",
|
||||
"Auto Get": "Hämta Automatiskt",
|
||||
"Overwrite": "Skriva över",
|
||||
"Options": "Alternativ",
|
||||
"Verify Token": "Verifiera Token",
|
||||
"Enable 2FA": "Aktivera 2FA",
|
||||
"Disable 2FA": "Inaktivera 2FA",
|
||||
"2FA Settings": "2FA Inställningar",
|
||||
"Two Factor Authentication": "Tvåfaktorsautentisering",
|
||||
"filterActive": "Aktiv",
|
||||
"filterActivePaused": "Pausad",
|
||||
"Inactive": "Inaktiv",
|
||||
"Setup 2FA": "Uppstart 2FA",
|
||||
"Clear all statistics": "Rensa alla Statistiker",
|
||||
"Skip existing": "Hoppa över existerande",
|
||||
"Keep both": "Behåll båda",
|
||||
"Token": "Token",
|
||||
"notAvailableShort": "N/A",
|
||||
"Apply on all existing monitors": "Applicera på alla existerande övervakare",
|
||||
"Heartbeats": "Heartbeats",
|
||||
"Show URI": "Visa URI",
|
||||
"color": "Färg",
|
||||
"value (optional)": "Värde (valfritt)",
|
||||
"Gray": "Grå",
|
||||
"Tags": "Taggar",
|
||||
"Tag with this name already exist.": "Tag med detta namn finns redan.",
|
||||
"Red": "Röd",
|
||||
"Orange": "Orange",
|
||||
"Green": "Grön",
|
||||
"Blue": "Blå",
|
||||
"Indigo": "Indigoblå",
|
||||
"Purple": "Lila",
|
||||
"Pink": "Rosa",
|
||||
"Custom": "Anpassad",
|
||||
"Search...": "Sök…",
|
||||
"Avg. Ping": "Medelvärde Ping",
|
||||
"Tag with this value already exist.": "Tagg med detta värde finns redan.",
|
||||
"Avg. Response": "Medelvärde Respons",
|
||||
"Entry Page": "Entry Sida",
|
||||
"statusPageRefreshIn": "Uppdaterar om: {0}",
|
||||
"No Services": "Inga Tjänster",
|
||||
"All Systems Operational": "Alla System i Drift",
|
||||
"Partially Degraded Service": "Delvis Försämrada Tjänster",
|
||||
"Add Group": "Lägg till Grupp",
|
||||
"Add New Tag": "Lägg till Ny Tagg",
|
||||
"Add New below or Select...": "Lägg till Ny under eller Välj…",
|
||||
"Add a monitor": "Lägg till en Övervakare",
|
||||
"Edit Status Page": "Hantera Status Sida",
|
||||
"Status Page": "Status Sida",
|
||||
"Status Pages": "Status Sidor",
|
||||
"Go to Dashboard": "Till Dashboard",
|
||||
"here": "här",
|
||||
"Required": "Krävs",
|
||||
"webhookJsonDesc": "{0} är bra för någon moderna HTTP servrar till exempel Express.js",
|
||||
"webhookCustomBodyDesc": "Definiera en anpassad HTTP Body till den request. Mall variabler {msg}, {heartbeat}, {monitor} accepteras.",
|
||||
"webhookAdditionalHeadersTitle": "Ytterligare Headers",
|
||||
"webhookBodyPresetOption": "Förinställning - {0}",
|
||||
"defaultNotificationName": "Min {notification} Varna ({number})",
|
||||
"webhookBodyCustomOption": "Anpassad Body",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"Application Token": "Applikation Token",
|
||||
"Server URL": "Server URL",
|
||||
"Priority": "Prioritet",
|
||||
"emojiCheatSheet": "Emoji fusklapp: {0}",
|
||||
"Read more": "Läs mer",
|
||||
"appriseNotInstalled": "Apprise är inte installerad. {0}",
|
||||
"Method": "Metod",
|
||||
"Body": "Body",
|
||||
"Headers": "Headers",
|
||||
"HeadersInvalidFormat": "Requestens headers är inte giltig JSON: ",
|
||||
"BodyInvalidFormat": "Requestens body är inte giltig JSON: ",
|
||||
"Monitor History": "Övervakare Historik",
|
||||
"PasswordsDoNotMatch": "Lösenorden matchar inte.",
|
||||
"records": "rekorder",
|
||||
"One record": "En rekord",
|
||||
"Current User": "Nuvarande Användare",
|
||||
"topic": "Ämne",
|
||||
"topicExplanation": "MQTT ämne att övervaka",
|
||||
"successMessageExplanation": "MQTT meddelande som ska anses vara framgång",
|
||||
"successMessage": "Framgång Meddelande",
|
||||
"recent": "Nyligen",
|
||||
"Done": "Klar",
|
||||
"Info": "Info",
|
||||
"Security": "Säkerhet",
|
||||
"Steam API Key": "Steam API Nyckel",
|
||||
"Shrink Database": "Minska Databas",
|
||||
"Pick a RR-Type...": "Välj en RR-Typ…",
|
||||
"Pick Accepted Status Codes...": "Välj Accepterade Statuskod…",
|
||||
"Default": "Standard",
|
||||
"HTTP Options": "HTTP Alternativ",
|
||||
"Create Incident": "Skapa Incident",
|
||||
"Title": "Titel",
|
||||
"Content": "Innehåll",
|
||||
"Style": "Stil",
|
||||
"info": "info",
|
||||
"Post URL": "Post URL",
|
||||
"PushUrl": "Push URL",
|
||||
"danger": "risk",
|
||||
"error": "fel",
|
||||
"critical": "kritisk",
|
||||
"primary": "primär",
|
||||
"light": "ljus",
|
||||
"dark": "mörk",
|
||||
"Post": "Post",
|
||||
"Please input title and content": "Snälla lägg till titel och innehåll",
|
||||
"Created": "Skapat",
|
||||
"Last Updated": "Senaste Uppdaterade",
|
||||
"Switch to Light Theme": "Byt till Ljustema",
|
||||
"Switch to Dark Theme": "Byt till Mörktema",
|
||||
"Show Tags": "Visa Taggar",
|
||||
"Hide Tags": "Göma Taggar",
|
||||
"Description": "Beskrivning",
|
||||
"No monitors available.": "Inga övervaktare tillgänglig.",
|
||||
"Add one": "Lägg till en",
|
||||
"Untitled Group": "Namnlös Grupp",
|
||||
"Services": "Tjänster",
|
||||
"Discard": "Radera",
|
||||
"Cancel": "Kancellera",
|
||||
"Select": "Välj",
|
||||
"selectedMonitorCount": "Valt: {0}",
|
||||
"Check/Uncheck": "Markera/Omarkera",
|
||||
"Powered by": "Drivs av",
|
||||
"Customize": "Anpassa",
|
||||
"Custom Footer": "Anpassad Footer",
|
||||
"Custom CSS": "Anpassad CSS",
|
||||
"deleteStatusPageMsg": "Är du säkert att du vill radera denna status sida?",
|
||||
"Proxies": "Proxyservrar",
|
||||
"default": "Standard",
|
||||
"enabled": "Aktiverad",
|
||||
"setAsDefault": "Ange Som Standard",
|
||||
"deleteProxyMsg": "Är du säkert att du vill radera denna proxyserver för alla övervakare?",
|
||||
"Certificate Chain": "Certifikatkedja",
|
||||
"Valid": "Giltig",
|
||||
"Invalid": "Ogiltig",
|
||||
"User": "Användare",
|
||||
"Installed": "Installerat",
|
||||
"Not installed": "Installerat ej",
|
||||
"Running": "Körs",
|
||||
"Not running": "Körs inte",
|
||||
"Remove Token": "Ta bort Token",
|
||||
"Start": "Starta",
|
||||
"Stop": "Stoppa",
|
||||
"Add New Status Page": "Lägg till Ny Status Sida",
|
||||
"Accept characters:": "Acceptera tecken:",
|
||||
"Unpin": "Unpin",
|
||||
"startOrEndWithOnly": "Börja eller sluta med {0} bara",
|
||||
"No consecutive dashes": "Ingen följande streck",
|
||||
"Next": "Nästa",
|
||||
"The slug is already taken. Please choose another slug.": "Sluggen är redan tagit. Snälla välja en annan slugg.",
|
||||
"No Proxy": "Ingen Proxyservern",
|
||||
"Authentication": "Autentisering",
|
||||
"HTTP Basic Auth": "HTTP Basic Auth",
|
||||
"New Status Page": "Ny Status Sida",
|
||||
"Page Not Found": "Sida hittas inte",
|
||||
"Reverse Proxy": "Omvänd Proxyserver",
|
||||
"Backup": "Backup",
|
||||
"About": "Om",
|
||||
"wayToGetCloudflaredURL": "(Ladda ned cloudflared från {0})",
|
||||
"cloudflareWebsite": "Cloudflare Webbsida",
|
||||
"Message:": "Meddelande:",
|
||||
"Don't know how to get the token? Please read the guide:": "Vet inte hur att få en token? Snälla läs guiden:",
|
||||
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Den nuvarande anslutningen kan kopplas bort om du närvarande ansluter via Cloudflare Tunnel. Är du säkert du vill avsluta den? Skriv ditt nuvarande lösenord för att konfirmera.",
|
||||
"HTTP Headers": "HTTP Headers",
|
||||
"Trust Proxy": "Lita på Proxyserver",
|
||||
"Other Software": "Annan programvara",
|
||||
"For example: nginx, Apache and Traefik.": "Till exempel: nginx, Apache och Traefik.",
|
||||
"Please read": "Läs är du snäll",
|
||||
"Subject:": "Subjekt:",
|
||||
"Valid To:": "Giltig Till:",
|
||||
"Days Remaining:": "Dagar kvar:",
|
||||
"Fingerprint:": "Fingertryck:",
|
||||
"No status pages": "Ingen status sidor",
|
||||
"Proxy": "Proxyservern",
|
||||
"Date Created": "Datum Skapade",
|
||||
"Footer Text": "Footer Text",
|
||||
"Show Powered By": "Visa Drivs Av",
|
||||
"Domain Names": "Domain Namn",
|
||||
"signedInDisp": "Inloggad som {0}",
|
||||
"signedInDispDisabled": "Auth Inaktiverad.",
|
||||
"RadiusSecret": "Radius Hemlighet",
|
||||
"RadiusSecretDescription": "Delad Hemlighet mellan client och server",
|
||||
"RadiusCalledStationId": "Kancellerad Station Id",
|
||||
"RadiusCalledStationIdDescription": "Enhetsidentifierare",
|
||||
"RadiusCallingStationId": "Calling Station Id",
|
||||
"Certificate Expiry Notification": "Notif om certifikatets utgång",
|
||||
"Domain Name Expiry Notification": "Notif om Domain Namns utgång",
|
||||
"API Key": "API Nyckel",
|
||||
"API Username": "API Användarnamn",
|
||||
"Show update if available": "Visa uppdatering om tillgänglig",
|
||||
"Also check beta release": "Kolla upp också beta version",
|
||||
"Events": "Händelser",
|
||||
"Active": "Aktiv",
|
||||
"statusPageNothing": "Ingenting här, snälla lägg till en grupp eller en monitor.",
|
||||
"warning": "varning",
|
||||
"Issuer:": "Utfärdare:",
|
||||
"Expected Value": "Förväntat Värde",
|
||||
"Primary Base URL": "Huvud Bas URL",
|
||||
"Home": "Hem",
|
||||
"Cannot connect to the socket server": "Kan inte koppla till socketservern",
|
||||
"Reconnecting...": "Återanslutar...",
|
||||
"Json Query": "Json Query",
|
||||
"Default enabled": "Standard aktiverad",
|
||||
"pushViewCode": "Visa kod",
|
||||
"Steam Game Server": "Steam Spel Server",
|
||||
"Docker Container": "Docker Container",
|
||||
"setupDatabaseChooseDatabase": "Vilken databas skulle du vilja använda?",
|
||||
"dbName": "Databas Namn",
|
||||
"What you can try:": "Vad du kan försöka:",
|
||||
"Container Name / ID": "Containernamn / ID",
|
||||
"Docker Host": "Docker värd",
|
||||
"Docker Hosts": "Docker värdar",
|
||||
"Domain": "Domän",
|
||||
"Most likely causes:": "Störst troliga anledningar:",
|
||||
"Coming Soon": "Kommer snart"
|
||||
}
|
||||
|
124
src/lang/te.json
124
src/lang/te.json
@@ -187,5 +187,127 @@
|
||||
"Tag with this value already exist.": "ఈ విలువతో ట్యాగ్ ఇప్పటికే ఉంది.",
|
||||
"Custom": "కస్టమ్",
|
||||
"Entry Page": "ఎంట్రీ పేజీ",
|
||||
"statusPageNothing": "ఇక్కడ ఏమీ లేదు, దయచేసి సమూహాన్ని లేదా మానిటర్ని జోడించండి."
|
||||
"statusPageNothing": "ఇక్కడ ఏమీ లేదు, దయచేసి సమూహాన్ని లేదా మానిటర్ని జోడించండి.",
|
||||
"No Services": "సేవలు లేవు",
|
||||
"Partially Degraded Service": "పాక్షికంగా క్షీణించిన సేవ",
|
||||
"Degraded Service": "దిగజారిన సేవ",
|
||||
"Add Group": "సమూహాన్ని జోడించండి",
|
||||
"Add a monitor": "మానిటర్ను జోడించండి",
|
||||
"Go to Dashboard": "డాష్బోర్డ్ కు వెళ్ళండి",
|
||||
"Status Page": "స్థితి పేజీ",
|
||||
"Status Pages": "స్థితి పేజీలు",
|
||||
"here": "ఇక్కడ",
|
||||
"Required": "అవసరం",
|
||||
"Post URL": "పోస్ట్ URL",
|
||||
"Content Type": "కంటెంట్ రకం",
|
||||
"webhookFormDataDesc": "PHPకి {multipart} మంచిది. JSON {decodeFunction}తో అన్వయించబడాలి",
|
||||
"webhookAdditionalHeadersTitle": "అదనపు శీర్షికలు",
|
||||
"webhookBodyPresetOption": "ప్రీసెట్ - {0}",
|
||||
"webhookBodyCustomOption": "కస్టమ్ బాడీ",
|
||||
"Webhook URL": "వెబ్హుక్ URL",
|
||||
"Application Token": "అప్లికేషన్ టోకెన్",
|
||||
"Server URL": "సర్వర్ URL",
|
||||
"Priority": "ప్రాధాన్యత",
|
||||
"Read more": "ఇంకా చదవండి",
|
||||
"appriseInstalled": "అప్రైజ్ ఇన్స్టాల్ చేయబడింది.",
|
||||
"Method": "పద్ధతి",
|
||||
"Body": "శరీరం",
|
||||
"Headers": "హెడర్సు",
|
||||
"PushUrl": "పుష్ URL",
|
||||
"BodyInvalidFormat": "అభ్యర్థన విషయం JSON చెల్లదు: ",
|
||||
"Monitor History": "మానిటర్ చరిత్ర",
|
||||
"clearDataOlderThan": "మానిటర్ చరిత్ర డేటాను {0} రోజుల పాటు ఉంచండి.",
|
||||
"records": "రికార్డులు",
|
||||
"One record": "ఒక రికార్డు",
|
||||
"Current User": "ప్రస్తుత వినియోగదారుడు",
|
||||
"topic": "అంశం",
|
||||
"topicExplanation": "పర్యవేక్షించడానికి MQTT అంశం",
|
||||
"successMessage": "విజయ సందేశం",
|
||||
"successMessageExplanation": "MQTT సందేశం విజయంగా పరిగణించబడుతుంది",
|
||||
"recent": "ఇటీవలి",
|
||||
"Done": "పూర్తి",
|
||||
"Info": "సమాచారం",
|
||||
"Steam API Key": "స్టీమ్ API కీ",
|
||||
"Shrink Database": "డేటాబేస్ కుదించు",
|
||||
"Pick Accepted Status Codes...": "ఆమోదించబడిన స్థితి కోడ్లను ఎంచుకోండి…",
|
||||
"Default": "డిఫాల్ట్",
|
||||
"HTTP Options": "HTTP ఎంపికలు",
|
||||
"Title": "శీర్షిక",
|
||||
"Content": "విషయము",
|
||||
"Style": "శైలి",
|
||||
"info": "సమాచారం",
|
||||
"warning": "హెచ్చరిక",
|
||||
"danger": "ప్రమాదం",
|
||||
"error": "లోపం",
|
||||
"primary": "ప్రాథమిక",
|
||||
"light": "వెలుతురు",
|
||||
"dark": "చీకటి",
|
||||
"Post": "పోస్ట్",
|
||||
"Created": "సృష్టించబడింది",
|
||||
"Last Updated": "చివరిగా నవీకరించబడింది",
|
||||
"Unpin": "అన్పిన్",
|
||||
"Show Tags": "ట్యాగ్లను చూపించు",
|
||||
"Hide Tags": "ట్యాగ్లను దాచండి",
|
||||
"Description": "వివరణ",
|
||||
"Add one": "ఒకటి జోడించండి",
|
||||
"No Monitors": "మానిటర్లు లేవు",
|
||||
"Services": "సేవలు",
|
||||
"Select": "ఎంచుకోండి",
|
||||
"selectedMonitorCount": "ఎంచుకున్నది: {0}",
|
||||
"Powered by": "ద్వారా ఆధారితం",
|
||||
"Customize": "అనుకూలీకరించండి",
|
||||
"Custom Footer": "అనుకూల ఫుటర్",
|
||||
"Custom CSS": "అనుకూల CSS",
|
||||
"deleteStatusPageMsg": "మీరు ఖచ్చితంగా ఈ స్థితి పేజీని తొలగించాలనుకుంటున్నారా?",
|
||||
"Proxies": "ప్రాక్సీలు",
|
||||
"default": "డిఫాల్ట్",
|
||||
"enabled": "ప్రారంభించబడింది",
|
||||
"Certificate Chain": "సర్టిఫికేట్ చైన్",
|
||||
"Valid": "చెల్లుబాటు అవుతుంది",
|
||||
"Invalid": "చెల్లదు",
|
||||
"User": "వినియోగదారు",
|
||||
"Installed": "ఇన్స్టాల్ చేయబడింది",
|
||||
"Not installed": "ఇన్స్టాల్ చేయలేదు",
|
||||
"Running": "నడుస్తోంది",
|
||||
"Not running": "నడవడం లేదు",
|
||||
"Remove Token": "టోకెన్ని తీసివేయండి",
|
||||
"Start": "ప్రారంభించండి",
|
||||
"Stop": "ఆపు",
|
||||
"Add New Status Page": "కొత్త స్థితి పేజీని జోడించండి",
|
||||
"Slug": "స్లగ్",
|
||||
"startOrEndWithOnly": "{0}తో మాత్రమే ప్రారంభించండి లేదా ముగించండి",
|
||||
"Next": "తరువాత",
|
||||
"No Proxy": "ప్రాక్సీ లేదు",
|
||||
"All Systems Operational": "అన్ని సిస్టమ్స్ ఆపరేషనల్",
|
||||
"Edit Status Page": "స్థితి పేజీని సవరించండి",
|
||||
"defaultNotificationName": "నా {నోటిఫికేషన్} హెచ్చరిక ({సంఖ్య})",
|
||||
"webhookJsonDesc": "Express.js వంటి ఏదైనా ఆధునిక HTTP సర్వర్లకు {0} మంచిది",
|
||||
"webhookCustomBodyDesc": "అభ్యర్థన కోసం అనుకూల HTTP బాడీని నిర్వచించండి. టెంప్లేట్ వేరియబుల్స్ {msg}, {heartbeat}, {monitor} ఆమోదయోగ్యమైనవి.",
|
||||
"webhookAdditionalHeadersDesc": "webhookతో పంపబడిన అదనపు హెడర్లను సెట్ చేస్తుంది. ప్రతి హెడర్ JSON కీ/విలువగా నిర్వచించబడాలి.",
|
||||
"emojiCheatSheet": "ఎమోజి చీట్ షీట్: {0}",
|
||||
"appriseNotInstalled": "అప్రైజ్ ఇన్స్టాల్ చేయబడలేదు. {0}",
|
||||
"HeadersInvalidFormat": "అభ్యర్థన హెడర్సు చెల్లుబాటు కావు JSON: ",
|
||||
"PasswordsDoNotMatch": "గుత్త పదములు సరి పోవట్లేదు.",
|
||||
"steamApiKeyDescription": "స్టీమ్ గేమ్ సర్వర్ని పర్యవేక్షించడానికి మీకు స్టీమ్ వెబ్-API కీ అవసరం. మీరు మీ API కీని ఇక్కడ నమోదు చేసుకోవచ్చు: ",
|
||||
"Security": "భద్రత",
|
||||
"Pick a RR-Type...": "RR-రకాన్ని ఎంచుకోండి…",
|
||||
"Create Incident": "సంఘటనను సృష్టించండి",
|
||||
"critical": "ప్రమాదకరమైన",
|
||||
"Please input title and content": "దయచేసి శీర్షిక మరియు కంటెంట్ని ఇన్పుట్ చేయండి",
|
||||
"Switch to Light Theme": "లైట్ థీమ్కి మారండి",
|
||||
"Switch to Dark Theme": "డార్క్ థీమ్కి మారండి",
|
||||
"No monitors available.": "మానిటర్లు అందుబాటులో లేవు.",
|
||||
"Untitled Group": "పేరులేని సమూహం",
|
||||
"Discard": "విస్మరించండి",
|
||||
"Cancel": "రద్దు చేయండి",
|
||||
"Check/Uncheck": "చెక్/చెక్చేయవద్దు",
|
||||
"shrinkDatabaseDescription": "SQLite కోసం డేటాబేస్ VACUUMని ట్రిగ్గర్ చేయండి. మీ డేటాబేస్ 1.10.0 తర్వాత సృష్టించబడితే, AUTO_VACUUM ఇప్పటికే ప్రారంభించబడింది మరియు ఈ చర్య అవసరం లేదు.",
|
||||
"setAsDefault": "డిఫాల్ట్ సెట్ చేయబడింది",
|
||||
"deleteProxyMsg": "మీరు ఖచ్చితంగా అన్ని మానిటర్ల కోసం ఈ ప్రాక్సీని తొలగించాలనుకుంటున్నారా?",
|
||||
"proxyDescription": "పనిచేయడానికి ప్రాక్సీలు తప్పనిసరిగా మానిటర్కు కేటాయించబడాలి.",
|
||||
"enableProxyDescription": "ఈ ప్రాక్సీ సక్రియం చేయబడే వరకు మానిటర్ అభ్యర్థనలపై ప్రభావం చూపదు. మీరు యాక్టివేషన్ స్థితి ద్వారా అన్ని మానిటర్ల నుండి ప్రాక్సీని తాత్కాలికంగా నిలిపివేయడాన్ని నియంత్రించవచ్చు.",
|
||||
"setAsDefaultProxyDescription": "కొత్త మానిటర్ల కోసం ఈ ప్రాక్సీ డిఫాల్ట్గా ప్రారంభించబడుతుంది. మీరు ఇప్పటికీ ప్రతి మానిటర్కు విడిగా ప్రాక్సీని నిలిపివేయవచ్చు.",
|
||||
"Accept characters:": "అక్షరాలను అంగీకరించండి:",
|
||||
"No consecutive dashes": "వరుస డాష్లను ఉపయోగించవద్దు",
|
||||
"The slug is already taken. Please choose another slug.": "స్లగ్ ఇప్పటికే తీసుకోబడింది. దయచేసి మరొక స్లగ్ని ఎంచుకోండి."
|
||||
}
|
||||
|
@@ -623,7 +623,7 @@
|
||||
"maintenanceStatus-scheduled": "กำหนดการ",
|
||||
"maintenanceStatus-ended": "สิ้นสุด",
|
||||
"maintenanceStatus-unknown": "ไม่ทราบ",
|
||||
"Specific Monitor Type": "ประเภทมอนิเตอร์เฉพาะ",
|
||||
"Specific Monitor Type": "ชนิดมอนิเตอร์เฉพาะ",
|
||||
"telegramMessageThreadID": "(ตัวเลือก) ไอดีเทรดข้อความ",
|
||||
"telegramMessageThreadIDDescription": "ตัวระบุที่ไม่ซ้ำซึ่งเป็นทางเลือกสำหรับเธรดข้อความเป้าหมาย (หัวข้อ) ของฟอรัม สำหรับฟอรัมซูเปอร์กรุ๊ปเท่านั้น",
|
||||
"sameAsServerTimezone": "เช่นเดียวกับเขตเวลาของเซิร์ฟเวอร์",
|
||||
@@ -675,5 +675,11 @@
|
||||
"notificationRegional": "ภูมิภาค",
|
||||
"timeoutAfter": "หมดเวลาหลังจาก {0} วินาที",
|
||||
"Select": "เลือก",
|
||||
"Expected Value": "ค่าที่คาดหวัง"
|
||||
"Expected Value": "ค่าที่คาดหวัง",
|
||||
"setupDatabaseChooseDatabase": "ฐานข้อมูลไหนที่ต้องการใช้งาน?",
|
||||
"setupDatabaseEmbeddedMariaDB": "คุณไม่จำเป็นต้องทำอะไร Docker image จะสร้างและตั่งค่า MariaDB ให้โดยอัตโนมัติ Uptime Kuma จะเชื่อมต่อกับฐานข้อมูลนี้ด้วย unix socket",
|
||||
"setupDatabaseMariaDB": "เชื่อมต่อไปยัง MariaDB ภายนอก คุณจำเป็นจะต้องตั่งค่าการเชื่อมต่อฐานข้อมูล",
|
||||
"setupDatabaseSQLite": "ไฟล์ฐานข้อมูลอย่างง่าย แนะนำสำหรับการปรับใช้ขนาดเล็ก ก่อนเวอร์ชัน 2.0.0 Uptime Kuma ใช้ SQLite เป็นฐานข้อมูลเริ่มต้น",
|
||||
"dbName": "ชื่อฐานข้อมูล",
|
||||
"Passive Monitor Type": "ชนิดมอนิเตอร์แบบพาสซีฟ"
|
||||
}
|
||||
|
@@ -640,7 +640,7 @@
|
||||
"Server Timezone": "Sunucu Saat Dilimi",
|
||||
"statusPageMaintenanceEndDate": "Bitiş Zamanı",
|
||||
"IconUrl": "Icon URL",
|
||||
"Enable DNS Cache": "HTTP monitörleri için DNS Önbelleğini etkinleştir",
|
||||
"Enable DNS Cache": "(Kullanımdan kaldırıldı) HTTP(ler) monitörleri için DNS Önbelleğini etkinleştirin",
|
||||
"Enable": "Etkin",
|
||||
"Disable": "Devre Dışı",
|
||||
"dnsCacheDescription": "Bazı IPv6 ortamlarında çalışmıyor olabilir, herhangi bir sorunla karşılaşırsanız devre dışı bırakın.",
|
||||
@@ -838,5 +838,37 @@
|
||||
"gamedigGuessPortDescription": "Valve Server Sorgu Protokolü tarafından kullanılan bağlantı noktası, istemci bağlantı noktasından farklı olabilir. Monitör sunucunuza bağlanamıyorsa bunu deneyin.",
|
||||
"styleElapsedTimeShowNoLine": "Göster (Satır Yok)",
|
||||
"styleElapsedTime": "Kalp atışı çubuğunun altında geçen süre",
|
||||
"styleElapsedTimeShowWithLine": "Göster (Satır ile birlikte)"
|
||||
"styleElapsedTimeShowWithLine": "Göster (Satır ile birlikte)",
|
||||
"enableNSCD": "Tüm DNS isteklerini önbelleğe almak için NSCD'yi (Ad Hizmeti Önbellek Programı) etkinleştirin",
|
||||
"setupDatabaseEmbeddedMariaDB": "Hiçbir şey ayarlamanıza gerek yok. Bu docker imajı sizin için otomatik olarak bir MariaDB yerleştirdi ve yapılandırdı. Çalışma Süresi Kuma bu veritabanına unix soketi aracılığıyla bağlanacaktır.",
|
||||
"setupDatabaseSQLite": "Küçük ölçekli dağıtımlar için önerilen basit bir veritabanı dosyası. v2.0.0'dan önce Uptime Kuma, varsayılan veritabanı olarak SQLite'ı kullanıyordu.",
|
||||
"setupDatabaseChooseDatabase": "Hangi veritabanını kullanmak istiyorsunuz?",
|
||||
"setupDatabaseMariaDB": "Harici bir MariaDB veritabanına bağlanın. Veritabanı bağlantı bilgilerini ayarlamanız gerekir.",
|
||||
"dbName": "Veritabanı ismi",
|
||||
"Saved.": "Kaydedildi.",
|
||||
"toastErrorTimeout": "Hata Bildirimleri için Zaman Aşımı",
|
||||
"toastSuccessTimeout": "Başarı Bildirimleri için Zaman Aşımı",
|
||||
"monitorToastMessagesLabel": "Toast bildirimlerini izleyin",
|
||||
"monitorToastMessagesDescription": "Monitörler için bildirimler, saniye cinsinden belirli bir süre sonunda kaybolur. -1'e ayarlamak zaman aşımını devre dışı bırakır. 0'a ayarlamak, tost bildirimlerini devre dışı bırakır.",
|
||||
"Bark API Version": "Bark API Sürümü",
|
||||
"pushViewCode": "Push monitör nasıl kullanılır? (Kodu Görüntüle)",
|
||||
"programmingLanguages": "Programlama dilleri",
|
||||
"pushOthers": "Diğerleri",
|
||||
"authInvalidToken": "Geçersiz Token.",
|
||||
"authIncorrectCreds": "Kullanıcı adı ya da parola yanlış.",
|
||||
"2faAlreadyEnabled": "2FA zaten etkin.",
|
||||
"2faEnabled": "2FA Etkin.",
|
||||
"2faDisabled": "2FA Devre Dışı.",
|
||||
"successResumed": "Başarıyla Devam Edildi.",
|
||||
"successPaused": "Başarıyla Duraklatıldı.",
|
||||
"successDeleted": "Başarıyla silindi.",
|
||||
"successEdited": "Başarıyla Düzenlendi.",
|
||||
"successBackupRestored": "Yedekleme başarıyla geri yüklendi.",
|
||||
"successDisabled": "Başarıyla Devre Dışı Bırakıldı.",
|
||||
"successEnabled": "Başarıyla Etkinleştirildi.",
|
||||
"tagNotFound": "Etiket bulunamadı.",
|
||||
"authUserInactiveOrDeleted": "Kullanıcı etkin değil veya silinmiş.",
|
||||
"successAdded": "Başarıyla eklendi.",
|
||||
"successAuthChangePassword": "Şifre başarıyla güncellendi.",
|
||||
"foundChromiumVersion": "Chromium/Chrome bulundu. Versiyon: {0}"
|
||||
}
|
||||
|
@@ -678,7 +678,7 @@
|
||||
"Server Timezone": "Часовий пояс сервера",
|
||||
"statusPageMaintenanceEndDate": "Закінчення",
|
||||
"IconUrl": "URL-адреса іконки",
|
||||
"Enable DNS Cache": "Увімкнути DNS-кеш для HTTP(s) моніторів",
|
||||
"Enable DNS Cache": "(Застаріле) Увімкнути DNS-кеш для HTTP(s) моніторів",
|
||||
"Enable": "Увімкнути",
|
||||
"confirmDeleteTagMsg": "Ви впевнені, що хочете видалити цей тег? Монітори, пов'язані з цим тегом, не будуть видалені.",
|
||||
"Guild ID": "ID гільдії",
|
||||
@@ -844,5 +844,37 @@
|
||||
"gamedigGuessPort": "Gamedig: Вгадати порт",
|
||||
"gamedigGuessPortDescription": "Порт, що використовується протоколом запитів до сервера Valve, може відрізнятися від порту клієнта. Спробуйте це, якщо монітор не може підключитися до вашого сервера.",
|
||||
"styleElapsedTimeShowWithLine": "Показати (з лінією)",
|
||||
"styleElapsedTimeShowNoLine": "Показати (без лінії)"
|
||||
"styleElapsedTimeShowNoLine": "Показати (без лінії)",
|
||||
"enableNSCD": "Увімкнути NSCD (Name Service Cache Daemon) для кешування всіх DNS-запитів",
|
||||
"setupDatabaseChooseDatabase": "Яку базу даних ви хочете використовувати?",
|
||||
"setupDatabaseEmbeddedMariaDB": "Вам не потрібно нічого налаштовувати. Цей докер-образ містить вбудовану та автоматично налаштовану базу даних MariaDB. Uptime Kuma підключиться до цієї бази даних через unix-сокет.",
|
||||
"setupDatabaseSQLite": "Простий файл бази даних, рекомендований для невеликих проєктів. До версії 2.0.0 Uptime Kuma використовувала SQLite як базу даних за замовчуванням.",
|
||||
"setupDatabaseMariaDB": "Підключитися до зовнішньої бази даних MariaDB. Вам потрібно задати інформацію для підключення до бази даних.",
|
||||
"dbName": "Назва бази даних",
|
||||
"Saved.": "Збережено.",
|
||||
"monitorToastMessagesLabel": "Тост-сповіщення монітора",
|
||||
"toastErrorTimeout": "Таймаут для сповіщень про помилки",
|
||||
"toastSuccessTimeout": "Таймаут для сповіщень про успіх",
|
||||
"monitorToastMessagesDescription": "Тост-сповіщення для моніторів зникають через заданий час у секундах. Значення -1 вимикає таймаут. Значення 0 вимикає тост-сповіщення.",
|
||||
"Bark API Version": "Версія Bark API",
|
||||
"pushViewCode": "Як користуватися Push-монітором? (Переглянути код)",
|
||||
"pushOthers": "Інші",
|
||||
"programmingLanguages": "Мови програмування",
|
||||
"authInvalidToken": "Недійсний токен.",
|
||||
"2faAlreadyEnabled": "2FA вже увімкнено.",
|
||||
"2faEnabled": "2FA увімкнено.",
|
||||
"2faDisabled": "2FA вимкнено.",
|
||||
"successAdded": "Успішно додано.",
|
||||
"successResumed": "Успішно відновлено.",
|
||||
"successPaused": "Успішно зупинено.",
|
||||
"successDeleted": "Успішно видалено.",
|
||||
"successAuthChangePassword": "Пароль успішно оновлено.",
|
||||
"successBackupRestored": "Резервну копію успішно відновлено.",
|
||||
"successDisabled": "Успішно вимкнено.",
|
||||
"tagNotFound": "Тег не знайдено.",
|
||||
"foundChromiumVersion": "Знайдено Chromium/Chrome. Версія: {0}",
|
||||
"authUserInactiveOrDeleted": "Користувач неактивний або видалений.",
|
||||
"authIncorrectCreds": "Неправильне ім'я користувача або пароль.",
|
||||
"successEdited": "Успішно відредаговано.",
|
||||
"successEnabled": "Успішно увімкнено."
|
||||
}
|
||||
|
@@ -654,7 +654,7 @@
|
||||
"Server Timezone": "服务器时区",
|
||||
"statusPageMaintenanceEndDate": "结束时间",
|
||||
"IconUrl": "图标 URL",
|
||||
"Enable DNS Cache": "为 HTTP(s) 监控项启用 DNS 缓存",
|
||||
"Enable DNS Cache": "(已弃用)为 HTTP(s) 监控项启用 DNS 缓存",
|
||||
"Enable": "启用",
|
||||
"Disable": "禁用",
|
||||
"dnsCacheDescription": "可能无法在某些 IPv6 环境工作,如果遇到问题请禁用。",
|
||||
@@ -840,5 +840,37 @@
|
||||
"gamedigGuessPort": "Gamedig: 自动检测端口号",
|
||||
"styleElapsedTimeShowWithLine": "显示(带连接线)",
|
||||
"styleElapsedTimeShowNoLine": "显示(不带连接线)",
|
||||
"styleElapsedTime": "在监控项详情的心跳栏下显示起止时间"
|
||||
"styleElapsedTime": "在监控项详情的心跳栏下显示起止时间",
|
||||
"enableNSCD": "启用 NSCD(名称服务缓存)以缓存所有 DNS 请求",
|
||||
"setupDatabaseChooseDatabase": "您想用哪种数据库?",
|
||||
"setupDatabaseEmbeddedMariaDB": "您无需设置此项。通过 Docker 方式安装时已自动配置了一个 MariaDB 数据库。Uptime Kuma 会通过 Unix 套接字方式连接该数据库。",
|
||||
"setupDatabaseMariaDB": "连接到外部 MariaDB 数据库。您需要设置该数据库的连接方式。",
|
||||
"setupDatabaseSQLite": "一个简单的数据库文件,推荐小规模部署使用。在 v2.0.0 版本之前,Uptime Kuma 使用 SQLite 作为默认数据库。",
|
||||
"dbName": "数据库名称",
|
||||
"Saved.": "已保存。",
|
||||
"monitorToastMessagesLabel": "监控项的弹窗通知",
|
||||
"toastSuccessTimeout": "成功类弹窗通知的自动关闭用时",
|
||||
"toastErrorTimeout": "失败类弹窗通知的自动关闭用时",
|
||||
"monitorToastMessagesDescription": "监控项的弹窗通知的自动关闭用时,以秒为单位。设置为 -1 将禁用弹窗通知的自动关闭功能,设置为 0 将完全禁用弹窗通知功能。",
|
||||
"Bark API Version": "Bark API 版本",
|
||||
"programmingLanguages": "编程语言",
|
||||
"pushOthers": "其他",
|
||||
"pushViewCode": "如何使用 Push 监控项?(查看示例代码)",
|
||||
"authInvalidToken": "无效的令牌。",
|
||||
"authUserInactiveOrDeleted": "该用户被禁用或删除。",
|
||||
"tagNotFound": "标签未找到。",
|
||||
"successEnabled": "已成功启用。",
|
||||
"successDisabled": "已成功禁用。",
|
||||
"successBackupRestored": "已成功恢复备份。",
|
||||
"successEdited": "已成功编辑。",
|
||||
"successDeleted": "已成功删除。",
|
||||
"successPaused": "已成功暂停。",
|
||||
"successResumed": "已成功恢复。",
|
||||
"successAdded": "已成功添加。",
|
||||
"2faDisabled": "已成功禁用 2FA。",
|
||||
"2faEnabled": "已成功启用 2FA。",
|
||||
"2faAlreadyEnabled": "2FA 已经启用。",
|
||||
"foundChromiumVersion": "已找到 Chromium/Chrome。版本:{0}",
|
||||
"successAuthChangePassword": "已成功更新密码。",
|
||||
"authIncorrectCreds": "错误的用户名或密码。"
|
||||
}
|
||||
|
@@ -730,5 +730,28 @@
|
||||
"Invert Keyword": "以上關鍵字不能出現",
|
||||
"Home": "首頁",
|
||||
"Expected Value": "預期值",
|
||||
"Json Query": "JSON 查询"
|
||||
"Json Query": "JSON 查询",
|
||||
"Saved.": "已儲存。",
|
||||
"Select": "選擇",
|
||||
"selectedMonitorCount": "已選:{0}",
|
||||
"Check/Uncheck": "選取中/取消選取",
|
||||
"telegramMessageThreadIDDescription": "(可選) Telegram 在超級群組使用的話題標識字串",
|
||||
"pushViewCode": "查看代碼",
|
||||
"pushOthers": "其他",
|
||||
"webhookBodyCustomOption": "自定義內容",
|
||||
"tailscalePingWarning": "如要使用 Tailscale Ping ,您需要以非 docker 方式安裝 Uptime Kuma,並在系統安裝 Tailscale 客戶端。",
|
||||
"invertKeywordDescription": "出現關鍵詞將令檢測結果設為失敗,而非成功。",
|
||||
"enableNSCD": "啟用 NSCD(名稱服務緩存)以緩存所有 DNS 請求",
|
||||
"setupDatabaseChooseDatabase": "你想使用以下哪種資料庫?",
|
||||
"setupDatabaseEmbeddedMariaDB": "你無需作任何設定。Docker image 中已包含設定好的 MariaDB。Uptime Kuma 會自動通過 Unix socket 連接到此資料庫。",
|
||||
"setupDatabaseMariaDB": "連接到額外 MariaDB 資料庫。 你需要設置資料庫連接資訊。",
|
||||
"setupDatabaseSQLite": "以一個檔案作為資料庫,建議用於小型的部署。在 v2.0.0 版本之前,Uptime Kuma 使用 SQLite 作為預設資料庫。",
|
||||
"dbName": "資料庫名稱",
|
||||
"webhookBodyPresetOption": "預設 - {0}",
|
||||
"programmingLanguages": "編程語言",
|
||||
"styleElapsedTime": "狀態條下顯示已過的時間",
|
||||
"styleElapsedTimeShowNoLine": "顯示(不帶連接線)",
|
||||
"styleElapsedTimeShowWithLine": "顯示(帶連接線)",
|
||||
"Request Timeout": "請求超時",
|
||||
"timeoutAfter": "{0} 秒後為超時"
|
||||
}
|
||||
|
@@ -121,7 +121,7 @@
|
||||
"Enable Auth": "啟用驗證",
|
||||
"disableauth.message1": ">你是否要<strong>取消登入驗證</strong>?",
|
||||
"disableauth.message2": "此功能是設計給已有<strong>第三方認證</strong>的使用者,例如 Cloudflare Access。",
|
||||
"Please use this option carefully!": "請謹慎使用。",
|
||||
"Please use this option carefully!": "請謹慎使用!",
|
||||
"Logout": "登出",
|
||||
"Leave": "離開",
|
||||
"I understand, please disable": "我了解了,請停用",
|
||||
@@ -220,9 +220,9 @@
|
||||
"Post URL": "Post 網址",
|
||||
"Content Type": "內容類型",
|
||||
"webhookJsonDesc": "{0} 適合任何現代的 HTTP 伺服器,如 Express.js",
|
||||
"webhookFormDataDesc": "{multipart} 適合 PHP。 JSON 必須先經由 {decodeFunction} 剖析。",
|
||||
"webhookFormDataDesc": "{multipart} 適合 PHP。 JSON 必須先經由 {decodeFunction} 剖析",
|
||||
"webhookAdditionalHeadersTitle": "額外標頭",
|
||||
"webhookAdditionalHeadersDesc": "設定與 webhook 一同傳送的額外標頭。",
|
||||
"webhookAdditionalHeadersDesc": "設置 webhook 請求的額外 Header。每一個 Header 應被定義為一對 JSON 鍵值對。",
|
||||
"smtp": "Email (SMTP)",
|
||||
"secureOptionNone": "無 / STARTTLS (25, 587)",
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
@@ -323,14 +323,14 @@
|
||||
"Body": "主體",
|
||||
"Headers": "標頭",
|
||||
"PushUrl": "Push 網址",
|
||||
"HeadersInvalidFormat": "要求標頭不是有效的 JSON:",
|
||||
"BodyInvalidFormat": "要求主體不是有效的 JSON:",
|
||||
"HeadersInvalidFormat": "要求標頭不是有效的 JSON: ",
|
||||
"BodyInvalidFormat": "要求主體不是有效的 JSON: ",
|
||||
"Monitor History": "監測器歷史紀錄",
|
||||
"clearDataOlderThan": "保留 {0} 天內的監測器歷史紀錄。",
|
||||
"PasswordsDoNotMatch": "密碼不相符。",
|
||||
"records": "記錄",
|
||||
"One record": "一項記錄",
|
||||
"steamApiKeyDescription": "若要監測 Steam 遊戲伺服器,您將需要 Steam Web-API 金鑰。您可以在此註冊您的 API 金鑰:",
|
||||
"steamApiKeyDescription": "若要監測 Steam 遊戲伺服器,您將需要 Steam Web-API 金鑰。您可以在此註冊您的 API 金鑰: ",
|
||||
"Current User": "目前使用者",
|
||||
"topic": "Topic",
|
||||
"topicExplanation": "要監測的 MQTT Topic",
|
||||
@@ -436,7 +436,7 @@
|
||||
"PhoneNumbers": "PhoneNumbers",
|
||||
"TemplateCode": "TemplateCode",
|
||||
"SignName": "SignName",
|
||||
"Sms template must contain parameters: ": "Sms 範本必須包含參數:",
|
||||
"Sms template must contain parameters: ": "Sms 範本必須包含參數: ",
|
||||
"Bark Endpoint": "Bark 端點",
|
||||
"Bark Group": "Bark 群組",
|
||||
"Bark Sound": "Bark 鈴聲",
|
||||
@@ -590,7 +590,7 @@
|
||||
"Examples": "範例",
|
||||
"Home Assistant URL": "Home Assistant 網址",
|
||||
"Long-Lived Access Token": "長期有效存取權杖",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "若要建立長期有效存取權杖,請點擊您的個人檔案名稱 (左下角),捲動至最下方,然後點擊建立權杖。",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "若要建立長期有效存取權杖,請點擊您的個人檔案名稱 (左下角),捲動至最下方,然後點擊建立權杖。 ",
|
||||
"Notification Service": "通知服務",
|
||||
"default: notify all devices": "預設:通知所有服務",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "您可以在 Home Assistant 中查看通知服務的列表,在\"開發者工具 > 服務\"下搜尋\"通知\"來找到您的裝置/手機的名稱。",
|
||||
@@ -644,7 +644,7 @@
|
||||
"Server Timezone": "伺服器時區",
|
||||
"statusPageMaintenanceEndDate": "結束",
|
||||
"IconUrl": "圖示網址",
|
||||
"Enable DNS Cache": "啟用 DNS 快取",
|
||||
"Enable DNS Cache": "(已棄用)為 HTTP(s) 監控項啟用 DNS 緩存",
|
||||
"Enable": "啟用",
|
||||
"Disable": "停用",
|
||||
"dnsCacheDescription": "在某些 IPv6 環境可能會無法運作,如果您遇到任何問題,請停用。",
|
||||
@@ -689,7 +689,7 @@
|
||||
"telegramProtectContentDescription": "如果啟用,Telegram 中的機器人訊息將受到保護,不會被轉發和保存。",
|
||||
"installing": "安裝中",
|
||||
"uninstall": "卸載",
|
||||
"loadingError": "無法獲取數據, 請重試",
|
||||
"loadingError": "無法獲取數據, 請重試。",
|
||||
"markdownSupported": "支援 Markdown 語法",
|
||||
"Packet Size": "數據包大小",
|
||||
"statusPageRefreshIn": "將於 {0} 後刷新",
|
||||
@@ -705,7 +705,7 @@
|
||||
"dataRetentionTimeError": "保留期限必須為 0 或正數",
|
||||
"infiniteRetention": "設定為 0 以作無限期保留。",
|
||||
"confirmDeleteTagMsg": "你確定你要刪除此標籤?相關的監測器不會被刪除。",
|
||||
"twilioAuthToken": "認證 Token",
|
||||
"twilioAuthToken": "認證 Token / API 金鑰",
|
||||
"twilioAccountSID": "帳號 SID",
|
||||
"ntfyUsernameAndPassword": "使用者名稱和密碼",
|
||||
"ntfyAuthenticationMethod": "認證類型",
|
||||
@@ -748,5 +748,41 @@
|
||||
"Home": "首頁",
|
||||
"chromeExecutable": "Chrome/Chromium 執行檔",
|
||||
"chromeExecutableAutoDetect": "自動偵測",
|
||||
"pagertreeCritical": "緊急"
|
||||
"pagertreeCritical": "緊急",
|
||||
"PushDeer Server": "PushDeer 伺服器",
|
||||
"pushDeerServerDescription": "留空則使用官方伺服器",
|
||||
"Body Encoding": "請求體編碼",
|
||||
"filterActive": "啟用",
|
||||
"filterActivePaused": "暫停",
|
||||
"Select": "選擇",
|
||||
"enableNSCD": "啟用 NSCD(名稱服務緩存)以緩存所有 DNS 請求",
|
||||
"Server URL should not contain the nfty topic": "服務器地址不應包含 ntfy主題",
|
||||
"Invert Keyword": "反轉模式",
|
||||
"Request Timeout": "請求超時",
|
||||
"timeoutAfter": "{0} 秒後超時",
|
||||
"styleElapsedTime": "在監控項詳情的心跳欄下顯示起止時間",
|
||||
"styleElapsedTimeShowNoLine": "顯示(不帶連接線)",
|
||||
"styleElapsedTimeShowWithLine": "顯示(帶連接線)",
|
||||
"webhookCustomBodyDesc": "為 webhook 設定一個自定義 HTTP 請求體。可在模板內使用{msg},、{heartbeat}和{monitor} 變量。",
|
||||
"webhookBodyPresetOption": "預設 - {0}",
|
||||
"webhookBodyCustomOption": "自定義內容",
|
||||
"selectedMonitorCount": "已選:{0}",
|
||||
"Check/Uncheck": "選中/取消選中",
|
||||
"tailscalePingWarning": "如需使用 Tailscale Ping 客戶端,您需要以非 docker 方式安裝 Uptime Kuma,並同時安裝 Tailscale 客戶端。",
|
||||
"invertKeywordDescription": "出現關鍵詞將令檢測結果設為失敗,而非成功。",
|
||||
"jsonQueryDescription": "對響應結果執行一次 JSON 查詢,其返回值將會被轉換為字符串,再與期望值進行比較。可訪問<a href='https://jsonata.org/'>jsonata.org</a> 閱讀JSON 查詢語言的文檔,或在<a href='https://try.jsonata.org/'>此處</a>測試查詢語句。",
|
||||
"wayToGetKookGuildID": "在 Kook 設置中打開“開發者模式”,然後右鍵點擊頻道可獲取其 ID",
|
||||
"Notify Channel": "通知該頻道",
|
||||
"aboutNotifyChannel": "勾選“通知該頻道”,會令該頻道內所有成員都收到一條桌面端或移動端通知,無論其狀態是在線或離開。",
|
||||
"pagertreeIntegrationUrl": "集成 URL 地址",
|
||||
"pagertreeUrgency": "緊急程度",
|
||||
"Expected Value": "預期值",
|
||||
"Json Query": "JSON 查詢",
|
||||
"setupDatabaseChooseDatabase": "您想使用什麼資料庫?",
|
||||
"setupDatabaseEmbeddedMariaDB": "您不需要設置任何東西。 此 docker 映像檔已自動為您嵌入並配置了 MariaDB。 Uptime Kuma 將通過 unix 套接字連接到該資料庫。",
|
||||
"setupDatabaseMariaDB": "連接到外部 MariaDB 資料庫。 需要設置資料庫連接資訊。",
|
||||
"dbName": "資料庫名稱",
|
||||
"Show Clickable Link": "顯示可點擊連結",
|
||||
"pagertreeSilent": "靜音",
|
||||
"twilioApiKey": "API 金鑰 (選用)"
|
||||
}
|
||||
|
@@ -117,12 +117,23 @@
|
||||
{{ $t("Settings") }}
|
||||
</router-link>
|
||||
</nav>
|
||||
|
||||
<button
|
||||
v-if="numActiveToasts != 0"
|
||||
type="button"
|
||||
class="btn btn-normal clear-all-toast-btn"
|
||||
@click="clearToasts"
|
||||
>
|
||||
<font-awesome-icon icon="times" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Login from "../components/Login.vue";
|
||||
import compareVersions from "compare-versions";
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
|
||||
@@ -131,7 +142,11 @@ export default {
|
||||
},
|
||||
|
||||
data() {
|
||||
return {};
|
||||
return {
|
||||
toastContainer: null,
|
||||
numActiveToasts: 0,
|
||||
toastContainerObserver: null,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
@@ -159,11 +174,34 @@ export default {
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.toastContainer = document.querySelector(".bottom-right.toast-container");
|
||||
|
||||
// Watch the number of active toasts
|
||||
this.toastContainerObserver = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.type === "childList") {
|
||||
this.numActiveToasts = mutation.target.children.length;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (this.toastContainer != null) {
|
||||
this.toastContainerObserver.observe(this.toastContainer, { childList: true });
|
||||
}
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.toastContainerObserver.disconnect();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* Clear all toast notifications.
|
||||
* @returns {void}
|
||||
*/
|
||||
clearToasts() {
|
||||
toast.clear();
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
@@ -323,4 +361,26 @@ main {
|
||||
background-color: $dark-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.clear-all-toast-btn {
|
||||
position: fixed;
|
||||
right: 1em;
|
||||
bottom: 1em;
|
||||
font-size: 1.2em;
|
||||
padding: 9px 15px;
|
||||
width: 48px;
|
||||
box-shadow: 2px 2px 30px rgba(0, 0, 0, 0.2);
|
||||
z-index: 100;
|
||||
|
||||
.dark & {
|
||||
box-shadow: 2px 2px 30px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 770px) {
|
||||
.clear-all-toast-btn {
|
||||
bottom: 72px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@@ -20,6 +20,7 @@ import dayjs from "dayjs";
|
||||
import timezone from "./modules/dayjs/plugin/timezone";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import { loadToastSettings } from "./util-frontend";
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
dayjs.extend(relativeTime);
|
||||
@@ -44,11 +45,7 @@ const app = createApp({
|
||||
app.use(router);
|
||||
app.use(i18n);
|
||||
|
||||
const options = {
|
||||
position: "bottom-right",
|
||||
};
|
||||
|
||||
app.use(Toast, options);
|
||||
app.use(Toast, loadToastSettings());
|
||||
app.component("Editable", contenteditable);
|
||||
app.component("FontAwesomeIcon", FontAwesomeIcon);
|
||||
|
||||
|
@@ -14,8 +14,9 @@ export default {
|
||||
methods: {
|
||||
/**
|
||||
* Convert value to UTC
|
||||
* @param {string | number | Date | dayjs.Dayjs} value
|
||||
* @returns {dayjs.Dayjs}
|
||||
* @param {string | number | Date | dayjs.Dayjs} value Time
|
||||
* value to convert
|
||||
* @returns {dayjs.Dayjs} Converted time
|
||||
*/
|
||||
toUTC(value) {
|
||||
return dayjs.tz(value, this.timezone).utc().format();
|
||||
@@ -23,8 +24,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Used for <input type="datetime" />
|
||||
* @param value
|
||||
* @returns {string}
|
||||
* @param {string | number | Date | dayjs.Dayjs} value Value to
|
||||
* convert
|
||||
* @returns {string} Datetime string
|
||||
*/
|
||||
toDateTimeInputFormat(value) {
|
||||
return this.datetimeFormat(value, "YYYY-MM-DDTHH:mm");
|
||||
@@ -33,7 +35,7 @@ export default {
|
||||
/**
|
||||
* Return a given value in the format YYYY-MM-DD HH:mm:ss
|
||||
* @param {any} value Value to format as date time
|
||||
* @returns {string}
|
||||
* @returns {string} Formatted string
|
||||
*/
|
||||
datetime(value) {
|
||||
return this.datetimeFormat(value, "YYYY-MM-DD HH:mm:ss");
|
||||
@@ -41,8 +43,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Get time for maintenance
|
||||
* @param {string | number | Date | dayjs.Dayjs} value
|
||||
* @returns {string}
|
||||
* @param {string | number | Date | dayjs.Dayjs} value Time to
|
||||
* format
|
||||
* @returns {string} Formatted string
|
||||
*/
|
||||
datetimeMaintenance(value) {
|
||||
const inputDate = new Date(value);
|
||||
@@ -58,7 +61,7 @@ export default {
|
||||
/**
|
||||
* Return a given value in the format YYYY-MM-DD
|
||||
* @param {any} value Value to format as date
|
||||
* @returns {string}
|
||||
* @returns {string} Formatted string
|
||||
*/
|
||||
date(value) {
|
||||
return this.datetimeFormat(value, "YYYY-MM-DD");
|
||||
@@ -69,7 +72,7 @@ export default {
|
||||
* to true, HH:mm:ss
|
||||
* @param {any} value Value to format
|
||||
* @param {boolean} second Should seconds be included?
|
||||
* @returns {string}
|
||||
* @returns {string} Formatted string
|
||||
*/
|
||||
time(value, second = true) {
|
||||
let secondString;
|
||||
@@ -85,7 +88,7 @@ export default {
|
||||
* Return a value in a custom format
|
||||
* @param {any} value Value to format
|
||||
* @param {any} format Format to return value in
|
||||
* @returns {string}
|
||||
* @returns {string} Formatted string
|
||||
*/
|
||||
datetimeFormat(value, format) {
|
||||
if (value !== undefined && value !== "") {
|
||||
|
@@ -22,7 +22,11 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Change the application language */
|
||||
/**
|
||||
* Change the application language
|
||||
* @param {string} lang Language code to switch to
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async changeLang(lang) {
|
||||
let message = (await langModules["../lang/" + lang + ".json"]()).default;
|
||||
this.$i18n.setLocaleMessage(lang, message);
|
||||
|
@@ -12,13 +12,19 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Handle screen resize */
|
||||
/**
|
||||
* Handle screen resize
|
||||
* @returns {void}
|
||||
*/
|
||||
onResize() {
|
||||
this.windowWidth = window.innerWidth;
|
||||
this.updateBody();
|
||||
},
|
||||
|
||||
/** Add css-class "mobile" to body if needed */
|
||||
/**
|
||||
* Add css-class "mobile" to body if needed
|
||||
* @returns {void}
|
||||
*/
|
||||
updateBody() {
|
||||
if (this.isMobile) {
|
||||
document.body.classList.add("mobile");
|
||||
|
@@ -3,8 +3,10 @@ import { useToast } from "vue-toastification";
|
||||
import jwtDecode from "jwt-decode";
|
||||
import Favico from "favico.js";
|
||||
import dayjs from "dayjs";
|
||||
import mitt from "mitt";
|
||||
|
||||
import { DOWN, MAINTENANCE, PENDING, UP } from "../util.ts";
|
||||
import { getDevContainerServerHostname, isDevContainer } from "../util-frontend.js";
|
||||
import { getDevContainerServerHostname, isDevContainer, getToastSuccessTimeout, getToastErrorTimeout } from "../util-frontend.js";
|
||||
const toast = useToast();
|
||||
|
||||
let socket;
|
||||
@@ -39,7 +41,6 @@ export default {
|
||||
maintenanceList: {},
|
||||
apiKeyList: {},
|
||||
heartbeatList: { },
|
||||
importantHeartbeatList: { },
|
||||
avgPingList: { },
|
||||
uptimeList: { },
|
||||
tlsInfoList: {},
|
||||
@@ -59,6 +60,7 @@ export default {
|
||||
currentPassword: "",
|
||||
},
|
||||
faviconUpdateDebounce: null,
|
||||
emitter: mitt(),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -70,9 +72,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Initialize connection to socket server
|
||||
* @param {boolean} [bypass = false] Should the check for if we
|
||||
* @param {boolean} bypass Should the check for if we
|
||||
* are on a status page be bypassed?
|
||||
* @returns {(void|null)}
|
||||
* @returns {void}
|
||||
*/
|
||||
initSocketIO(bypass = false) {
|
||||
// No need to re-init
|
||||
@@ -89,6 +91,11 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// Also don't need to connect to the socket.io for setup database page
|
||||
if (location.pathname === "/setup-database") {
|
||||
return;
|
||||
}
|
||||
|
||||
this.socket.initedSocketIO = true;
|
||||
|
||||
let protocol = (location.protocol === "https:") ? "wss://" : "ws://";
|
||||
@@ -185,22 +192,18 @@ export default {
|
||||
if (this.monitorList[data.monitorID] !== undefined) {
|
||||
if (data.status === 0) {
|
||||
toast.error(`[${this.monitorList[data.monitorID].name}] [DOWN] ${data.msg}`, {
|
||||
timeout: false,
|
||||
timeout: getToastErrorTimeout(),
|
||||
});
|
||||
} else if (data.status === 1) {
|
||||
toast.success(`[${this.monitorList[data.monitorID].name}] [Up] ${data.msg}`, {
|
||||
timeout: 20000,
|
||||
timeout: getToastSuccessTimeout(),
|
||||
});
|
||||
} else {
|
||||
toast(`[${this.monitorList[data.monitorID].name}] ${data.msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (! (data.monitorID in this.importantHeartbeatList)) {
|
||||
this.importantHeartbeatList[data.monitorID] = [];
|
||||
}
|
||||
|
||||
this.importantHeartbeatList[data.monitorID].unshift(data);
|
||||
this.emitter.emit("newImportantHeartbeat", data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -224,14 +227,6 @@ export default {
|
||||
this.tlsInfoList[monitorID] = JSON.parse(data);
|
||||
});
|
||||
|
||||
socket.on("importantHeartbeatList", (monitorID, data, overwrite) => {
|
||||
if (! (monitorID in this.importantHeartbeatList) || overwrite) {
|
||||
this.importantHeartbeatList[monitorID] = data;
|
||||
} else {
|
||||
this.importantHeartbeatList[monitorID] = data.concat(this.importantHeartbeatList[monitorID]);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("connect_error", (err) => {
|
||||
console.error(`Failed to connect to the backend. Socket.io connect_error: ${err.message}`);
|
||||
this.connectionErrorMsg = `${this.$t("Cannot connect to the socket server.")} [${err}] ${this.$t("Reconnecting...")}`;
|
||||
@@ -292,7 +287,7 @@ export default {
|
||||
|
||||
/**
|
||||
* The storage currently in use
|
||||
* @returns {Storage}
|
||||
* @returns {Storage} Current storage
|
||||
*/
|
||||
storage() {
|
||||
return (this.remember) ? localStorage : sessionStorage;
|
||||
@@ -300,7 +295,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Get payload of JWT cookie
|
||||
* @returns {(Object|undefined)}
|
||||
* @returns {(object | undefined)} JWT payload
|
||||
*/
|
||||
getJWTPayload() {
|
||||
const jwtToken = this.$root.storage().token;
|
||||
@@ -313,7 +308,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Get current socket
|
||||
* @returns {Socket}
|
||||
* @returns {Socket} Current socket
|
||||
*/
|
||||
getSocket() {
|
||||
return socket;
|
||||
@@ -321,36 +316,48 @@ export default {
|
||||
|
||||
/**
|
||||
* Show success or error toast dependant on response status code
|
||||
* @param {Object} res Response object
|
||||
* @param {object} res Response object
|
||||
* @returns {void}
|
||||
*/
|
||||
toastRes(res) {
|
||||
let msg = res.msg;
|
||||
if (res.msgi18n) {
|
||||
if (msg != null && typeof msg === "object") {
|
||||
msg = this.$t(msg.key, msg.values);
|
||||
} else {
|
||||
msg = this.$t(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (res.ok) {
|
||||
toast.success(res.msg);
|
||||
toast.success(msg);
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
toast.error(msg);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a success toast
|
||||
* @param {string} msg Message to show
|
||||
* @returns {void}
|
||||
*/
|
||||
toastSuccess(msg) {
|
||||
toast.success(msg);
|
||||
toast.success(this.$t(msg));
|
||||
},
|
||||
|
||||
/**
|
||||
* Show an error toast
|
||||
* @param {string} msg Message to show
|
||||
* @returns {void}
|
||||
*/
|
||||
toastError(msg) {
|
||||
toast.error(msg);
|
||||
toast.error(this.$t(msg));
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for login
|
||||
* @callback loginCB
|
||||
* @param {Object} res Response object
|
||||
* @param {object} res Response object
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -359,6 +366,7 @@ export default {
|
||||
* @param {string} password Password to log in with
|
||||
* @param {string} token User token
|
||||
* @param {loginCB} callback Callback to call with result
|
||||
* @returns {void}
|
||||
*/
|
||||
login(username, password, token, callback) {
|
||||
socket.emit("login", {
|
||||
@@ -387,6 +395,7 @@ export default {
|
||||
/**
|
||||
* Log in using a token
|
||||
* @param {string} token Token to log in with
|
||||
* @returns {void}
|
||||
*/
|
||||
loginByToken(token) {
|
||||
socket.emit("loginByToken", token, (res) => {
|
||||
@@ -401,7 +410,10 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Log out of the web application */
|
||||
/**
|
||||
* Log out of the web application
|
||||
* @returns {void}
|
||||
*/
|
||||
logout() {
|
||||
socket.emit("logout", () => { });
|
||||
this.storage().removeItem("token");
|
||||
@@ -414,9 +426,13 @@ export default {
|
||||
/**
|
||||
* Callback for general socket requests
|
||||
* @callback socketCB
|
||||
* @param {Object} res Result of operation
|
||||
* @param {object} res Result of operation
|
||||
*/
|
||||
/**
|
||||
* Prepare 2FA configuration
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
/** Prepare 2FA configuration */
|
||||
prepare2FA(callback) {
|
||||
socket.emit("prepare2FA", callback);
|
||||
},
|
||||
@@ -424,7 +440,8 @@ export default {
|
||||
/**
|
||||
* Save the current 2FA configuration
|
||||
* @param {any} secret Unused
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
save2FA(secret, callback) {
|
||||
socket.emit("save2FA", callback);
|
||||
@@ -432,7 +449,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Disable 2FA for this user
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
disable2FA(callback) {
|
||||
socket.emit("disable2FA", callback);
|
||||
@@ -441,7 +459,8 @@ export default {
|
||||
/**
|
||||
* Verify the provided 2FA token
|
||||
* @param {string} token Token to verify
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
verifyToken(token, callback) {
|
||||
socket.emit("verifyToken", token, callback);
|
||||
@@ -449,7 +468,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Get current 2FA status
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
twoFAStatus(callback) {
|
||||
socket.emit("twoFAStatus", callback);
|
||||
@@ -457,7 +477,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Get list of monitors
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
getMonitorList(callback) {
|
||||
if (! callback) {
|
||||
@@ -468,7 +489,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Get list of maintenances
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
getMaintenanceList(callback) {
|
||||
if (! callback) {
|
||||
@@ -479,7 +501,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Send list of API keys
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
getAPIKeyList(callback) {
|
||||
if (!callback) {
|
||||
@@ -490,17 +513,19 @@ export default {
|
||||
|
||||
/**
|
||||
* Add a monitor
|
||||
* @param {Object} monitor Object representing monitor to add
|
||||
* @param {socketCB} callback
|
||||
* @param {object} monitor Object representing monitor to add
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
add(monitor, callback) {
|
||||
socket.emit("add", monitor, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a maintenace
|
||||
* @param {Object} maintenance
|
||||
* @param {socketCB} callback
|
||||
* Adds a maintenance
|
||||
* @param {object} maintenance Maintenance to add
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
addMaintenance(maintenance, callback) {
|
||||
socket.emit("addMaintenance", maintenance, callback);
|
||||
@@ -508,9 +533,10 @@ export default {
|
||||
|
||||
/**
|
||||
* Add monitors to maintenance
|
||||
* @param {number} maintenanceID
|
||||
* @param {number[]} monitors
|
||||
* @param {socketCB} callback
|
||||
* @param {number} maintenanceID Maintenance to modify
|
||||
* @param {number[]} monitors IDs of monitors to add
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
addMonitorMaintenance(maintenanceID, monitors, callback) {
|
||||
socket.emit("addMonitorMaintenance", maintenanceID, monitors, callback);
|
||||
@@ -518,9 +544,10 @@ export default {
|
||||
|
||||
/**
|
||||
* Add status page to maintenance
|
||||
* @param {number} maintenanceID
|
||||
* @param {number} statusPages
|
||||
* @param {socketCB} callback
|
||||
* @param {number} maintenanceID Maintenance to modify
|
||||
* @param {number} statusPages ID of status page to add
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
addMaintenanceStatusPage(maintenanceID, statusPages, callback) {
|
||||
socket.emit("addMaintenanceStatusPage", maintenanceID, statusPages, callback);
|
||||
@@ -528,8 +555,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Get monitors affected by maintenance
|
||||
* @param {number} maintenanceID
|
||||
* @param {socketCB} callback
|
||||
* @param {number} maintenanceID Maintenance to read
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
getMonitorMaintenance(maintenanceID, callback) {
|
||||
socket.emit("getMonitorMaintenance", maintenanceID, callback);
|
||||
@@ -537,8 +565,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Get status pages where maintenance is shown
|
||||
* @param {number} maintenanceID
|
||||
* @param {socketCB} callback
|
||||
* @param {number} maintenanceID Maintenance to read
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
getMaintenanceStatusPage(maintenanceID, callback) {
|
||||
socket.emit("getMaintenanceStatusPage", maintenanceID, callback);
|
||||
@@ -547,7 +576,8 @@ export default {
|
||||
/**
|
||||
* Delete monitor by ID
|
||||
* @param {number} monitorID ID of monitor to delete
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteMonitor(monitorID, callback) {
|
||||
socket.emit("deleteMonitor", monitorID, callback);
|
||||
@@ -555,8 +585,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Delete specified maintenance
|
||||
* @param {number} maintenanceID
|
||||
* @param {socketCB} callback
|
||||
* @param {number} maintenanceID Maintenance to delete
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteMaintenance(maintenanceID, callback) {
|
||||
socket.emit("deleteMaintenance", maintenanceID, callback);
|
||||
@@ -564,8 +595,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Add an API key
|
||||
* @param {Object} key API key to add
|
||||
* @param {socketCB} callback
|
||||
* @param {object} key API key to add
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
addAPIKey(key, callback) {
|
||||
socket.emit("addAPIKey", key, callback);
|
||||
@@ -574,17 +606,20 @@ export default {
|
||||
/**
|
||||
* Delete specified API key
|
||||
* @param {int} keyID ID of key to delete
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteAPIKey(keyID, callback) {
|
||||
socket.emit("deleteAPIKey", keyID, callback);
|
||||
},
|
||||
|
||||
/** Clear the hearbeat list */
|
||||
/**
|
||||
* Clear the hearbeat list
|
||||
* @returns {void}
|
||||
*/
|
||||
clearData() {
|
||||
console.log("reset heartbeat list");
|
||||
this.heartbeatList = {};
|
||||
this.importantHeartbeatList = {};
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -592,7 +627,8 @@ export default {
|
||||
* @param {string} uploadedJSON JSON to upload
|
||||
* @param {string} importHandle Type of import. If set to
|
||||
* most data in database will be replaced
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
uploadBackup(uploadedJSON, importHandle, callback) {
|
||||
socket.emit("uploadBackup", uploadedJSON, importHandle, callback);
|
||||
@@ -601,7 +637,8 @@ export default {
|
||||
/**
|
||||
* Clear events for a specified monitor
|
||||
* @param {number} monitorID ID of monitor to clear
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
clearEvents(monitorID, callback) {
|
||||
socket.emit("clearEvents", monitorID, callback);
|
||||
@@ -610,7 +647,8 @@ export default {
|
||||
/**
|
||||
* Clear the heartbeats of a specified monitor
|
||||
* @param {number} monitorID Id of monitor to clear
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
clearHeartbeats(monitorID, callback) {
|
||||
socket.emit("clearHeartbeats", monitorID, callback);
|
||||
@@ -618,7 +656,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Clear all statistics
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
clearStatistics(callback) {
|
||||
socket.emit("clearStatistics", callback);
|
||||
@@ -628,11 +667,12 @@ export default {
|
||||
* Get monitor beats for a specific monitor in a time range
|
||||
* @param {number} monitorID ID of monitor to fetch
|
||||
* @param {number} period Time in hours from now
|
||||
* @param {socketCB} callback
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
getMonitorBeats(monitorID, period, callback) {
|
||||
socket.emit("getMonitorBeats", monitorID, period, callback);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
@@ -739,7 +779,7 @@ export default {
|
||||
* Frontend Version
|
||||
* It should be compiled to a static value while building the frontend.
|
||||
* Please see ./config/vite.config.js, it is defined via vite.js
|
||||
* @returns {string}
|
||||
* @returns {string} Current version
|
||||
*/
|
||||
frontendVersion() {
|
||||
// eslint-disable-next-line no-undef
|
||||
@@ -748,7 +788,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Are both frontend and backend in the same version?
|
||||
* @returns {boolean}
|
||||
* @returns {boolean} The frontend and backend match?
|
||||
*/
|
||||
isFrontendBackendVersionMatched() {
|
||||
if (!this.info.version) {
|
||||
|
@@ -95,7 +95,10 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** Update the theme color meta tag */
|
||||
/**
|
||||
* Update the theme color meta tag
|
||||
* @returns {void}
|
||||
*/
|
||||
updateThemeColorMeta() {
|
||||
if (this.theme === "dark") {
|
||||
document.querySelector("#theme-color").setAttribute("content", "#161B22");
|
||||
|
@@ -51,7 +51,10 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/** Submit form data to add new status page */
|
||||
/**
|
||||
* Submit form data to add new status page
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async submit() {
|
||||
this.processing = true;
|
||||
|
||||
@@ -63,7 +66,7 @@ export default {
|
||||
} else {
|
||||
|
||||
if (res.msg.includes("UNIQUE constraint")) {
|
||||
this.$root.toastError(this.$t("The slug is already taken. Please choose another slug."));
|
||||
this.$root.toastError("The slug is already taken. Please choose another slug.");
|
||||
} else {
|
||||
this.$root.toastRes(res);
|
||||
}
|
||||
|
@@ -42,13 +42,13 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(beat, index) in displayedRecords" :key="index" :class="{ 'shadow-box': $root.windowWidth <= 550}">
|
||||
<td><router-link :to="`/dashboard/${beat.monitorID}`">{{ beat.name }}</router-link></td>
|
||||
<td><router-link :to="`/dashboard/${beat.monitorID}`">{{ $root.monitorList[beat.monitorID]?.name }}</router-link></td>
|
||||
<td><Status :status="beat.status" /></td>
|
||||
<td :class="{ 'border-0':! beat.msg}"><Datetime :value="beat.time" /></td>
|
||||
<td class="border-0">{{ beat.msg }}</td>
|
||||
</tr>
|
||||
|
||||
<tr v-if="importantHeartBeatList.length === 0">
|
||||
<tr v-if="importantHeartBeatListLength === 0">
|
||||
<td colspan="4">
|
||||
{{ $t("No important events") }}
|
||||
</td>
|
||||
@@ -59,7 +59,7 @@
|
||||
<div class="d-flex justify-content-center kuma_pagination">
|
||||
<pagination
|
||||
v-model="page"
|
||||
:records="importantHeartBeatList.length"
|
||||
:records="importantHeartBeatListLength"
|
||||
:per-page="perPage"
|
||||
:options="paginationConfig"
|
||||
/>
|
||||
@@ -92,72 +92,89 @@ export default {
|
||||
page: 1,
|
||||
perPage: 25,
|
||||
initialPerPage: 25,
|
||||
heartBeatList: [],
|
||||
paginationConfig: {
|
||||
hideCount: true,
|
||||
chunksNavigation: "scroll",
|
||||
},
|
||||
importantHeartBeatListLength: 0,
|
||||
displayedRecords: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
importantHeartBeatList() {
|
||||
let result = [];
|
||||
|
||||
for (let monitorID in this.$root.importantHeartbeatList) {
|
||||
let list = this.$root.importantHeartbeatList[monitorID];
|
||||
result = result.concat(list);
|
||||
}
|
||||
|
||||
for (let beat of result) {
|
||||
let monitor = this.$root.monitorList[beat.monitorID];
|
||||
|
||||
if (monitor) {
|
||||
beat.name = monitor.name;
|
||||
}
|
||||
}
|
||||
|
||||
result.sort((a, b) => {
|
||||
if (a.time > b.time) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.time < b.time) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
this.heartBeatList = result;
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
displayedRecords() {
|
||||
const startIndex = this.perPage * (this.page - 1);
|
||||
const endIndex = startIndex + this.perPage;
|
||||
return this.heartBeatList.slice(startIndex, endIndex);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
importantHeartBeatList() {
|
||||
perPage() {
|
||||
this.$nextTick(() => {
|
||||
this.updatePerPage();
|
||||
this.getImportantHeartbeatListPaged();
|
||||
});
|
||||
},
|
||||
|
||||
page() {
|
||||
this.getImportantHeartbeatListPaged();
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getImportantHeartbeatListLength();
|
||||
|
||||
this.$root.emitter.on("newImportantHeartbeat", this.onNewImportantHeartbeat);
|
||||
|
||||
this.initialPerPage = this.perPage;
|
||||
|
||||
window.addEventListener("resize", this.updatePerPage);
|
||||
this.updatePerPage();
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.$root.emitter.off("newImportantHeartbeat", this.onNewImportantHeartbeat);
|
||||
|
||||
window.removeEventListener("resize", this.updatePerPage);
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Updates the displayed records when a new important heartbeat arrives.
|
||||
* @param {object} heartbeat - The heartbeat object received.
|
||||
* @returns {void}
|
||||
*/
|
||||
onNewImportantHeartbeat(heartbeat) {
|
||||
if (this.page === 1) {
|
||||
this.displayedRecords.unshift(heartbeat);
|
||||
if (this.displayedRecords.length > this.perPage) {
|
||||
this.displayedRecords.pop();
|
||||
}
|
||||
this.importantHeartBeatListLength += 1;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the length of the important heartbeat list for all monitors.
|
||||
* @returns {void}
|
||||
*/
|
||||
getImportantHeartbeatListLength() {
|
||||
this.$root.getSocket().emit("monitorImportantHeartbeatListCount", null, (res) => {
|
||||
if (res.ok) {
|
||||
this.importantHeartBeatListLength = res.count;
|
||||
this.getImportantHeartbeatListPaged();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the important heartbeat list for the current page.
|
||||
* @returns {void}
|
||||
*/
|
||||
getImportantHeartbeatListPaged() {
|
||||
const offset = (this.page - 1) * this.perPage;
|
||||
this.$root.getSocket().emit("monitorImportantHeartbeatListPaged", null, offset, this.perPage, (res) => {
|
||||
if (res.ok) {
|
||||
this.displayedRecords = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the number of items shown per page based on the available height.
|
||||
* @returns {void}
|
||||
*/
|
||||
updatePerPage() {
|
||||
const tableContainer = this.$refs.tableContainer;
|
||||
const tableContainerHeight = tableContainer.offsetHeight;
|
||||
|
@@ -76,6 +76,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Push Examples -->
|
||||
<div v-if="monitor.type === 'push'" class="shadow-box big-padding">
|
||||
<a href="#" @click="pushMonitor.showPushExamples = !pushMonitor.showPushExamples">{{ $t("pushViewCode") }}</a>
|
||||
|
||||
<transition name="slide-fade" appear>
|
||||
<div v-if="pushMonitor.showPushExamples" class="mt-3">
|
||||
<select id="push-current-example" v-model="pushMonitor.currentExample" class="form-select">
|
||||
<optgroup :label="$t('programmingLanguages')">
|
||||
<option value="csharp">C#</option>
|
||||
<option value="go">Go</option>
|
||||
<option value="java">Java</option>
|
||||
<option value="javascript-fetch">JavaScript (fetch)</option>
|
||||
<option value="php">PHP</option>
|
||||
<option value="python">Python</option>
|
||||
<option value="typescript-fetch">TypeScript (fetch)</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$t('pushOthers')">
|
||||
<option value="bash-curl">Bash (curl)</option>
|
||||
<option value="powershell">PowerShell</option>
|
||||
<option value="docker">Docker</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
|
||||
<prism-editor v-model="pushMonitor.code" class="css-editor mt-3" :highlight="pushExampleHighlighter" line-numbers readonly></prism-editor>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="shadow-box big-padding text-center stats">
|
||||
<div class="row">
|
||||
@@ -95,6 +123,8 @@
|
||||
<CountUp :value="avgPing" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Uptime (24-hour) -->
|
||||
<div class="col-12 col-sm col row d-flex align-items-center d-sm-block">
|
||||
<h4 class="col-4 col-sm-12">{{ $t("Uptime") }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">(24{{ $t("-hour") }})</p>
|
||||
@@ -102,6 +132,8 @@
|
||||
<Uptime :monitor="monitor" type="24" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Uptime (30-day) -->
|
||||
<div class="col-12 col-sm col row d-flex align-items-center d-sm-block">
|
||||
<h4 class="col-4 col-sm-12">{{ $t("Uptime") }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">(30{{ $t("-day") }})</p>
|
||||
@@ -110,6 +142,15 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Uptime (1-year) -->
|
||||
<div class="col-12 col-sm col row d-flex align-items-center d-sm-block">
|
||||
<h4 class="col-4 col-sm-12">{{ $t("Uptime") }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">(1{{ $t("-year") }})</p>
|
||||
<span class="col-4 col-sm-12 num">
|
||||
<Uptime :monitor="monitor" type="1y" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="tlsInfo" class="col-12 col-sm col row d-flex align-items-center d-sm-block">
|
||||
<h4 class="col-4 col-sm-12">{{ $t("Cert Exp.") }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">(<Datetime :value="tlsInfo.certInfo.validTo" date-only />)</p>
|
||||
@@ -182,7 +223,7 @@
|
||||
<td class="border-0">{{ beat.msg }}</td>
|
||||
</tr>
|
||||
|
||||
<tr v-if="importantHeartBeatList.length === 0">
|
||||
<tr v-if="importantHeartBeatListLength === 0">
|
||||
<td colspan="3">
|
||||
{{ $t("No important events") }}
|
||||
</td>
|
||||
@@ -193,7 +234,7 @@
|
||||
<div class="d-flex justify-content-center kuma_pagination">
|
||||
<pagination
|
||||
v-model="page"
|
||||
:records="importantHeartBeatList.length"
|
||||
:records="importantHeartBeatListLength"
|
||||
:per-page="perPage"
|
||||
:options="paginationConfig"
|
||||
/>
|
||||
@@ -236,6 +277,12 @@ import CertificateInfo from "../components/CertificateInfo.vue";
|
||||
import { getMonitorRelativeURL } from "../util.ts";
|
||||
import { URL } from "whatwg-url";
|
||||
import { getResBaseURL } from "../util-frontend";
|
||||
import { highlight, languages } from "prismjs/components/prism-core";
|
||||
import "prismjs/components/prism-clike";
|
||||
import "prismjs/components/prism-javascript";
|
||||
import "prismjs/components/prism-css";
|
||||
import { PrismEditor } from "vue-prism-editor";
|
||||
import "vue-prism-editor/dist/prismeditor.min.css";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -249,6 +296,7 @@ export default {
|
||||
PingChart,
|
||||
Tag,
|
||||
CertificateInfo,
|
||||
PrismEditor,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -262,6 +310,13 @@ export default {
|
||||
chunksNavigation: "scroll",
|
||||
},
|
||||
cacheTime: Date.now(),
|
||||
importantHeartBeatListLength: 0,
|
||||
displayedRecords: [],
|
||||
pushMonitor: {
|
||||
showPushExamples: false,
|
||||
currentExample: "javascript-fetch",
|
||||
code: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -300,16 +355,6 @@ export default {
|
||||
return this.$t("notAvailableShort");
|
||||
},
|
||||
|
||||
importantHeartBeatList() {
|
||||
if (this.$root.importantHeartbeatList[this.monitor.id]) {
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
this.heartBeatList = this.$root.importantHeartbeatList[this.monitor.id];
|
||||
return this.$root.importantHeartbeatList[this.monitor.id];
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
status() {
|
||||
if (this.$root.statusList[this.monitor.id]) {
|
||||
return this.$root.statusList[this.monitor.id];
|
||||
@@ -333,12 +378,6 @@ export default {
|
||||
return this.tlsInfo != null && this.toggleCertInfoBox;
|
||||
},
|
||||
|
||||
displayedRecords() {
|
||||
const startIndex = this.perPage * (this.page - 1);
|
||||
const endIndex = startIndex + this.perPage;
|
||||
return this.heartBeatList.slice(startIndex, endIndex);
|
||||
},
|
||||
|
||||
group() {
|
||||
if (!this.monitor.pathName.includes("/")) {
|
||||
return "";
|
||||
@@ -354,73 +393,136 @@ export default {
|
||||
return getResBaseURL() + this.monitor.screenshot + "?time=" + this.cacheTime;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
getResBaseURL,
|
||||
/** Request a test notification be sent for this monitor */
|
||||
testNotification() {
|
||||
this.$root.getSocket().emit("testNotification", this.monitor.id);
|
||||
toast.success("Test notification is requested.");
|
||||
watch: {
|
||||
page(to) {
|
||||
this.getImportantHeartbeatListPaged();
|
||||
},
|
||||
|
||||
/** Show dialog to confirm pause */
|
||||
monitor(to) {
|
||||
this.getImportantHeartbeatListLength();
|
||||
},
|
||||
"monitor.type"() {
|
||||
if (this.monitor && this.monitor.type === "push") {
|
||||
this.loadPushExample();
|
||||
}
|
||||
},
|
||||
"pushMonitor.currentExample"() {
|
||||
this.loadPushExample();
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getImportantHeartbeatListLength();
|
||||
|
||||
this.$root.emitter.on("newImportantHeartbeat", this.onNewImportantHeartbeat);
|
||||
|
||||
if (this.monitor && this.monitor.type === "push") {
|
||||
if (this.lastHeartBeat.status === -1) {
|
||||
this.pushMonitor.showPushExamples = true;
|
||||
}
|
||||
this.loadPushExample();
|
||||
}
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.$root.emitter.off("newImportantHeartbeat", this.onNewImportantHeartbeat);
|
||||
},
|
||||
|
||||
methods: {
|
||||
getResBaseURL,
|
||||
/**
|
||||
* Request a test notification be sent for this monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
testNotification() {
|
||||
this.$root.getSocket().emit("testNotification", this.monitor.id);
|
||||
this.$root.toastSuccess("Test notification is requested.");
|
||||
},
|
||||
|
||||
/**
|
||||
* Show dialog to confirm pause
|
||||
* @returns {void}
|
||||
*/
|
||||
pauseDialog() {
|
||||
this.$refs.confirmPause.show();
|
||||
},
|
||||
|
||||
/** Resume this monitor */
|
||||
/**
|
||||
* Resume this monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
resumeMonitor() {
|
||||
this.$root.getSocket().emit("resumeMonitor", this.monitor.id, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
});
|
||||
},
|
||||
|
||||
/** Request that this monitor is paused */
|
||||
/**
|
||||
* Request that this monitor is paused
|
||||
* @returns {void}
|
||||
*/
|
||||
pauseMonitor() {
|
||||
this.$root.getSocket().emit("pauseMonitor", this.monitor.id, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
});
|
||||
},
|
||||
|
||||
/** Show dialog to confirm deletion */
|
||||
/**
|
||||
* Show dialog to confirm deletion
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteDialog() {
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
/** Show dialog to confirm clearing events */
|
||||
/**
|
||||
* Show dialog to confirm clearing events
|
||||
* @returns {void}
|
||||
*/
|
||||
clearEventsDialog() {
|
||||
this.$refs.confirmClearEvents.show();
|
||||
},
|
||||
|
||||
/** Show dialog to confirm clearing heartbeats */
|
||||
/**
|
||||
* Show dialog to confirm clearing heartbeats
|
||||
* @returns {void}
|
||||
*/
|
||||
clearHeartbeatsDialog() {
|
||||
this.$refs.confirmClearHeartbeats.show();
|
||||
},
|
||||
|
||||
/** Request that this monitor is deleted */
|
||||
/**
|
||||
* Request that this monitor is deleted
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteMonitor() {
|
||||
this.$root.deleteMonitor(this.monitor.id, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
if (res.ok) {
|
||||
toast.success(res.msg);
|
||||
this.$router.push("/dashboard");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request that this monitors events are cleared
|
||||
* @returns {void}
|
||||
*/
|
||||
clearEvents() {
|
||||
this.$root.clearEvents(this.monitor.id, (res) => {
|
||||
if (res.ok) {
|
||||
this.getImportantHeartbeatListLength();
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Request that this monitors events are cleared */
|
||||
clearEvents() {
|
||||
this.$root.clearEvents(this.monitor.id, (res) => {
|
||||
if (! res.ok) {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Request that this monitors heartbeats are cleared */
|
||||
/**
|
||||
* Request that this monitors heartbeats are cleared
|
||||
* @returns {void}
|
||||
*/
|
||||
clearHeartbeats() {
|
||||
this.$root.clearHeartbeats(this.monitor.id, (res) => {
|
||||
if (! res.ok) {
|
||||
@@ -431,8 +533,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Return the correct title for the ping stat
|
||||
* @param {boolean} [average=false] Is the statistic an average?
|
||||
* @returns {string} Title formated dependant on monitor type
|
||||
* @param {boolean} average Is the statistic an average?
|
||||
* @returns {string} Title formatted dependant on monitor type
|
||||
*/
|
||||
pingTitle(average = false) {
|
||||
let translationPrefix = "";
|
||||
@@ -456,7 +558,11 @@ export default {
|
||||
return getMonitorRelativeURL(id);
|
||||
},
|
||||
|
||||
/** Filter and hide password in URL for display */
|
||||
/**
|
||||
* Filter and hide password in URL for display
|
||||
* @param {string} urlString URL to censor
|
||||
* @returns {string} Censored URL
|
||||
*/
|
||||
filterPassword(urlString) {
|
||||
try {
|
||||
let parsedUrl = new URL(urlString);
|
||||
@@ -468,6 +574,72 @@ export default {
|
||||
// Handle SQL Server
|
||||
return urlString.replaceAll(/Password=(.+);/ig, "Password=******;");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the length of the important heartbeat list for this monitor.
|
||||
* @returns {void}
|
||||
*/
|
||||
getImportantHeartbeatListLength() {
|
||||
if (this.monitor) {
|
||||
this.$root.getSocket().emit("monitorImportantHeartbeatListCount", this.monitor.id, (res) => {
|
||||
if (res.ok) {
|
||||
this.importantHeartBeatListLength = res.count;
|
||||
this.getImportantHeartbeatListPaged();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the important heartbeat list for the current page.
|
||||
* @returns {void}
|
||||
*/
|
||||
getImportantHeartbeatListPaged() {
|
||||
if (this.monitor) {
|
||||
const offset = (this.page - 1) * this.perPage;
|
||||
this.$root.getSocket().emit("monitorImportantHeartbeatListPaged", this.monitor.id, offset, this.perPage, (res) => {
|
||||
if (res.ok) {
|
||||
this.displayedRecords = res.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the displayed records when a new important heartbeat arrives.
|
||||
* @param {object} heartbeat - The heartbeat object received.
|
||||
* @returns {void}
|
||||
*/
|
||||
onNewImportantHeartbeat(heartbeat) {
|
||||
if (heartbeat.monitorID === this.monitor?.id) {
|
||||
if (this.page === 1) {
|
||||
this.displayedRecords.unshift(heartbeat);
|
||||
if (this.displayedRecords.length > this.perPage) {
|
||||
this.displayedRecords.pop();
|
||||
}
|
||||
this.importantHeartBeatListLength += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Highlight the example code
|
||||
* @param {string} code Code
|
||||
* @returns {string} Highlighted code
|
||||
*/
|
||||
pushExampleHighlighter(code) {
|
||||
return highlight(code, languages.js);
|
||||
},
|
||||
|
||||
loadPushExample() {
|
||||
this.pushMonitor.code = "";
|
||||
this.$root.getSocket().emit("getPushExample", this.pushMonitor.currentExample, (res) => {
|
||||
let code = res.code
|
||||
.replace("60", this.monitor.interval)
|
||||
.replace("https://example.com/api/push/key?status=up&msg=OK&ping=", this.pushURL);
|
||||
this.pushMonitor.code = code;
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@@ -246,14 +246,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useToast } from "vue-toastification";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import Datepicker from "@vuepic/vue-datepicker";
|
||||
import { timezoneList } from "../util-frontend";
|
||||
import cronstrue from "cronstrue/i18n";
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VueMultiselect,
|
||||
@@ -417,7 +414,10 @@ export default {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
/** Initialise page */
|
||||
/**
|
||||
* Initialise page
|
||||
* @returns {void}
|
||||
*/
|
||||
init() {
|
||||
this.affectedMonitors = [];
|
||||
this.selectedStatusPages = [];
|
||||
@@ -454,7 +454,7 @@ export default {
|
||||
this.affectedMonitors.push(this.affectedMonitorsOptions.find(item => item.id === monitor.id));
|
||||
});
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -469,22 +469,25 @@ export default {
|
||||
|
||||
this.showOnAllPages = Object.values(res.statusPages).length === this.selectedStatusPagesOptions.length;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/** Create new maintenance */
|
||||
/**
|
||||
* Create new maintenance
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async submit() {
|
||||
this.processing = true;
|
||||
|
||||
if (this.affectedMonitors.length === 0) {
|
||||
toast.error(this.$t("atLeastOneMonitor"));
|
||||
this.$root.toastError(this.$t("atLeastOneMonitor"));
|
||||
return this.processing = false;
|
||||
}
|
||||
|
||||
@@ -493,14 +496,14 @@ export default {
|
||||
if (res.ok) {
|
||||
await this.addMonitorMaintenance(res.maintenanceID, async () => {
|
||||
await this.addMaintenanceStatusPage(res.maintenanceID, () => {
|
||||
toast.success(res.msg);
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
this.$root.getMaintenanceList();
|
||||
this.$router.push("/maintenance");
|
||||
});
|
||||
});
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
}
|
||||
|
||||
@@ -518,7 +521,7 @@ export default {
|
||||
});
|
||||
} else {
|
||||
this.processing = false;
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -526,13 +529,14 @@ export default {
|
||||
|
||||
/**
|
||||
* Add monitor to maintenance
|
||||
* @param {number} maintenanceID
|
||||
* @param {socketCB} callback
|
||||
* @param {number} maintenanceID ID of maintenance to modify
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async addMonitorMaintenance(maintenanceID, callback) {
|
||||
await this.$root.addMonitorMaintenance(maintenanceID, this.affectedMonitors, async (res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
} else {
|
||||
this.$root.getMonitorList();
|
||||
}
|
||||
@@ -543,13 +547,14 @@ export default {
|
||||
|
||||
/**
|
||||
* Add status page to maintenance
|
||||
* @param {number} maintenanceID
|
||||
* @param {socketCB} callback
|
||||
* @param {number} maintenanceID ID of maintenance to modify
|
||||
* @param {socketCB} callback Callback for socket response
|
||||
* @returns {void}
|
||||
*/
|
||||
async addMaintenanceStatusPage(maintenanceID, callback) {
|
||||
await this.$root.addMaintenanceStatusPage(maintenanceID, (this.showOnAllPages) ? this.selectedStatusPagesOptions : this.selectedStatusPages, async (res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
} else {
|
||||
this.$root.getMaintenanceList();
|
||||
}
|
||||
|
@@ -119,6 +119,9 @@
|
||||
{{ $t("needPushEvery", [monitor.interval]) }}<br />
|
||||
{{ $t("pushOptionalParams", ["status, msg, ping"]) }}
|
||||
</div>
|
||||
<button class="btn btn-primary" type="button" @click="resetToken">
|
||||
{{ $t("Reset Token") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Keyword -->
|
||||
@@ -658,6 +661,7 @@
|
||||
<label for="httpBodyEncoding" class="form-label">{{ $t("Body Encoding") }}</label>
|
||||
<select id="httpBodyEncoding" v-model="monitor.httpBodyEncoding" class="form-select">
|
||||
<option value="json">JSON</option>
|
||||
<option value="form">x-www-form-urlencoded</option>
|
||||
<option value="xml">XML</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -849,7 +853,9 @@ import { hostNameRegexPattern } from "../util-frontend";
|
||||
import { sleep } from "../util";
|
||||
import HiddenInput from "../components/HiddenInput.vue";
|
||||
|
||||
const toast = useToast();
|
||||
const toast = useToast;
|
||||
|
||||
const pushTokenLength = 32;
|
||||
|
||||
const monitorDefaults = {
|
||||
type: "http",
|
||||
@@ -1010,6 +1016,9 @@ message HealthCheckResponse {
|
||||
</soap:Body>
|
||||
</soap:Envelope>` ]);
|
||||
}
|
||||
if (this.monitor && this.monitor.httpBodyEncoding === "form") {
|
||||
return this.$t("Example:", [ "key1=value1&key2=value2" ]);
|
||||
}
|
||||
return this.$t("Example:", [ `
|
||||
{
|
||||
"key": "value"
|
||||
@@ -1077,8 +1086,7 @@ message HealthCheckResponse {
|
||||
|
||||
/**
|
||||
* Generates the parent monitor options list based on the sorted group monitor list and draft group name.
|
||||
*
|
||||
* @return {Array} The parent monitor options list.
|
||||
* @returns {Array} The parent monitor options list.
|
||||
*/
|
||||
parentMonitorOptionsList() {
|
||||
let list = [];
|
||||
@@ -1164,7 +1172,9 @@ message HealthCheckResponse {
|
||||
"monitor.type"() {
|
||||
if (this.monitor.type === "push") {
|
||||
if (! this.monitor.pushToken) {
|
||||
this.monitor.pushToken = genSecret(10);
|
||||
// ideally this would require checking if the generated token is already used
|
||||
// it's very unlikely to get a collision though (62^32 ~ 2.27265788 * 10^57 unique tokens)
|
||||
this.monitor.pushToken = genSecret(pushTokenLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1185,7 +1195,7 @@ message HealthCheckResponse {
|
||||
if (res.ok) {
|
||||
this.gameList = res.gameList;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1257,7 +1267,10 @@ message HealthCheckResponse {
|
||||
this.kafkaSaslMechanismOptions = kafkaSaslMechanismOptions;
|
||||
},
|
||||
methods: {
|
||||
/** Initialize the edit monitor form */
|
||||
/**
|
||||
* Initialize the edit monitor form
|
||||
* @returns {void}
|
||||
*/
|
||||
init() {
|
||||
if (this.isAdd) {
|
||||
|
||||
@@ -1327,7 +1340,7 @@ message HealthCheckResponse {
|
||||
this.monitor.timeout = ~~(this.monitor.interval * 8) / 10;
|
||||
}
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1370,6 +1383,10 @@ message HealthCheckResponse {
|
||||
return true;
|
||||
},
|
||||
|
||||
resetToken() {
|
||||
this.monitor.pushToken = genSecret(pushTokenLength);
|
||||
},
|
||||
|
||||
/**
|
||||
* Submit the form data for processing
|
||||
* @returns {void}
|
||||
@@ -1423,7 +1440,7 @@ message HealthCheckResponse {
|
||||
createdNewParent = true;
|
||||
this.monitor.parent = res.monitorID;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
this.processing = false;
|
||||
return;
|
||||
}
|
||||
@@ -1439,17 +1456,14 @@ message HealthCheckResponse {
|
||||
if (createdNewParent) {
|
||||
this.startParentGroupMonitor();
|
||||
}
|
||||
|
||||
toast.success(res.msg);
|
||||
this.processing = false;
|
||||
this.$root.getMonitorList();
|
||||
this.$router.push("/dashboard/" + res.monitorID);
|
||||
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.processing = false;
|
||||
}
|
||||
|
||||
this.$root.toastRes(res);
|
||||
});
|
||||
} else {
|
||||
await this.$refs.tagsManager.submit(this.monitor.id);
|
||||
@@ -1476,6 +1490,7 @@ message HealthCheckResponse {
|
||||
* Added a Notification Event
|
||||
* Enable it if the notification is added in EditMonitor.vue
|
||||
* @param {number} id ID of notification to add
|
||||
* @returns {void}
|
||||
*/
|
||||
addedNotification(id) {
|
||||
this.monitor.notificationIDList[id] = true;
|
||||
@@ -1485,21 +1500,26 @@ message HealthCheckResponse {
|
||||
* Added a Proxy Event
|
||||
* Enable it if the proxy is added in EditMonitor.vue
|
||||
* @param {number} id ID of proxy to add
|
||||
* @returns {void}
|
||||
*/
|
||||
addedProxy(id) {
|
||||
this.monitor.proxyId = id;
|
||||
},
|
||||
|
||||
// Added a Docker Host Event
|
||||
// Enable it if the Docker Host is added in EditMonitor.vue
|
||||
/**
|
||||
* Added a Docker Host Event
|
||||
* Enable it if the Docker Host is added in EditMonitor.vue
|
||||
* @param {number} id ID of docker host
|
||||
* @returns {void}
|
||||
*/
|
||||
addedDockerHost(id) {
|
||||
this.monitor.docker_host = id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a draft group.
|
||||
*
|
||||
* @param {string} draftGroupName - The name of the draft group.
|
||||
* @param {string} draftGroupName The name of the draft group.
|
||||
* @returns {void}
|
||||
*/
|
||||
addedDraftGroup(draftGroupName) {
|
||||
this.draftGroupName = draftGroupName;
|
||||
|
@@ -19,25 +19,33 @@ export default {
|
||||
},
|
||||
async mounted() {
|
||||
|
||||
// There are only 2 cases that could come in here.
|
||||
// There are only 3 cases that could come in here.
|
||||
// 1. Matched status Page domain name
|
||||
// 2. Vue Frontend Dev
|
||||
let res = (await axios.get("/api/entry-page")).data;
|
||||
// 3. Vue Frontend Dev (not setup database yet)
|
||||
let res;
|
||||
try {
|
||||
res = (await axios.get("/api/entry-page")).data;
|
||||
|
||||
if (res.type === "statusPageMatchedDomain") {
|
||||
this.statusPageSlug = res.statusPageSlug;
|
||||
this.$root.forceStatusPageTheme = true;
|
||||
if (res.type === "statusPageMatchedDomain") {
|
||||
this.statusPageSlug = res.statusPageSlug;
|
||||
this.$root.forceStatusPageTheme = true;
|
||||
|
||||
} else if (res.type === "entryPage") { // Dev only. For production, the logic is in the server side
|
||||
const entryPage = res.entryPage;
|
||||
} else if (res.type === "entryPage") { // Dev only. For production, the logic is in the server side
|
||||
const entryPage = res.entryPage;
|
||||
|
||||
if (entryPage === "statusPage") {
|
||||
this.$router.push("/status");
|
||||
if (entryPage === "statusPage") {
|
||||
this.$router.push("/status");
|
||||
} else {
|
||||
this.$router.push("/dashboard");
|
||||
}
|
||||
} else if (res.type === "setup-database") {
|
||||
this.$router.push("/setup-database");
|
||||
} else {
|
||||
this.$router.push("/dashboard");
|
||||
}
|
||||
} else {
|
||||
this.$router.push("/dashboard");
|
||||
} catch (e) {
|
||||
alert("Cannot connect to the backend server. Did you start the backend server? (npm run start-server-dev)");
|
||||
}
|
||||
|
||||
},
|
||||
|
@@ -65,7 +65,10 @@ export default {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
/** Initialise page */
|
||||
/**
|
||||
* Initialise page
|
||||
* @returns {void}
|
||||
*/
|
||||
init() {
|
||||
this.$root.getSocket().emit("getMonitorMaintenance", this.$route.params.id, (res) => {
|
||||
if (res.ok) {
|
||||
@@ -84,20 +87,22 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Confirm deletion */
|
||||
/**
|
||||
* Confirm deletion
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteDialog() {
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
/** Delete maintenance after showing confirmation */
|
||||
/**
|
||||
* Delete maintenance after showing confirmation
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteMaintenance() {
|
||||
this.$root.deleteMaintenance(this.maintenance.id, (res) => {
|
||||
if (res.ok) {
|
||||
toast.success(res.msg);
|
||||
this.$router.push("/maintenance");
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
this.$root.toastRes(res);
|
||||
this.$router.push("/maintenance");
|
||||
});
|
||||
},
|
||||
},
|
||||
|
@@ -81,8 +81,6 @@ import { getResBaseURL } from "../util-frontend";
|
||||
import { getMaintenanceRelativeURL } from "../util.ts";
|
||||
import Confirm from "../components/Confirm.vue";
|
||||
import MaintenanceTime from "../components/MaintenanceTime.vue";
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -135,7 +133,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Get maintenance URL
|
||||
* @param {number} id
|
||||
* @param {number} id ID of maintenance to read
|
||||
* @returns {string} Relative URL
|
||||
*/
|
||||
maintenanceURL(id) {
|
||||
@@ -144,27 +142,33 @@ export default {
|
||||
|
||||
/**
|
||||
* Show delete confirmation
|
||||
* @param {number} maintenanceID
|
||||
* @param {number} maintenanceID ID of maintenance to show delete
|
||||
* confirmation for.
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteDialog(maintenanceID) {
|
||||
this.selectedMaintenanceID = maintenanceID;
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
/** Delete maintenance after showing confirmation dialog */
|
||||
/**
|
||||
* Delete maintenance after showing confirmation dialog
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteMaintenance() {
|
||||
this.$root.deleteMaintenance(this.selectedMaintenanceID, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
if (res.ok) {
|
||||
toast.success(res.msg);
|
||||
this.$router.push("/maintenance");
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show dialog to confirm pause
|
||||
* @param {number} maintenanceID ID of maintenance to confirm
|
||||
* pause.
|
||||
* @returns {void}
|
||||
*/
|
||||
pauseDialog(maintenanceID) {
|
||||
this.selectedMaintenanceID = maintenanceID;
|
||||
@@ -173,6 +177,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Pause maintenance
|
||||
* @returns {void}
|
||||
*/
|
||||
pauseMaintenance() {
|
||||
this.$root.getSocket().emit("pauseMaintenance", this.selectedMaintenanceID, (res) => {
|
||||
@@ -182,6 +187,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Resume maintenance
|
||||
* @param {number} id ID of maintenance to resume
|
||||
* @returns {void}
|
||||
*/
|
||||
resumeMaintenance(id) {
|
||||
this.$root.getSocket().emit("resumeMaintenance", id, (res) => {
|
||||
|
@@ -45,7 +45,10 @@ export default {
|
||||
|
||||
},
|
||||
methods: {
|
||||
/** Go back 1 in browser history */
|
||||
/**
|
||||
* Go back 1 in browser history
|
||||
* @returns {void}
|
||||
*/
|
||||
goBack() {
|
||||
history.back();
|
||||
}
|
||||
|
@@ -113,9 +113,6 @@ export default {
|
||||
proxies: {
|
||||
title: this.$t("Proxies"),
|
||||
},
|
||||
backup: {
|
||||
title: this.$t("Backup"),
|
||||
},
|
||||
about: {
|
||||
title: this.$t("About"),
|
||||
},
|
||||
@@ -139,6 +136,7 @@ export default {
|
||||
/**
|
||||
* Load the general settings page
|
||||
* For desktop only, on mobile do nothing
|
||||
* @returns {void}
|
||||
*/
|
||||
loadGeneralPage() {
|
||||
if (!this.currentPage && !this.$root.isMobile) {
|
||||
@@ -146,7 +144,10 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/** Load settings from server */
|
||||
/**
|
||||
* Load settings from server
|
||||
* @returns {void}
|
||||
*/
|
||||
loadSettings() {
|
||||
this.$root.getSocket().emit("getSettings", (res) => {
|
||||
this.settings = res.data;
|
||||
@@ -190,13 +191,15 @@ export default {
|
||||
/**
|
||||
* Callback for saving settings
|
||||
* @callback saveSettingsCB
|
||||
* @param {Object} res Result of operation
|
||||
* @param {object} res Result of operation
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Save Settings
|
||||
* @param {saveSettingsCB} [callback]
|
||||
* @param {string} [currentPassword] Only need for disableAuth to true
|
||||
* @param {saveSettingsCB} callback Callback for socket response
|
||||
* @param {string} currentPassword Only need for disableAuth to true
|
||||
* @returns {void}
|
||||
*/
|
||||
saveSettings(callback, currentPassword) {
|
||||
let valid = this.validateSettings();
|
||||
@@ -216,7 +219,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Ensure settings are valid
|
||||
* @returns {Object} Contains success state and error msg
|
||||
* @returns {object} Contains success state and error msg
|
||||
*/
|
||||
validateSettings() {
|
||||
if (this.settings.keepDataPeriodDays < 0) {
|
||||
|
@@ -46,9 +46,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -62,6 +59,8 @@ export default {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
// TODO: Check if it is a database setup
|
||||
|
||||
this.$root.getSocket().emit("needSetup", (needSetup) => {
|
||||
if (! needSetup) {
|
||||
this.$router.push("/");
|
||||
@@ -77,7 +76,7 @@ export default {
|
||||
this.processing = true;
|
||||
|
||||
if (this.password !== this.repeatPassword) {
|
||||
toast.error(this.$t("PasswordsDoNotMatch"));
|
||||
this.$root.toastError("PasswordsDoNotMatch");
|
||||
this.processing = false;
|
||||
return;
|
||||
}
|
||||
|
238
src/pages/SetupDatabase.vue
Normal file
238
src/pages/SetupDatabase.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div v-if="show" class="form-container">
|
||||
<form @submit.prevent="submit">
|
||||
<div>
|
||||
<object width="64" height="64" data="/icon.svg" />
|
||||
<div style="font-size: 28px; font-weight: bold; margin-top: 5px;">
|
||||
Uptime Kuma
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="info.runningSetup" class="mt-5">
|
||||
<div class="alert alert-success mx-3 px-4" role="alert">
|
||||
<div class="d-flex align-items-center">
|
||||
<strong>Setting up the database. It may take a while, please be patient.</strong>
|
||||
<div class="ms-3 pt-1">
|
||||
<div class="spinner-border" role="status" aria-hidden="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="!info.runningSetup">
|
||||
<div class="form-floating short mt-3">
|
||||
<select id="language" v-model="$root.language" class="form-select">
|
||||
<option v-for="(lang, i) in $i18n.availableLocales" :key="`Lang${i}`" :value="lang">
|
||||
{{ $i18n.messages[lang].languageName }}
|
||||
</option>
|
||||
</select>
|
||||
<label for="language" class="form-label">{{ $t("Language") }}</label>
|
||||
</div>
|
||||
|
||||
<p class="mt-5 short">
|
||||
{{ $t("setupDatabaseChooseDatabase") }}
|
||||
</p>
|
||||
|
||||
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
|
||||
<template v-if="info.isEnabledEmbeddedMariaDB">
|
||||
<input id="btnradio3" v-model="dbConfig.type" type="radio" class="btn-check" autocomplete="off" value="embedded-mariadb">
|
||||
|
||||
<label class="btn btn-outline-primary" for="btnradio3">
|
||||
Embedded MariaDB
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<input id="btnradio2" v-model="dbConfig.type" type="radio" class="btn-check" autocomplete="off" value="mariadb">
|
||||
<label class="btn btn-outline-primary" for="btnradio2">
|
||||
MariaDB/MySQL
|
||||
</label>
|
||||
|
||||
<input id="btnradio1" v-model="dbConfig.type" type="radio" class="btn-check" autocomplete="off" value="sqlite">
|
||||
<label class="btn btn-outline-primary" for="btnradio1">
|
||||
SQLite
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div v-if="dbConfig.type === 'embedded-mariadb'" class="mt-3 short">
|
||||
{{ $t("setupDatabaseEmbeddedMariaDB") }}
|
||||
</div>
|
||||
|
||||
<div v-if="dbConfig.type === 'mariadb'" class="mt-3 short">
|
||||
{{ $t("setupDatabaseMariaDB") }}
|
||||
</div>
|
||||
|
||||
<div v-if="dbConfig.type === 'sqlite'" class="mt-3 short">
|
||||
{{ $t("setupDatabaseSQLite") }}
|
||||
</div>
|
||||
|
||||
<template v-if="dbConfig.type === 'mariadb'">
|
||||
<div class="form-floating mt-3 short">
|
||||
<input id="floatingInput" v-model="dbConfig.hostname" type="text" class="form-control" required>
|
||||
<label for="floatingInput">{{ $t("Hostname") }}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mt-3 short">
|
||||
<input id="floatingInput" v-model="dbConfig.port" type="text" class="form-control" required>
|
||||
<label for="floatingInput">{{ $t("Port") }}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mt-3 short">
|
||||
<input id="floatingInput" v-model="dbConfig.username" type="text" class="form-control" required>
|
||||
<label for="floatingInput">{{ $t("Username") }}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mt-3 short">
|
||||
<input id="floatingInput" v-model="dbConfig.password" type="password" class="form-control" required>
|
||||
<label for="floatingInput">{{ $t("Password") }}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mt-3 short">
|
||||
<input id="floatingInput" v-model="dbConfig.dbName" type="text" class="form-control" required>
|
||||
<label for="floatingInput">{{ $t("dbName") }}</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<button class="btn btn-primary mt-4 short" type="submit" :disabled="disabledButton">
|
||||
{{ $t("Next") }}
|
||||
</button>
|
||||
</template>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { sleep } from "../util.ts";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
dbConfig: {
|
||||
type: undefined,
|
||||
port: 3306,
|
||||
hostname: "",
|
||||
username: "",
|
||||
password: "",
|
||||
dbName: "kuma",
|
||||
},
|
||||
info: {
|
||||
needSetup: false,
|
||||
runningSetup: false,
|
||||
isEnabledEmbeddedMariaDB: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
disabledButton() {
|
||||
return this.dbConfig.type === undefined || this.info.runningSetup;
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
let res = await axios.get("/setup-database-info");
|
||||
this.info = res.data;
|
||||
|
||||
if (this.info && this.info.needSetup === false) {
|
||||
location.href = "/setup";
|
||||
} else {
|
||||
this.show = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submit() {
|
||||
this.info.runningSetup = true;
|
||||
|
||||
try {
|
||||
await axios.post("/setup-database", {
|
||||
dbConfig: this.dbConfig,
|
||||
});
|
||||
await sleep(2000);
|
||||
await this.goToMainServerWhenReady();
|
||||
} catch (e) {
|
||||
toast.error(e.response.data);
|
||||
} finally {
|
||||
this.info.runningSetup = false;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
async goToMainServerWhenReady() {
|
||||
try {
|
||||
console.log("Trying...");
|
||||
let res = await axios.get("/setup-database-info");
|
||||
if (res.data && res.data.needSetup === false) {
|
||||
this.show = false;
|
||||
location.href = "/setup";
|
||||
} else {
|
||||
if (res.data) {
|
||||
this.info = res.data;
|
||||
}
|
||||
throw new Error("not ready");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Not ready yet");
|
||||
await sleep(2000);
|
||||
await this.goToMainServerWhenReady();
|
||||
}
|
||||
},
|
||||
|
||||
test() {
|
||||
this.$root.toastError("not implemented");
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
label {
|
||||
width: 200px;
|
||||
line-height: 55px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.form-floating {
|
||||
> .form-select {
|
||||
padding-left: 1.3rem;
|
||||
padding-top: 1.525rem;
|
||||
line-height: 1.35;
|
||||
|
||||
~ label {
|
||||
padding-left: 1.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
> label {
|
||||
padding-left: 1.3rem;
|
||||
}
|
||||
|
||||
> .form-control {
|
||||
padding-left: 1.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.short {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
form {
|
||||
max-width: 800px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
@@ -453,6 +453,7 @@ export default {
|
||||
|
||||
/**
|
||||
* If the monitor is added to public list, which will not be in this list.
|
||||
* @returns {object[]} List of monitors
|
||||
*/
|
||||
sortedMonitorList() {
|
||||
let result = [];
|
||||
@@ -597,7 +598,8 @@ export default {
|
||||
|
||||
/**
|
||||
* If connected to the socket and logged in, request private data of this statusPage
|
||||
* @param connected
|
||||
* @param {boolean} loggedIn Is the client logged in?
|
||||
* @returns {void}
|
||||
*/
|
||||
"$root.loggedIn"(loggedIn) {
|
||||
if (loggedIn) {
|
||||
@@ -612,7 +614,7 @@ export default {
|
||||
}
|
||||
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -620,6 +622,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Selected a monitor and add to the list.
|
||||
* @param {object} monitor Monitor to add
|
||||
* @returns {void}
|
||||
*/
|
||||
selectedMonitor(monitor) {
|
||||
if (monitor) {
|
||||
@@ -726,7 +730,7 @@ export default {
|
||||
/**
|
||||
* Get status page data
|
||||
* It should be preloaded in window.preloadData
|
||||
* @returns {Promise<any>}
|
||||
* @returns {Promise<any>} Status page data
|
||||
*/
|
||||
getData: function () {
|
||||
if (window.preloadData) {
|
||||
@@ -741,13 +745,16 @@ export default {
|
||||
/**
|
||||
* Provide syntax highlighting for CSS
|
||||
* @param {string} code Text to highlight
|
||||
* @returns {string}
|
||||
* @returns {string} Highlighted CSS
|
||||
*/
|
||||
highlighter(code) {
|
||||
return highlight(code, languages.css);
|
||||
},
|
||||
|
||||
/** Update the heartbeat list and update favicon if neccessary */
|
||||
/**
|
||||
* Update the heartbeat list and update favicon if necessary
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHeartbeatList() {
|
||||
// If editMode, it will use the data from websocket.
|
||||
if (! this.editMode) {
|
||||
@@ -795,7 +802,10 @@ export default {
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
/** Enable editing mode */
|
||||
/**
|
||||
* Enable editing mode
|
||||
* @returns {void}
|
||||
*/
|
||||
edit() {
|
||||
if (this.hasToken) {
|
||||
this.$root.initSocketIO(true);
|
||||
@@ -807,7 +817,10 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/** Save the status page */
|
||||
/**
|
||||
* Save the status page
|
||||
* @returns {void}
|
||||
*/
|
||||
save() {
|
||||
this.loading = true;
|
||||
let startTime = new Date();
|
||||
@@ -838,33 +851,42 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Show dialog confirming deletion */
|
||||
/**
|
||||
* Show dialog confirming deletion
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteDialog() {
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
/** Request deletion of this status page */
|
||||
/**
|
||||
* Request deletion of this status page
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteStatusPage() {
|
||||
this.$root.getSocket().emit("deleteStatusPage", this.slug, (res) => {
|
||||
if (res.ok) {
|
||||
this.enableEditMode = false;
|
||||
location.href = "/manage-status-page";
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns label for a specifed monitor
|
||||
* @param {Object} monitor Object representing monitor
|
||||
* @returns {string}
|
||||
* Returns label for a specified monitor
|
||||
* @param {object} monitor Object representing monitor
|
||||
* @returns {string} Monitor label
|
||||
*/
|
||||
monitorSelectorLabel(monitor) {
|
||||
return `${monitor.name}`;
|
||||
},
|
||||
|
||||
/** Add a group to the status page */
|
||||
/**
|
||||
* Add a group to the status page
|
||||
* @returns {void}
|
||||
*/
|
||||
addGroup() {
|
||||
let groupName = this.$t("Untitled Group");
|
||||
|
||||
@@ -878,12 +900,18 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Add a domain to the status page */
|
||||
/**
|
||||
* Add a domain to the status page
|
||||
* @returns {void}
|
||||
*/
|
||||
addDomainField() {
|
||||
this.config.domainNameList.push("");
|
||||
},
|
||||
|
||||
/** Discard changes to status page */
|
||||
/**
|
||||
* Discard changes to status page
|
||||
* @returns {void}
|
||||
*/
|
||||
discard() {
|
||||
location.href = "/status/" + this.slug;
|
||||
},
|
||||
@@ -891,19 +919,26 @@ export default {
|
||||
/**
|
||||
* Set URL of new image after successful crop operation
|
||||
* @param {string} imgDataUrl URL of image in data:// format
|
||||
* @returns {void}
|
||||
*/
|
||||
cropSuccess(imgDataUrl) {
|
||||
this.imgDataUrl = imgDataUrl;
|
||||
},
|
||||
|
||||
/** Show image crop dialog if in edit mode */
|
||||
/**
|
||||
* Show image crop dialog if in edit mode
|
||||
* @returns {void}
|
||||
*/
|
||||
showImageCropUploadMethod() {
|
||||
if (this.editMode) {
|
||||
this.showImageCropUpload = true;
|
||||
}
|
||||
},
|
||||
|
||||
/** Create an incident for this status page */
|
||||
/**
|
||||
* Create an incident for this status page
|
||||
* @returns {void}
|
||||
*/
|
||||
createIncident() {
|
||||
this.enableEditIncidentMode = true;
|
||||
|
||||
@@ -918,10 +953,13 @@ export default {
|
||||
};
|
||||
},
|
||||
|
||||
/** Post the incident to the status page */
|
||||
/**
|
||||
* Post the incident to the status page
|
||||
* @returns {void}
|
||||
*/
|
||||
postIncident() {
|
||||
if (this.incident.title === "" || this.incident.content === "") {
|
||||
toast.error(this.$t("Please input title and content"));
|
||||
this.$root.toastError("Please input title and content");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -931,20 +969,26 @@ export default {
|
||||
this.enableEditIncidentMode = false;
|
||||
this.incident = res.incident;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
this.$root.toastError(res.msg);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/** Click Edit Button */
|
||||
/**
|
||||
* Click Edit Button
|
||||
* @returns {void}
|
||||
*/
|
||||
editIncident() {
|
||||
this.enableEditIncidentMode = true;
|
||||
this.previousIncident = Object.assign({}, this.incident);
|
||||
},
|
||||
|
||||
/** Cancel creation or editing of incident */
|
||||
/**
|
||||
* Cancel creation or editing of incident
|
||||
* @returns {void}
|
||||
*/
|
||||
cancelIncident() {
|
||||
this.enableEditIncidentMode = false;
|
||||
|
||||
@@ -954,7 +998,10 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/** Unpin the incident */
|
||||
/**
|
||||
* Unpin the incident
|
||||
* @returns {void}
|
||||
*/
|
||||
unpinIncident() {
|
||||
this.$root.getSocket().emit("unpinIncident", this.slug, () => {
|
||||
this.incident = null;
|
||||
@@ -963,7 +1010,8 @@ export default {
|
||||
|
||||
/**
|
||||
* Get the relative time difference of a date from now
|
||||
* @returns {string}
|
||||
* @param {any} date Date to get time difference
|
||||
* @returns {string} Time difference
|
||||
*/
|
||||
dateFromNow(date) {
|
||||
return dayjs.utc(date).fromNow();
|
||||
@@ -972,6 +1020,7 @@ export default {
|
||||
/**
|
||||
* Remove a domain from the status page
|
||||
* @param {number} index Index of domain to remove
|
||||
* @returns {void}
|
||||
*/
|
||||
removeDomain(index) {
|
||||
this.config.domainNameList.splice(index, 1);
|
||||
@@ -979,7 +1028,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Generate sanitized HTML from maintenance description
|
||||
* @param {string} description
|
||||
* @param {string} description Text to sanitize
|
||||
* @returns {string} Sanitized HTML
|
||||
*/
|
||||
maintenanceHTML(description) {
|
||||
@@ -1196,20 +1245,6 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
/* required class */
|
||||
.css-editor {
|
||||
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
|
||||
|
||||
border-radius: 1rem;
|
||||
padding: 10px 5px;
|
||||
border: 1px solid #ced4da;
|
||||
|
||||
.dark & {
|
||||
background: $dark-bg;
|
||||
border: 1px solid $dark-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.bg-maintenance {
|
||||
.alert-heading {
|
||||
font-weight: bold;
|
||||
|
@@ -19,6 +19,7 @@ import DockerHosts from "./components/settings/Docker.vue";
|
||||
import MaintenanceDetails from "./pages/MaintenanceDetails.vue";
|
||||
import ManageMaintenance from "./pages/ManageMaintenance.vue";
|
||||
import APIKeys from "./components/settings/APIKeys.vue";
|
||||
import SetupDatabase from "./pages/SetupDatabase.vue";
|
||||
|
||||
// Settings - Sub Pages
|
||||
import Appearance from "./components/settings/Appearance.vue";
|
||||
@@ -29,7 +30,6 @@ import Tags from "./components/settings/Tags.vue";
|
||||
import MonitorHistory from "./components/settings/MonitorHistory.vue";
|
||||
const Security = () => import("./components/settings/Security.vue");
|
||||
import Proxies from "./components/settings/Proxies.vue";
|
||||
import Backup from "./components/settings/Backup.vue";
|
||||
import About from "./components/settings/About.vue";
|
||||
|
||||
const routes = [
|
||||
@@ -125,10 +125,6 @@ const routes = [
|
||||
path: "proxies",
|
||||
component: Proxies,
|
||||
},
|
||||
{
|
||||
path: "backup",
|
||||
component: Backup,
|
||||
},
|
||||
{
|
||||
path: "about",
|
||||
component: About,
|
||||
@@ -167,6 +163,10 @@ const routes = [
|
||||
path: "/setup",
|
||||
component: Setup,
|
||||
},
|
||||
{
|
||||
path: "/setup-database",
|
||||
component: SetupDatabase,
|
||||
},
|
||||
{
|
||||
path: "/status-page",
|
||||
component: StatusPage,
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import dayjs from "dayjs";
|
||||
import timezones from "timezones-list";
|
||||
import { localeDirection, currentLocale } from "./i18n";
|
||||
import { POSITION } from "vue-toastification";
|
||||
|
||||
/**
|
||||
* Returns the offset from UTC in hours for the current locale.
|
||||
* @param {string} timeZone Timezone to get offset for
|
||||
* @returns {number} The offset from UTC in hours.
|
||||
*
|
||||
* Generated by Trelent
|
||||
@@ -20,12 +22,11 @@ function getTimezoneOffset(timeZone) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of timezones sorted by their offset from UTC.
|
||||
* @param {Object[]} timezones An array of timezone objects.
|
||||
* @returns {Object[]} A list of the given timezones sorted by their offset from UTC.
|
||||
*
|
||||
* Generated by Trelent
|
||||
*/
|
||||
* Returns a list of timezones sorted by their offset from UTC.
|
||||
* @returns {object[]} A list of the given timezones sorted by their offset from UTC.
|
||||
*
|
||||
* Generated by Trelent
|
||||
*/
|
||||
export function timezoneList() {
|
||||
let result = [];
|
||||
|
||||
@@ -58,7 +59,10 @@ export function timezoneList() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Set the locale of the HTML page */
|
||||
/**
|
||||
* Set the locale of the HTML page
|
||||
* @returns {void}
|
||||
*/
|
||||
export function setPageLocale() {
|
||||
const html = document.documentElement;
|
||||
html.setAttribute("lang", currentLocale() );
|
||||
@@ -68,7 +72,7 @@ export function setPageLocale() {
|
||||
/**
|
||||
* Get the base URL
|
||||
* Mainly used for dev, because the backend and the frontend are in different ports.
|
||||
* @returns {string}
|
||||
* @returns {string} Base URL
|
||||
*/
|
||||
export function getResBaseURL() {
|
||||
const env = process.env.NODE_ENV;
|
||||
@@ -81,6 +85,10 @@ export function getResBaseURL() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently running in a dev container?
|
||||
* @returns {boolean} Running in dev container?
|
||||
*/
|
||||
export function isDevContainer() {
|
||||
// eslint-disable-next-line no-undef
|
||||
return (typeof DEVCONTAINER === "string" && DEVCONTAINER === "1");
|
||||
@@ -88,6 +96,7 @@ export function isDevContainer() {
|
||||
|
||||
/**
|
||||
* Supports GitHub Codespaces only currently
|
||||
* @returns {string} Dev container server hostname
|
||||
*/
|
||||
export function getDevContainerServerHostname() {
|
||||
if (!isDevContainer()) {
|
||||
@@ -99,9 +108,10 @@ export function getDevContainerServerHostname() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {} mqtt wheather or not the regex should take into account the fact that it is an mqtt uri
|
||||
* @returns RegExp The requested regex
|
||||
* Regex pattern fr identifying hostnames and IP addresses
|
||||
* @param {boolean} mqtt whether or not the regex should take into
|
||||
* account the fact that it is an mqtt uri
|
||||
* @returns {RegExp} The requested regex
|
||||
*/
|
||||
export function hostNameRegexPattern(mqtt = false) {
|
||||
// mqtt, mqtts, ws and wss schemes accepted by mqtt.js (https://github.com/mqttjs/MQTT.js/#connect)
|
||||
@@ -117,7 +127,8 @@ export function hostNameRegexPattern(mqtt = false) {
|
||||
/**
|
||||
* Get the tag color options
|
||||
* Shared between components
|
||||
* @returns {Object[]}
|
||||
* @param {any} self Component
|
||||
* @returns {object[]} Colour options
|
||||
*/
|
||||
export function colorOptions(self) {
|
||||
return [
|
||||
@@ -139,3 +150,65 @@ export function colorOptions(self) {
|
||||
color: "#DB2777" },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the toast timeout settings from storage.
|
||||
* @returns {object} The toast plugin options object.
|
||||
*/
|
||||
export function loadToastSettings() {
|
||||
return {
|
||||
position: POSITION.BOTTOM_RIGHT,
|
||||
containerClassName: "toast-container mb-5",
|
||||
showCloseButtonOnHover: true,
|
||||
|
||||
filterBeforeCreate: (toast, toasts) => {
|
||||
if (toast.timeout === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return toast;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timeout for success toasts
|
||||
* @returns {(number|boolean)} Timeout in ms. If false timeout disabled.
|
||||
*/
|
||||
export function getToastSuccessTimeout() {
|
||||
let successTimeout = 20000;
|
||||
|
||||
if (localStorage.toastSuccessTimeout !== undefined) {
|
||||
const parsedTimeout = parseInt(localStorage.toastSuccessTimeout);
|
||||
if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
|
||||
successTimeout = parsedTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
if (successTimeout === -1) {
|
||||
successTimeout = false;
|
||||
}
|
||||
|
||||
return successTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timeout for error toasts
|
||||
* @returns {(number|boolean)} Timeout in ms. If false timeout disabled.
|
||||
*/
|
||||
export function getToastErrorTimeout() {
|
||||
let errorTimeout = -1;
|
||||
|
||||
if (localStorage.toastErrorTimeout !== undefined) {
|
||||
const parsedTimeout = parseInt(localStorage.toastErrorTimeout);
|
||||
if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) {
|
||||
errorTimeout = parsedTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
if (errorTimeout === -1) {
|
||||
errorTimeout = false;
|
||||
}
|
||||
|
||||
return errorTimeout;
|
||||
}
|
||||
|
253
src/util.js
253
src/util.js
@@ -1,13 +1,16 @@
|
||||
"use strict";
|
||||
/*!
|
||||
// Common Util for frontend and backend
|
||||
//
|
||||
// DOT NOT MODIFY util.js!
|
||||
// Need to run "tsc" to compile if there are any changes.
|
||||
// Need to run "npm run tsc" to compile if there are any changes.
|
||||
//
|
||||
// Backend uses the compiled file util.js
|
||||
// Frontend uses util.ts
|
||||
*/
|
||||
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.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.isDev = void 0;
|
||||
exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = 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.isDev = 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 = void 0;
|
||||
const dayjs = require("dayjs");
|
||||
exports.isDev = process.env.NODE_ENV === "development";
|
||||
exports.appName = "Uptime Kuma";
|
||||
@@ -22,9 +25,57 @@ exports.STATUS_PAGE_MAINTENANCE = 3;
|
||||
exports.SQL_DATE_FORMAT = "YYYY-MM-DD";
|
||||
exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
|
||||
exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm";
|
||||
exports.MAX_INTERVAL_SECOND = 2073600; // 24 days
|
||||
exports.MIN_INTERVAL_SECOND = 20; // 20 seconds
|
||||
/** Flip the status of s */
|
||||
exports.MAX_INTERVAL_SECOND = 2073600;
|
||||
exports.MIN_INTERVAL_SECOND = 20;
|
||||
exports.CONSOLE_STYLE_Reset = "\x1b[0m";
|
||||
exports.CONSOLE_STYLE_Bright = "\x1b[1m";
|
||||
exports.CONSOLE_STYLE_Dim = "\x1b[2m";
|
||||
exports.CONSOLE_STYLE_Underscore = "\x1b[4m";
|
||||
exports.CONSOLE_STYLE_Blink = "\x1b[5m";
|
||||
exports.CONSOLE_STYLE_Reverse = "\x1b[7m";
|
||||
exports.CONSOLE_STYLE_Hidden = "\x1b[8m";
|
||||
exports.CONSOLE_STYLE_FgBlack = "\x1b[30m";
|
||||
exports.CONSOLE_STYLE_FgRed = "\x1b[31m";
|
||||
exports.CONSOLE_STYLE_FgGreen = "\x1b[32m";
|
||||
exports.CONSOLE_STYLE_FgYellow = "\x1b[33m";
|
||||
exports.CONSOLE_STYLE_FgBlue = "\x1b[34m";
|
||||
exports.CONSOLE_STYLE_FgMagenta = "\x1b[35m";
|
||||
exports.CONSOLE_STYLE_FgCyan = "\x1b[36m";
|
||||
exports.CONSOLE_STYLE_FgWhite = "\x1b[37m";
|
||||
exports.CONSOLE_STYLE_FgGray = "\x1b[90m";
|
||||
exports.CONSOLE_STYLE_FgOrange = "\x1b[38;5;208m";
|
||||
exports.CONSOLE_STYLE_FgLightGreen = "\x1b[38;5;119m";
|
||||
exports.CONSOLE_STYLE_FgLightBlue = "\x1b[38;5;117m";
|
||||
exports.CONSOLE_STYLE_FgViolet = "\x1b[38;5;141m";
|
||||
exports.CONSOLE_STYLE_FgBrown = "\x1b[38;5;130m";
|
||||
exports.CONSOLE_STYLE_FgPink = "\x1b[38;5;219m";
|
||||
exports.CONSOLE_STYLE_BgBlack = "\x1b[40m";
|
||||
exports.CONSOLE_STYLE_BgRed = "\x1b[41m";
|
||||
exports.CONSOLE_STYLE_BgGreen = "\x1b[42m";
|
||||
exports.CONSOLE_STYLE_BgYellow = "\x1b[43m";
|
||||
exports.CONSOLE_STYLE_BgBlue = "\x1b[44m";
|
||||
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,
|
||||
exports.CONSOLE_STYLE_FgLightGreen,
|
||||
exports.CONSOLE_STYLE_FgBlue,
|
||||
exports.CONSOLE_STYLE_FgLightBlue,
|
||||
exports.CONSOLE_STYLE_FgMagenta,
|
||||
exports.CONSOLE_STYLE_FgOrange,
|
||||
exports.CONSOLE_STYLE_FgViolet,
|
||||
exports.CONSOLE_STYLE_FgBrown,
|
||||
exports.CONSOLE_STYLE_FgPink,
|
||||
];
|
||||
const consoleLevelColors = {
|
||||
"INFO": exports.CONSOLE_STYLE_FgCyan,
|
||||
"WARN": exports.CONSOLE_STYLE_FgYellow,
|
||||
"ERROR": exports.CONSOLE_STYLE_FgRed,
|
||||
"DEBUG": exports.CONSOLE_STYLE_FgGray,
|
||||
};
|
||||
function flipStatus(s) {
|
||||
if (s === exports.UP) {
|
||||
return exports.DOWN;
|
||||
@@ -35,18 +86,10 @@ function flipStatus(s) {
|
||||
return s;
|
||||
}
|
||||
exports.flipStatus = flipStatus;
|
||||
/**
|
||||
* Delays for specified number of seconds
|
||||
* @param ms Number of milliseconds to sleep for
|
||||
*/
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
exports.sleep = sleep;
|
||||
/**
|
||||
* PHP's ucfirst
|
||||
* @param str
|
||||
*/
|
||||
function ucfirst(str) {
|
||||
if (!str) {
|
||||
return str;
|
||||
@@ -55,26 +98,12 @@ function ucfirst(str) {
|
||||
return firstLetter.toUpperCase() + str.substr(1);
|
||||
}
|
||||
exports.ucfirst = ucfirst;
|
||||
/**
|
||||
* @deprecated Use log.debug
|
||||
* @since https://github.com/louislam/uptime-kuma/pull/910
|
||||
* @param msg
|
||||
*/
|
||||
function debug(msg) {
|
||||
exports.log.log("", msg, "debug");
|
||||
}
|
||||
exports.debug = debug;
|
||||
class Logger {
|
||||
constructor() {
|
||||
/**
|
||||
* UPTIME_KUMA_HIDE_LOG=debug_monitor,info_monitor
|
||||
*
|
||||
* Example:
|
||||
* [
|
||||
* "debug_monitor", // Hide all logs that level is debug and the module is monitor
|
||||
* "info_monitor",
|
||||
* ]
|
||||
*/
|
||||
this.hideLog = {
|
||||
info: [],
|
||||
warn: [],
|
||||
@@ -82,10 +111,9 @@ class Logger {
|
||||
debug: [],
|
||||
};
|
||||
if (typeof process !== "undefined" && process.env.UPTIME_KUMA_HIDE_LOG) {
|
||||
let list = process.env.UPTIME_KUMA_HIDE_LOG.split(",").map(v => v.toLowerCase());
|
||||
for (let pair of list) {
|
||||
// split first "_" only
|
||||
let values = pair.split(/_(.*)/s);
|
||||
const list = process.env.UPTIME_KUMA_HIDE_LOG.split(",").map(v => v.toLowerCase());
|
||||
for (const pair of list) {
|
||||
const values = pair.split(/_(.*)/s);
|
||||
if (values.length >= 2) {
|
||||
this.hideLog[values[0]].push(values[1]);
|
||||
}
|
||||
@@ -94,12 +122,6 @@ class Logger {
|
||||
this.debug("server", this.hideLog);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Write a message to the log
|
||||
* @param module The module the log comes from
|
||||
* @param msg Message to write
|
||||
* @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
|
||||
*/
|
||||
log(module, msg, level) {
|
||||
if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
|
||||
return;
|
||||
@@ -113,63 +135,56 @@ class Logger {
|
||||
else {
|
||||
now = dayjs().format();
|
||||
}
|
||||
const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg;
|
||||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
let timePart = exports.CONSOLE_STYLE_FgCyan + now + exports.CONSOLE_STYLE_Reset;
|
||||
let modulePart = "[" + moduleColor + module + exports.CONSOLE_STYLE_Reset + "]";
|
||||
let levelPart = levelColor + `${level}:` + exports.CONSOLE_STYLE_Reset;
|
||||
if (level === "INFO") {
|
||||
console.info(formattedMessage);
|
||||
console.info(timePart, modulePart, levelPart, msg);
|
||||
}
|
||||
else if (level === "WARN") {
|
||||
console.warn(formattedMessage);
|
||||
console.warn(timePart, modulePart, levelPart, msg);
|
||||
}
|
||||
else if (level === "ERROR") {
|
||||
console.error(formattedMessage);
|
||||
let msgPart;
|
||||
if (typeof msg === "string") {
|
||||
msgPart = exports.CONSOLE_STYLE_FgRed + msg + exports.CONSOLE_STYLE_Reset;
|
||||
}
|
||||
else {
|
||||
msgPart = msg;
|
||||
}
|
||||
console.error(timePart, modulePart, levelPart, msgPart);
|
||||
}
|
||||
else if (level === "DEBUG") {
|
||||
if (exports.isDev) {
|
||||
console.log(formattedMessage);
|
||||
timePart = exports.CONSOLE_STYLE_FgGray + now + exports.CONSOLE_STYLE_Reset;
|
||||
let msgPart;
|
||||
if (typeof msg === "string") {
|
||||
msgPart = exports.CONSOLE_STYLE_FgGray + msg + exports.CONSOLE_STYLE_Reset;
|
||||
}
|
||||
else {
|
||||
msgPart = msg;
|
||||
}
|
||||
console.debug(timePart, modulePart, levelPart, msgPart);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log(formattedMessage);
|
||||
console.log(timePart, modulePart, msg);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Log an INFO message
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
info(module, msg) {
|
||||
this.log(module, msg, "info");
|
||||
}
|
||||
/**
|
||||
* Log a WARN message
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
warn(module, msg) {
|
||||
this.log(module, msg, "warn");
|
||||
}
|
||||
/**
|
||||
* Log an ERROR message
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
error(module, msg) {
|
||||
this.log(module, msg, "error");
|
||||
}
|
||||
/**
|
||||
* Log a DEBUG message
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
debug(module, msg) {
|
||||
this.log(module, msg, "debug");
|
||||
}
|
||||
/**
|
||||
* Log an exeption as an ERROR
|
||||
* @param module Module log comes from
|
||||
* @param exception The exeption to include
|
||||
* @param msg The message to write
|
||||
*/
|
||||
exception(module, exception, msg) {
|
||||
let finalMessage = exception;
|
||||
if (msg) {
|
||||
@@ -179,20 +194,12 @@ class Logger {
|
||||
}
|
||||
}
|
||||
exports.log = new Logger();
|
||||
/**
|
||||
* String.prototype.replaceAll() polyfill
|
||||
* https://gomakethings.com/how-to-replace-a-section-of-a-string-with-another-one-with-vanilla-js/
|
||||
* @author Chris Ferdinandi
|
||||
* @license MIT
|
||||
*/
|
||||
function polyfill() {
|
||||
if (!String.prototype.replaceAll) {
|
||||
String.prototype.replaceAll = function (str, newStr) {
|
||||
// If a regex pattern
|
||||
if (Object.prototype.toString.call(str).toLowerCase() === "[object regexp]") {
|
||||
return this.replace(str, newStr);
|
||||
}
|
||||
// If a string
|
||||
return this.replace(new RegExp(str, "g"), newStr);
|
||||
};
|
||||
}
|
||||
@@ -202,10 +209,6 @@ class TimeLogger {
|
||||
constructor() {
|
||||
this.startTime = dayjs().valueOf();
|
||||
}
|
||||
/**
|
||||
* Output time since start of monitor
|
||||
* @param name Name of monitor
|
||||
*/
|
||||
print(name) {
|
||||
if (exports.isDev && process.env.TIMELOGGER === "1") {
|
||||
console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms");
|
||||
@@ -213,66 +216,42 @@ class TimeLogger {
|
||||
}
|
||||
}
|
||||
exports.TimeLogger = TimeLogger;
|
||||
/**
|
||||
* Returns a random number between min (inclusive) and max (exclusive)
|
||||
*/
|
||||
function getRandomArbitrary(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
exports.getRandomArbitrary = getRandomArbitrary;
|
||||
/**
|
||||
* From: https://stackoverflow.com/questions/1527803/generating-random-whole-numbers-in-javascript-in-a-specific-range
|
||||
*
|
||||
* Returns a random integer between min (inclusive) and max (inclusive).
|
||||
* The value is no lower than min (or the next integer greater than min
|
||||
* if min isn't an integer) and no greater than max (or the next integer
|
||||
* lower than max if max isn't an integer).
|
||||
* Using Math.round() will give you a non-uniform distribution!
|
||||
*/
|
||||
function getRandomInt(min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
exports.getRandomInt = getRandomInt;
|
||||
/**
|
||||
* Returns either the NodeJS crypto.randomBytes() function or its
|
||||
* browser equivalent implemented via window.crypto.getRandomValues()
|
||||
*/
|
||||
let getRandomBytes = ((typeof window !== 'undefined' && window.crypto)
|
||||
// Browsers
|
||||
const getRandomBytes = ((typeof window !== "undefined" && window.crypto)
|
||||
? function () {
|
||||
return (numBytes) => {
|
||||
let randomBytes = new Uint8Array(numBytes);
|
||||
const randomBytes = new Uint8Array(numBytes);
|
||||
for (let i = 0; i < numBytes; i += 65536) {
|
||||
window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536)));
|
||||
}
|
||||
return randomBytes;
|
||||
};
|
||||
}
|
||||
// Node
|
||||
: function () {
|
||||
return require("crypto").randomBytes;
|
||||
})();
|
||||
/**
|
||||
* Get a random integer suitable for use in cryptography between upper
|
||||
* and lower bounds.
|
||||
* @param min Minimum value of integer
|
||||
* @param max Maximum value of integer
|
||||
* @returns Cryptographically suitable random integer
|
||||
*/
|
||||
function getCryptoRandomInt(min, max) {
|
||||
// synchronous version of: https://github.com/joepie91/node-random-number-csprng
|
||||
const range = max - min;
|
||||
if (range >= Math.pow(2, 32))
|
||||
if (range >= Math.pow(2, 32)) {
|
||||
console.log("Warning! Range is too large.");
|
||||
}
|
||||
let tmpRange = range;
|
||||
let bitsNeeded = 0;
|
||||
let bytesNeeded = 0;
|
||||
let mask = 1;
|
||||
while (tmpRange > 0) {
|
||||
if (bitsNeeded % 8 === 0)
|
||||
if (bitsNeeded % 8 === 0) {
|
||||
bytesNeeded += 1;
|
||||
}
|
||||
bitsNeeded += 1;
|
||||
mask = mask << 1 | 1;
|
||||
tmpRange = tmpRange >>> 1;
|
||||
@@ -291,11 +270,6 @@ function getCryptoRandomInt(min, max) {
|
||||
}
|
||||
}
|
||||
exports.getCryptoRandomInt = getCryptoRandomInt;
|
||||
/**
|
||||
* Generate a random alphanumeric string of fixed length
|
||||
* @param length Length of string to generate
|
||||
* @returns string
|
||||
*/
|
||||
function genSecret(length = 64) {
|
||||
let secret = "";
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
@@ -306,29 +280,14 @@ function genSecret(length = 64) {
|
||||
return secret;
|
||||
}
|
||||
exports.genSecret = genSecret;
|
||||
/**
|
||||
* Get the path of a monitor
|
||||
* @param id ID of monitor
|
||||
* @returns Formatted relative path
|
||||
*/
|
||||
function getMonitorRelativeURL(id) {
|
||||
return "/dashboard/" + id;
|
||||
}
|
||||
exports.getMonitorRelativeURL = getMonitorRelativeURL;
|
||||
/**
|
||||
* Get relative path for maintenance
|
||||
* @param id ID of maintenance
|
||||
* @returns Formatted relative path
|
||||
*/
|
||||
function getMaintenanceRelativeURL(id) {
|
||||
return "/maintenance/" + id;
|
||||
}
|
||||
exports.getMaintenanceRelativeURL = getMaintenanceRelativeURL;
|
||||
/**
|
||||
* Parse to Time Object that used in VueDatePicker
|
||||
* @param {string} time E.g. 12:00
|
||||
* @returns object
|
||||
*/
|
||||
function parseTimeObject(time) {
|
||||
if (!time) {
|
||||
return {
|
||||
@@ -336,11 +295,11 @@ function parseTimeObject(time) {
|
||||
minutes: 0,
|
||||
};
|
||||
}
|
||||
let array = time.split(":");
|
||||
const array = time.split(":");
|
||||
if (array.length < 2) {
|
||||
throw new Error("parseVueDatePickerTimeFormat: Invalid Time");
|
||||
}
|
||||
let obj = {
|
||||
const obj = {
|
||||
hours: parseInt(array[0]),
|
||||
minutes: parseInt(array[1]),
|
||||
seconds: 0,
|
||||
@@ -351,9 +310,6 @@ function parseTimeObject(time) {
|
||||
return obj;
|
||||
}
|
||||
exports.parseTimeObject = parseTimeObject;
|
||||
/**
|
||||
* @returns string e.g. 12:00
|
||||
*/
|
||||
function parseTimeFromTimeObject(obj) {
|
||||
if (!obj) {
|
||||
return obj;
|
||||
@@ -366,36 +322,27 @@ function parseTimeFromTimeObject(obj) {
|
||||
return result;
|
||||
}
|
||||
exports.parseTimeFromTimeObject = parseTimeFromTimeObject;
|
||||
/**
|
||||
* Convert ISO date to UTC
|
||||
* @param input Date
|
||||
* @returns ISO Date time
|
||||
*/
|
||||
function isoToUTCDateTime(input) {
|
||||
return dayjs(input).utc().format(exports.SQL_DATETIME_FORMAT);
|
||||
}
|
||||
exports.isoToUTCDateTime = isoToUTCDateTime;
|
||||
/**
|
||||
* @param input
|
||||
*/
|
||||
function utcToISODateTime(input) {
|
||||
return dayjs.utc(input).toISOString();
|
||||
}
|
||||
exports.utcToISODateTime = utcToISODateTime;
|
||||
/**
|
||||
* For SQL_DATETIME_FORMAT
|
||||
*/
|
||||
function utcToLocal(input, format = exports.SQL_DATETIME_FORMAT) {
|
||||
return dayjs.utc(input).local().format(format);
|
||||
}
|
||||
exports.utcToLocal = utcToLocal;
|
||||
/**
|
||||
* Convert local datetime to UTC
|
||||
* @param input Local date
|
||||
* @param format Format to return
|
||||
* @returns Date in requested format
|
||||
*/
|
||||
function localToUTC(input, format = exports.SQL_DATETIME_FORMAT) {
|
||||
return dayjs(input).utc().format(format);
|
||||
}
|
||||
exports.localToUTC = localToUTC;
|
||||
function intHash(str, length = 10) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash += str.charCodeAt(i);
|
||||
}
|
||||
return (hash % length + length) % length;
|
||||
}
|
||||
exports.intHash = intHash;
|
||||
|
236
src/util.ts
236
src/util.ts
@@ -1,13 +1,19 @@
|
||||
/*!
|
||||
// Common Util for frontend and backend
|
||||
//
|
||||
// DOT NOT MODIFY util.js!
|
||||
// Need to run "tsc" to compile if there are any changes.
|
||||
// Need to run "npm run tsc" to compile if there are any changes.
|
||||
//
|
||||
// Backend uses the compiled file util.js
|
||||
// Frontend uses util.ts
|
||||
*/
|
||||
|
||||
import * as dayjs from "dayjs";
|
||||
import * as dayjs from "dayjs";
|
||||
|
||||
// For loading dayjs plugins, don't remove event though it is not used in this file
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import * as timezone from "dayjs/plugin/timezone";
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import * as utc from "dayjs/plugin/utc";
|
||||
|
||||
export const isDev = process.env.NODE_ENV === "development";
|
||||
@@ -29,7 +35,66 @@ export const SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm";
|
||||
export const MAX_INTERVAL_SECOND = 2073600; // 24 days
|
||||
export const MIN_INTERVAL_SECOND = 20; // 20 seconds
|
||||
|
||||
/** Flip the status of s */
|
||||
// Console colors
|
||||
// https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color
|
||||
export const CONSOLE_STYLE_Reset = "\x1b[0m";
|
||||
export const CONSOLE_STYLE_Bright = "\x1b[1m";
|
||||
export const CONSOLE_STYLE_Dim = "\x1b[2m";
|
||||
export const CONSOLE_STYLE_Underscore = "\x1b[4m";
|
||||
export const CONSOLE_STYLE_Blink = "\x1b[5m";
|
||||
export const CONSOLE_STYLE_Reverse = "\x1b[7m";
|
||||
export const CONSOLE_STYLE_Hidden = "\x1b[8m";
|
||||
|
||||
export const CONSOLE_STYLE_FgBlack = "\x1b[30m";
|
||||
export const CONSOLE_STYLE_FgRed = "\x1b[31m";
|
||||
export const CONSOLE_STYLE_FgGreen = "\x1b[32m";
|
||||
export const CONSOLE_STYLE_FgYellow = "\x1b[33m";
|
||||
export const CONSOLE_STYLE_FgBlue = "\x1b[34m";
|
||||
export const CONSOLE_STYLE_FgMagenta = "\x1b[35m";
|
||||
export const CONSOLE_STYLE_FgCyan = "\x1b[36m";
|
||||
export const CONSOLE_STYLE_FgWhite = "\x1b[37m";
|
||||
export const CONSOLE_STYLE_FgGray = "\x1b[90m";
|
||||
export const CONSOLE_STYLE_FgOrange = "\x1b[38;5;208m";
|
||||
export const CONSOLE_STYLE_FgLightGreen = "\x1b[38;5;119m";
|
||||
export const CONSOLE_STYLE_FgLightBlue = "\x1b[38;5;117m";
|
||||
export const CONSOLE_STYLE_FgViolet = "\x1b[38;5;141m";
|
||||
export const CONSOLE_STYLE_FgBrown = "\x1b[38;5;130m";
|
||||
export const CONSOLE_STYLE_FgPink = "\x1b[38;5;219m";
|
||||
|
||||
export const CONSOLE_STYLE_BgBlack = "\x1b[40m";
|
||||
export const CONSOLE_STYLE_BgRed = "\x1b[41m";
|
||||
export const CONSOLE_STYLE_BgGreen = "\x1b[42m";
|
||||
export const CONSOLE_STYLE_BgYellow = "\x1b[43m";
|
||||
export const CONSOLE_STYLE_BgBlue = "\x1b[44m";
|
||||
export const CONSOLE_STYLE_BgMagenta = "\x1b[45m";
|
||||
export const CONSOLE_STYLE_BgCyan = "\x1b[46m";
|
||||
export const CONSOLE_STYLE_BgWhite = "\x1b[47m";
|
||||
export const CONSOLE_STYLE_BgGray = "\x1b[100m";
|
||||
|
||||
const consoleModuleColors = [
|
||||
CONSOLE_STYLE_FgCyan,
|
||||
CONSOLE_STYLE_FgGreen,
|
||||
CONSOLE_STYLE_FgLightGreen,
|
||||
CONSOLE_STYLE_FgBlue,
|
||||
CONSOLE_STYLE_FgLightBlue,
|
||||
CONSOLE_STYLE_FgMagenta,
|
||||
CONSOLE_STYLE_FgOrange,
|
||||
CONSOLE_STYLE_FgViolet,
|
||||
CONSOLE_STYLE_FgBrown,
|
||||
CONSOLE_STYLE_FgPink,
|
||||
];
|
||||
|
||||
const consoleLevelColors : Record<string, string> = {
|
||||
"INFO": CONSOLE_STYLE_FgCyan,
|
||||
"WARN": CONSOLE_STYLE_FgYellow,
|
||||
"ERROR": CONSOLE_STYLE_FgRed,
|
||||
"DEBUG": CONSOLE_STYLE_FgGray,
|
||||
};
|
||||
|
||||
/**
|
||||
* Flip the status of s
|
||||
* @param s
|
||||
*/
|
||||
export function flipStatus(s: number) {
|
||||
if (s === UP) {
|
||||
return DOWN;
|
||||
@@ -64,11 +129,10 @@ export function ucfirst(str: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use log.debug
|
||||
* @since https://github.com/louislam/uptime-kuma/pull/910
|
||||
* @deprecated Use log.debug (https://github.com/louislam/uptime-kuma/pull/910)
|
||||
* @param msg
|
||||
*/
|
||||
export function debug(msg: any) {
|
||||
export function debug(msg: unknown) {
|
||||
log.log("", msg, "debug");
|
||||
}
|
||||
|
||||
@@ -83,20 +147,23 @@ class Logger {
|
||||
* "info_monitor",
|
||||
* ]
|
||||
*/
|
||||
hideLog : any = {
|
||||
hideLog : Record<string, string[]> = {
|
||||
info: [],
|
||||
warn: [],
|
||||
error: [],
|
||||
debug: [],
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
if (typeof process !== "undefined" && process.env.UPTIME_KUMA_HIDE_LOG) {
|
||||
let list = process.env.UPTIME_KUMA_HIDE_LOG.split(",").map(v => v.toLowerCase());
|
||||
const list = process.env.UPTIME_KUMA_HIDE_LOG.split(",").map(v => v.toLowerCase());
|
||||
|
||||
for (let pair of list) {
|
||||
for (const pair of list) {
|
||||
// split first "_" only
|
||||
let values = pair.split(/_(.*)/s);
|
||||
const values = pair.split(/_(.*)/s);
|
||||
|
||||
if (values.length >= 2) {
|
||||
this.hideLog[values[0]].push(values[1]);
|
||||
@@ -128,20 +195,39 @@ class Logger {
|
||||
} else {
|
||||
now = dayjs().format();
|
||||
}
|
||||
const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg;
|
||||
|
||||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
|
||||
let timePart = CONSOLE_STYLE_FgCyan + now + CONSOLE_STYLE_Reset;
|
||||
let modulePart = "[" + moduleColor + module + CONSOLE_STYLE_Reset + "]";
|
||||
let levelPart = levelColor + `${level}:` + CONSOLE_STYLE_Reset;
|
||||
|
||||
if (level === "INFO") {
|
||||
console.info(formattedMessage);
|
||||
console.info(timePart, modulePart, levelPart, msg);
|
||||
} else if (level === "WARN") {
|
||||
console.warn(formattedMessage);
|
||||
console.warn(timePart, modulePart, levelPart, msg);
|
||||
} else if (level === "ERROR") {
|
||||
console.error(formattedMessage);
|
||||
let msgPart :string;
|
||||
if (typeof msg === "string") {
|
||||
msgPart = CONSOLE_STYLE_FgRed + msg + CONSOLE_STYLE_Reset;
|
||||
} else {
|
||||
msgPart = msg;
|
||||
}
|
||||
console.error(timePart, modulePart, levelPart, msgPart);
|
||||
} else if (level === "DEBUG") {
|
||||
if (isDev) {
|
||||
console.log(formattedMessage);
|
||||
timePart = CONSOLE_STYLE_FgGray + now + CONSOLE_STYLE_Reset;
|
||||
let msgPart :string;
|
||||
if (typeof msg === "string") {
|
||||
msgPart = CONSOLE_STYLE_FgGray + msg + CONSOLE_STYLE_Reset;
|
||||
} else {
|
||||
msgPart = msg;
|
||||
}
|
||||
console.debug(timePart, modulePart, levelPart, msgPart);
|
||||
}
|
||||
} else {
|
||||
console.log(formattedMessage);
|
||||
console.log(timePart, modulePart, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +236,7 @@ class Logger {
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
info(module: string, msg: any) {
|
||||
info(module: string, msg: unknown) {
|
||||
this.log(module, msg, "info");
|
||||
}
|
||||
|
||||
@@ -159,7 +245,7 @@ class Logger {
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
warn(module: string, msg: any) {
|
||||
warn(module: string, msg: unknown) {
|
||||
this.log(module, msg, "warn");
|
||||
}
|
||||
|
||||
@@ -168,8 +254,8 @@ class Logger {
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
error(module: string, msg: any) {
|
||||
this.log(module, msg, "error");
|
||||
error(module: string, msg: unknown) {
|
||||
this.log(module, msg, "error");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,24 +263,24 @@ class Logger {
|
||||
* @param module Module log comes from
|
||||
* @param msg Message to write
|
||||
*/
|
||||
debug(module: string, msg: any) {
|
||||
this.log(module, msg, "debug");
|
||||
debug(module: string, msg: unknown) {
|
||||
this.log(module, msg, "debug");
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an exeption as an ERROR
|
||||
* Log an exception as an ERROR
|
||||
* @param module Module log comes from
|
||||
* @param exception The exeption to include
|
||||
* @param exception The exception to include
|
||||
* @param msg The message to write
|
||||
*/
|
||||
exception(module: string, exception: any, msg: any) {
|
||||
let finalMessage = exception
|
||||
exception(module: string, exception: unknown, msg: unknown) {
|
||||
let finalMessage = exception;
|
||||
|
||||
if (msg) {
|
||||
finalMessage = `${msg}: ${exception}`
|
||||
finalMessage = `${msg}: ${exception}`;
|
||||
}
|
||||
|
||||
this.log(module, finalMessage , "error");
|
||||
this.log(module, finalMessage, "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,22 +311,28 @@ export function polyfill() {
|
||||
export class TimeLogger {
|
||||
startTime: number;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
this.startTime = dayjs().valueOf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output time since start of monitor
|
||||
* @param name Name of monitor
|
||||
*/
|
||||
print(name: string) {
|
||||
if (isDev && process.env.TIMELOGGER === "1") {
|
||||
console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms")
|
||||
console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random number between min (inclusive) and max (exclusive)
|
||||
* @param min
|
||||
* @param max
|
||||
*/
|
||||
export function getRandomArbitrary(min: number, max: number) {
|
||||
return Math.random() * (max - min) + min;
|
||||
@@ -254,6 +346,8 @@ export function getRandomArbitrary(min: number, max: number) {
|
||||
* if min isn't an integer) and no greater than max (or the next integer
|
||||
* lower than max if max isn't an integer).
|
||||
* Using Math.round() will give you a non-uniform distribution!
|
||||
* @param min
|
||||
* @param max
|
||||
*/
|
||||
export function getRandomInt(min: number, max: number) {
|
||||
min = Math.ceil(min);
|
||||
@@ -265,13 +359,13 @@ export function getRandomInt(min: number, max: number) {
|
||||
* Returns either the NodeJS crypto.randomBytes() function or its
|
||||
* browser equivalent implemented via window.crypto.getRandomValues()
|
||||
*/
|
||||
let getRandomBytes = (
|
||||
(typeof window !== 'undefined' && window.crypto)
|
||||
const getRandomBytes = (
|
||||
(typeof window !== "undefined" && window.crypto)
|
||||
|
||||
// Browsers
|
||||
? function () {
|
||||
return (numBytes: number) => {
|
||||
let randomBytes = new Uint8Array(numBytes);
|
||||
const randomBytes = new Uint8Array(numBytes);
|
||||
for (let i = 0; i < numBytes; i += 65536) {
|
||||
window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536)));
|
||||
}
|
||||
@@ -279,8 +373,9 @@ let getRandomBytes = (
|
||||
};
|
||||
}
|
||||
|
||||
// Node
|
||||
: function() {
|
||||
// Node
|
||||
: function () {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
return require("crypto").randomBytes;
|
||||
}
|
||||
)();
|
||||
@@ -296,35 +391,38 @@ export function getCryptoRandomInt(min: number, max: number):number {
|
||||
|
||||
// synchronous version of: https://github.com/joepie91/node-random-number-csprng
|
||||
|
||||
const range = max - min
|
||||
if (range >= Math.pow(2, 32))
|
||||
console.log("Warning! Range is too large.")
|
||||
|
||||
let tmpRange = range
|
||||
let bitsNeeded = 0
|
||||
let bytesNeeded = 0
|
||||
let mask = 1
|
||||
|
||||
while (tmpRange > 0) {
|
||||
if (bitsNeeded % 8 === 0) bytesNeeded += 1
|
||||
bitsNeeded += 1
|
||||
mask = mask << 1 | 1
|
||||
tmpRange = tmpRange >>> 1
|
||||
const range = max - min;
|
||||
if (range >= Math.pow(2, 32)) {
|
||||
console.log("Warning! Range is too large.");
|
||||
}
|
||||
|
||||
const randomBytes = getRandomBytes(bytesNeeded)
|
||||
let randomValue = 0
|
||||
let tmpRange = range;
|
||||
let bitsNeeded = 0;
|
||||
let bytesNeeded = 0;
|
||||
let mask = 1;
|
||||
|
||||
while (tmpRange > 0) {
|
||||
if (bitsNeeded % 8 === 0) {
|
||||
bytesNeeded += 1;
|
||||
}
|
||||
bitsNeeded += 1;
|
||||
mask = mask << 1 | 1;
|
||||
tmpRange = tmpRange >>> 1;
|
||||
}
|
||||
|
||||
const randomBytes = getRandomBytes(bytesNeeded);
|
||||
let randomValue = 0;
|
||||
|
||||
for (let i = 0; i < bytesNeeded; i++) {
|
||||
randomValue |= randomBytes[i] << 8 * i
|
||||
randomValue |= randomBytes[i] << 8 * i;
|
||||
}
|
||||
|
||||
randomValue = randomValue & mask;
|
||||
|
||||
if (randomValue <= range) {
|
||||
return min + randomValue
|
||||
return min + randomValue;
|
||||
} else {
|
||||
return getCryptoRandomInt(min, max)
|
||||
return getCryptoRandomInt(min, max);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,17 +472,17 @@ export function parseTimeObject(time: string) {
|
||||
};
|
||||
}
|
||||
|
||||
let array = time.split(":");
|
||||
const array = time.split(":");
|
||||
|
||||
if (array.length < 2) {
|
||||
throw new Error("parseVueDatePickerTimeFormat: Invalid Time");
|
||||
}
|
||||
|
||||
let obj = {
|
||||
const obj = {
|
||||
hours: parseInt(array[0]),
|
||||
minutes: parseInt(array[1]),
|
||||
seconds: 0,
|
||||
}
|
||||
};
|
||||
if (array.length >= 3) {
|
||||
obj.seconds = parseInt(array[2]);
|
||||
}
|
||||
@@ -392,6 +490,7 @@ export function parseTimeObject(time: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
* @returns string e.g. 12:00
|
||||
*/
|
||||
export function parseTimeFromTimeObject(obj : any) {
|
||||
@@ -401,10 +500,10 @@ export function parseTimeFromTimeObject(obj : any) {
|
||||
|
||||
let result = "";
|
||||
|
||||
result += obj.hours.toString().padStart(2, "0") + ":" + obj.minutes.toString().padStart(2, "0")
|
||||
result += obj.hours.toString().padStart(2, "0") + ":" + obj.minutes.toString().padStart(2, "0");
|
||||
|
||||
if (obj.seconds) {
|
||||
result += ":" + obj.seconds.toString().padStart(2, "0")
|
||||
result += ":" + obj.seconds.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -428,8 +527,11 @@ export function utcToISODateTime(input : string) {
|
||||
|
||||
/**
|
||||
* For SQL_DATETIME_FORMAT
|
||||
* @param input
|
||||
* @param format
|
||||
* @returns A string date of SQL_DATETIME_FORMAT
|
||||
*/
|
||||
export function utcToLocal(input : string, format = SQL_DATETIME_FORMAT) {
|
||||
export function utcToLocal(input : string, format = SQL_DATETIME_FORMAT) : string {
|
||||
return dayjs.utc(input).local().format(format);
|
||||
}
|
||||
|
||||
@@ -442,3 +544,19 @@ export function utcToLocal(input : string, format = SQL_DATETIME_FORMAT) {
|
||||
export function localToUTC(input : string, format = SQL_DATETIME_FORMAT) {
|
||||
return dayjs(input).utc().format(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a decimal integer number from a string
|
||||
* @param str Input
|
||||
* @param length Default is 10 which means 0 - 9
|
||||
*/
|
||||
export function intHash(str : string, length = 10) : number {
|
||||
// A simple hashing function (you can use more complex hash functions if needed)
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash += str.charCodeAt(i);
|
||||
}
|
||||
// Normalize the hash to the range [0, 10]
|
||||
return (hash % length + length) % length; // Ensure the result is non-negative
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user