mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-08-22 00:19:13 +08:00
Merge remote-tracking branch 'origin/master' into status-page-expiry
# Conflicts: # src/lang/en.json
This commit is contained in:
@@ -111,6 +111,10 @@ optgroup {
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: white;
|
||||
|
||||
@@ -158,6 +162,26 @@ optgroup {
|
||||
background-color: #161B22;
|
||||
}
|
||||
|
||||
.btn-outline-normal {
|
||||
padding: 4px 10px;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 25px;
|
||||
background-color: transparent;
|
||||
|
||||
.dark & {
|
||||
color: $dark-font-color;
|
||||
border: 1px solid $dark-font-color2;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $highlight-white;
|
||||
|
||||
.dark & {
|
||||
background-color: $dark-font-color2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
.table-shadow-box {
|
||||
padding: 10px !important;
|
||||
@@ -436,7 +460,6 @@ optgroup {
|
||||
.monitor-list {
|
||||
&.scrollbar {
|
||||
overflow-y: auto;
|
||||
height: calc(100% - 107px);
|
||||
}
|
||||
|
||||
@media (max-width: 770px) {
|
||||
|
@@ -2,6 +2,10 @@
|
||||
<div class="shadow-box mb-3" :style="boxStyle">
|
||||
<div class="list-header">
|
||||
<div class="header-top">
|
||||
<button class="btn btn-outline-normal ms-2" :class="{ 'active': selectMode }" type="button" @click="selectMode = !selectMode">
|
||||
{{ $t("Select") }}
|
||||
</button>
|
||||
|
||||
<div class="placeholder"></div>
|
||||
<div class="search-wrapper">
|
||||
<a v-if="searchText == ''" class="search-icon">
|
||||
@@ -21,27 +25,55 @@
|
||||
<div class="header-filter">
|
||||
<MonitorListFilter :filterState="filterState" @update-filter="updateFilter" />
|
||||
</div>
|
||||
|
||||
<!-- Selection Controls -->
|
||||
<div v-if="selectMode" class="selection-controls px-2 pt-2">
|
||||
<input
|
||||
v-model="selectAll"
|
||||
class="form-check-input select-input"
|
||||
type="checkbox"
|
||||
/>
|
||||
|
||||
<button class="btn-outline-normal" @click="pauseDialog"><font-awesome-icon icon="pause" size="sm" /> {{ $t("Pause") }}</button>
|
||||
<button class="btn-outline-normal" @click="resumeSelected"><font-awesome-icon icon="play" size="sm" /> {{ $t("Resume") }}</button>
|
||||
|
||||
<span v-if="selectedMonitorCount > 0">
|
||||
{{ $t("selectedMonitorCount", [ selectedMonitorCount ]) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="monitor-list" :class="{ scrollbar: scrollbar }">
|
||||
<div ref="monitorList" class="monitor-list" :class="{ scrollbar: scrollbar }" :style="monitorListStyle">
|
||||
<div v-if="Object.keys($root.monitorList).length === 0" class="text-center mt-3">
|
||||
{{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link>
|
||||
</div>
|
||||
|
||||
<MonitorListItem
|
||||
v-for="(item, index) in sortedMonitorList" :key="index" :monitor="item"
|
||||
v-for="(item, index) in sortedMonitorList"
|
||||
:key="index"
|
||||
:monitor="item"
|
||||
:isSearch="searchText !== ''"
|
||||
:isSelectMode="selectMode"
|
||||
:isSelected="isSelected"
|
||||
:select="select"
|
||||
:deselect="deselect"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Confirm ref="confirmPause" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="pauseSelected">
|
||||
{{ $t("pauseMonitorMsg") }}
|
||||
</Confirm>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Confirm from "../components/Confirm.vue";
|
||||
import MonitorListItem from "../components/MonitorListItem.vue";
|
||||
import MonitorListFilter from "./MonitorListFilter.vue";
|
||||
import { getMonitorRelativeURL } from "../util.ts";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Confirm,
|
||||
MonitorListItem,
|
||||
MonitorListFilter,
|
||||
},
|
||||
@@ -54,6 +86,10 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
searchText: "",
|
||||
selectMode: false,
|
||||
selectAll: false,
|
||||
disableSelectAllWatcher: false,
|
||||
selectedMonitors: {},
|
||||
windowTop: 0,
|
||||
filterState: {
|
||||
status: null,
|
||||
@@ -146,6 +182,58 @@ export default {
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
isDarkTheme() {
|
||||
return document.body.classList.contains("dark");
|
||||
},
|
||||
|
||||
monitorListStyle() {
|
||||
let listHeaderHeight = 107;
|
||||
|
||||
if (this.selectMode) {
|
||||
listHeaderHeight += 42;
|
||||
}
|
||||
|
||||
return {
|
||||
"height": `calc(100% - ${listHeaderHeight}px)`
|
||||
};
|
||||
},
|
||||
|
||||
selectedMonitorCount() {
|
||||
return Object.keys(this.selectedMonitors).length;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
searchText() {
|
||||
for (let monitor of this.sortedMonitorList) {
|
||||
if (!this.selectedMonitors[monitor.id]) {
|
||||
if (this.selectAll) {
|
||||
this.disableSelectAllWatcher = true;
|
||||
this.selectAll = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectAll() {
|
||||
if (!this.disableSelectAllWatcher) {
|
||||
this.selectedMonitors = {};
|
||||
|
||||
if (this.selectAll) {
|
||||
this.sortedMonitorList.forEach((item) => {
|
||||
this.selectedMonitors[item.id] = true;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.disableSelectAllWatcher = false;
|
||||
}
|
||||
},
|
||||
selectMode() {
|
||||
if (!this.selectMode) {
|
||||
this.selectAll = false;
|
||||
this.selectedMonitors = {};
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener("scroll", this.onScroll);
|
||||
@@ -181,6 +269,53 @@ export default {
|
||||
updateFilter(newFilter) {
|
||||
this.filterState = newFilter;
|
||||
},
|
||||
/**
|
||||
* Deselect a monitor
|
||||
* @param {number} id ID of monitor
|
||||
*/
|
||||
deselect(id) {
|
||||
delete this.selectedMonitors[id];
|
||||
},
|
||||
/**
|
||||
* Select a monitor
|
||||
* @param {number} id ID of monitor
|
||||
*/
|
||||
select(id) {
|
||||
this.selectedMonitors[id] = true;
|
||||
},
|
||||
/**
|
||||
* Determine if monitor is selected
|
||||
* @param {number} id ID of monitor
|
||||
* @returns {bool}
|
||||
*/
|
||||
isSelected(id) {
|
||||
return id in this.selectedMonitors;
|
||||
},
|
||||
/** Disable select mode and reset selection */
|
||||
cancelSelectMode() {
|
||||
this.selectMode = false;
|
||||
this.selectedMonitors = {};
|
||||
},
|
||||
/** Show dialog to confirm pause */
|
||||
pauseDialog() {
|
||||
this.$refs.confirmPause.show();
|
||||
},
|
||||
/** Pause each selected monitor */
|
||||
pauseSelected() {
|
||||
Object.keys(this.selectedMonitors)
|
||||
.filter(id => this.$root.monitorList[id].active)
|
||||
.forEach(id => this.$root.getSocket().emit("pauseMonitor", id));
|
||||
|
||||
this.cancelSelectMode();
|
||||
},
|
||||
/** Resume each selected monitor */
|
||||
resumeSelected() {
|
||||
Object.keys(this.selectedMonitors)
|
||||
.filter(id => !this.$root.monitorList[id].active)
|
||||
.forEach(id => this.$root.getSocket().emit("resumeMonitor", id));
|
||||
|
||||
this.cancelSelectMode();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -271,4 +406,12 @@ export default {
|
||||
padding-left: 67px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.selection-controls {
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@@ -44,6 +44,7 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
@import "../assets/vars.scss";
|
||||
@import "../assets/app.scss";
|
||||
|
||||
.filter-dropdown-menu {
|
||||
z-index: 100;
|
||||
@@ -102,18 +103,10 @@ export default {
|
||||
}
|
||||
|
||||
.filter-dropdown-status {
|
||||
@extend .btn-outline-normal;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
margin-left: 5px;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 25px;
|
||||
background-color: transparent;
|
||||
|
||||
.dark & {
|
||||
color: $dark-font-color;
|
||||
border: 1px solid $dark-font-color2;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border: 1px solid $highlight;
|
||||
|
@@ -1,34 +1,56 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-link :to="monitorURL(monitor.id)" class="item" :class="{ 'disabled': ! monitor.active }">
|
||||
<div class="row">
|
||||
<div class="col-9 col-md-8 small-padding" :class="{ 'monitor-item': $root.userHeartbeatBar == 'bottom' || $root.userHeartbeatBar == 'none' }">
|
||||
<div class="info" :style="depthMargin">
|
||||
<Uptime :monitor="monitor" type="24" :pill="true" />
|
||||
<span v-if="hasChildren" class="collapse-padding" @click.prevent="changeCollapsed">
|
||||
<font-awesome-icon icon="chevron-down" class="animated" :class="{ collapsed: isCollapsed}" />
|
||||
</span>
|
||||
{{ monitorName }}
|
||||
</div>
|
||||
<div class="tags">
|
||||
<Tag v-for="tag in monitor.tags" :key="tag" :item="tag" :size="'sm'" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="$root.userHeartbeatBar == 'normal'" :key="$root.userHeartbeatBar" class="col-3 col-md-4">
|
||||
<HeartbeatBar size="small" :monitor-id="monitor.id" />
|
||||
</div>
|
||||
<div :style="depthMargin">
|
||||
<!-- Checkbox -->
|
||||
<div v-if="isSelectMode" class="select-input-wrapper">
|
||||
<input
|
||||
class="form-check-input select-input"
|
||||
type="checkbox"
|
||||
:aria-label="$t('Check/Uncheck')"
|
||||
:checked="isSelected(monitor.id)"
|
||||
@click.stop="toggleSelection"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="$root.userHeartbeatBar == 'bottom'" class="row">
|
||||
<div class="col-12 bottom-style">
|
||||
<HeartbeatBar size="small" :monitor-id="monitor.id" />
|
||||
<router-link :to="monitorURL(monitor.id)" class="item" :class="{ 'disabled': ! monitor.active }">
|
||||
<div class="row">
|
||||
<div class="col-9 col-md-8 small-padding" :class="{ 'monitor-item': $root.userHeartbeatBar == 'bottom' || $root.userHeartbeatBar == 'none' }">
|
||||
<div class="info">
|
||||
<Uptime :monitor="monitor" type="24" :pill="true" />
|
||||
<span v-if="hasChildren" class="collapse-padding" @click.prevent="changeCollapsed">
|
||||
<font-awesome-icon icon="chevron-down" class="animated" :class="{ collapsed: isCollapsed}" />
|
||||
</span>
|
||||
{{ monitorName }}
|
||||
</div>
|
||||
<div v-if="monitor.tags.length > 0" class="tags">
|
||||
<Tag v-for="tag in monitor.tags" :key="tag" :item="tag" :size="'sm'" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="$root.userHeartbeatBar == 'normal'" :key="$root.userHeartbeatBar" class="col-3 col-md-4">
|
||||
<HeartbeatBar ref="heartbeatBar" size="small" :monitor-id="monitor.id" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
|
||||
<div v-if="$root.userHeartbeatBar == 'bottom'" class="row">
|
||||
<div class="col-12 bottom-style">
|
||||
<HeartbeatBar ref="heartbeatBar" size="small" :monitor-id="monitor.id" />
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<transition name="slide-fade-up">
|
||||
<div v-if="!isCollapsed" class="childs">
|
||||
<MonitorListItem v-for="(item, index) in sortedChildMonitorList" :key="index" :monitor="item" :isSearch="isSearch" :depth="depth + 1" />
|
||||
<MonitorListItem
|
||||
v-for="(item, index) in sortedChildMonitorList"
|
||||
:key="index" :monitor="item"
|
||||
:isSearch="isSearch"
|
||||
:isSelectMode="isSelectMode"
|
||||
:isSelected="isSelected"
|
||||
:select="select"
|
||||
:deselect="deselect"
|
||||
:depth="depth + 1"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
@@ -58,11 +80,31 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** If the user is in select mode */
|
||||
isSelectMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** How many ancestors are above this monitor */
|
||||
depth: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
/** Callback to determine if monitor is selected */
|
||||
isSelected: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
},
|
||||
/** Callback fired when monitor is selected */
|
||||
select: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
},
|
||||
/** Callback fired when monitor is deselected */
|
||||
deselect: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -118,6 +160,12 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isSelectMode() {
|
||||
// TODO: Resize the heartbeat bar, but too slow
|
||||
// this.$refs.heartbeatBar.resize();
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
|
||||
// Always unfold if monitor is accessed directly
|
||||
@@ -164,6 +212,16 @@ export default {
|
||||
monitorURL(id) {
|
||||
return getMonitorRelativeURL(id);
|
||||
},
|
||||
/**
|
||||
* Toggle selection of monitor
|
||||
*/
|
||||
toggleSelection() {
|
||||
if (this.isSelected(this.monitor.id)) {
|
||||
this.deselect(this.monitor.id);
|
||||
} else {
|
||||
this.select(this.monitor.id);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -201,4 +259,14 @@ export default {
|
||||
transition: all 0.2s $easing-in;
|
||||
}
|
||||
|
||||
.select-input-wrapper {
|
||||
float: left;
|
||||
margin-top: 15px;
|
||||
margin-left: 3px;
|
||||
margin-right: 10px;
|
||||
padding-left: 4px;
|
||||
position: relative;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@@ -126,6 +126,7 @@ export default {
|
||||
"lunasea": "LunaSea",
|
||||
"matrix": "Matrix",
|
||||
"mattermost": "Mattermost",
|
||||
"nostr": "Nostr",
|
||||
"ntfy": "Ntfy",
|
||||
"octopush": "Octopush",
|
||||
"OneBot": "OneBot",
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<label for="gorush-platform" class="form-label">{{ $t("Platform") }}</label><span style="color: red;"><sup>*</sup></span>
|
||||
<select id="gorush-platform" v-model="$parent.notification.gorushPlatform" class="form-select">
|
||||
<option value="ios">iOS</option>
|
||||
<option value="android">{{ $t("Android") }}</option>
|
||||
<option value="android">Android</option>
|
||||
<option value="huawei">{{ $t("Huawei") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@@ -13,7 +13,7 @@
|
||||
<div class="form-text">
|
||||
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
||||
<i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;">
|
||||
<a href="https://docs.mattermost.com/developer/webhooks-incoming.html" target="_blank">https://docs.mattermost.com/developer/webhooks-incoming.html</a>
|
||||
<a href="https://developers.mattermost.com/integrate/webhooks/incoming/" target="_blank">https://developers.mattermost.com/integrate/webhooks/incoming/</a>
|
||||
</i18n-t>
|
||||
<p style="margin-top: 8px;">
|
||||
{{ $t("aboutMattermostChannelName") }}
|
||||
|
26
src/components/notifications/Nostr.vue
Normal file
26
src/components/notifications/Nostr.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="nostr-relays" class="form-label">{{ $t("nostrRelays") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<textarea id="nostr-relays" v-model="$parent.notification.relays" class="form-control" :required="true" placeholder="wss://127.0.0.1:7777/"></textarea>
|
||||
<small class="form-text text-muted">{{ $t("nostrRelaysHelp") }}</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="nostr-sender" class="form-label">{{ $t("nostrSender") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<HiddenInput id="nostr-sender" v-model="$parent.notification.sender" autocomplete="new-password" :required="true"></HiddenInput>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="nostr-recipients" class="form-label">{{ $t("nostrRecipients") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<textarea id="nostr-recipients" v-model="$parent.notification.recipients" class="form-control" :required="true" placeholder="npub123... npub789..."></textarea>
|
||||
<small class="form-text text-muted">{{ $t("nostrRecipientsHelp") }}</small>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
},
|
||||
};
|
||||
</script>
|
@@ -7,8 +7,9 @@
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ntfy-server-url" class="form-label">{{ $t("Server URL") }}</label>
|
||||
<div class="input-group mb-3">
|
||||
<input id="ntfy-server-url" v-model="$parent.notification.ntfyserverurl" type="text" class="form-control" required>
|
||||
<input id="ntfy-server-url" v-model="$parent.notification.ntfyserverurl" type="text" class="form-control" required>
|
||||
<div class="form-text">
|
||||
{{ $t("Server URL should not contain the nfty topic") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
|
@@ -19,6 +19,7 @@ import LineNotify from "./LineNotify.vue";
|
||||
import LunaSea from "./LunaSea.vue";
|
||||
import Matrix from "./Matrix.vue";
|
||||
import Mattermost from "./Mattermost.vue";
|
||||
import Nostr from "./Nostr.vue";
|
||||
import Ntfy from "./Ntfy.vue";
|
||||
import Octopush from "./Octopush.vue";
|
||||
import OneBot from "./OneBot.vue";
|
||||
@@ -77,6 +78,7 @@ const NotificationFormList = {
|
||||
"lunasea": LunaSea,
|
||||
"matrix": Matrix,
|
||||
"mattermost": Mattermost,
|
||||
"nostr": Nostr,
|
||||
"ntfy": Ntfy,
|
||||
"octopush": Octopush,
|
||||
"OneBot": OneBot,
|
||||
|
@@ -455,8 +455,6 @@
|
||||
"For safety, must use secret key": "للسلامة يجب استخدام المفتاح السري",
|
||||
"Device Token": "رمز الجهاز",
|
||||
"Platform": "منصة",
|
||||
"iOS": "iOS",
|
||||
"Android": "ذكري المظهر",
|
||||
"Huawei": "هواوي",
|
||||
"High": "عالٍ",
|
||||
"Retry": "إعادة المحاولة",
|
||||
|
@@ -592,7 +592,6 @@
|
||||
"For safety, must use secret key": "للسلامة يجب استخدام المفتاح السري",
|
||||
"Device Token": "رمز الجهاز",
|
||||
"Platform": "منصة",
|
||||
"Android": "ذكري المظهر",
|
||||
"Huawei": "هواوي",
|
||||
"High": "عالٍ",
|
||||
"Retry": "إعادة المحاولة",
|
||||
|
@@ -396,8 +396,6 @@
|
||||
"For safety, must use secret key": "За сигурност, трябва да се използва таен ключ",
|
||||
"Device Token": "Токен за устройство",
|
||||
"Platform": "Платформа",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Висок",
|
||||
"Retry": "Повтори",
|
||||
|
@@ -454,8 +454,6 @@
|
||||
"For safety, must use secret key": "Z důvodu bezpečnosti použijte secret key",
|
||||
"Device Token": "Token zařízení",
|
||||
"Platform": "Platforma",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Vysoký",
|
||||
"Retry": "Opakovat",
|
||||
|
@@ -558,7 +558,6 @@
|
||||
"high": "høj",
|
||||
"Base URL": "Base URL",
|
||||
"Platform": "Platform",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"Retry": "Forsøg igen",
|
||||
"Topic": "Emne",
|
||||
|
@@ -403,8 +403,6 @@
|
||||
"For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden",
|
||||
"Device Token": "Gerätetoken",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Hoch",
|
||||
"Retry": "Wiederholungen",
|
||||
|
@@ -403,8 +403,6 @@
|
||||
"For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden",
|
||||
"Device Token": "Gerätetoken",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Hoch",
|
||||
"Retry": "Wiederholungen",
|
||||
|
@@ -420,8 +420,6 @@
|
||||
"For safety, must use secret key": "Για ασφάλεια, πρέπει να χρησιμοποιήσετε secret key",
|
||||
"Device Token": "Device Token",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "High",
|
||||
"Retry": "Ξαναδοκιμάσετε",
|
||||
|
@@ -269,6 +269,9 @@
|
||||
"Services": "Services",
|
||||
"Discard": "Discard",
|
||||
"Cancel": "Cancel",
|
||||
"Select": "Select",
|
||||
"selectedMonitorCount": "Selected: {0}",
|
||||
"Check/Uncheck": "Check/Uncheck",
|
||||
"Powered by": "Powered by",
|
||||
"shrinkDatabaseDescription": "Trigger database VACUUM for SQLite. If your database is created after 1.10.0, AUTO_VACUUM is already enabled and this action is not needed.",
|
||||
"Customize": "Customize",
|
||||
@@ -364,6 +367,7 @@
|
||||
"deleteDockerHostMsg": "Are you sure want to delete this docker host for all monitors?",
|
||||
"socket": "Socket",
|
||||
"tcp": "TCP / HTTP",
|
||||
"tailscalePingWarning": "In order to use the Tailscale Ping monitor, you need to install Uptime Kuma without Docker and also install Tailscale client on your server.",
|
||||
"Docker Container": "Docker Container",
|
||||
"Container Name / ID": "Container Name / ID",
|
||||
"Docker Host": "Docker Host",
|
||||
@@ -619,7 +623,6 @@
|
||||
"For safety, must use secret key": "For safety, must use secret key",
|
||||
"Device Token": "Device Token",
|
||||
"Platform": "Platform",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "High",
|
||||
"Retry": "Retry",
|
||||
@@ -690,6 +693,7 @@
|
||||
"Octopush API Version": "Octopush API Version",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"ntfy Topic": "ntfy Topic",
|
||||
"Server URL should not contain the nfty topic": "Server URL should not contain the nfty topic",
|
||||
"onebotHttpAddress": "OneBot HTTP Address",
|
||||
"onebotMessageType": "OneBot Message Type",
|
||||
"onebotGroupMessage": "Group",
|
||||
@@ -785,6 +789,11 @@
|
||||
"noGroupMonitorMsg": "Not Available. Create a Group Monitor First.",
|
||||
"Close": "Close",
|
||||
"Request Body": "Request Body",
|
||||
"nostrRelays": "Nostr relays",
|
||||
"nostrRelaysHelp": "One relay URL per line",
|
||||
"nostrSender": "Sender Private Key (nsec)",
|
||||
"nostrRecipients": "Recipients Public Keys (npub)",
|
||||
"nostrRecipientsHelp": "npub format, one per line",
|
||||
"showCertificateExpiry": "Show Certificate Expiry",
|
||||
"noOrBadCertificate": "No/Bad Certificate"
|
||||
}
|
||||
|
@@ -497,8 +497,6 @@
|
||||
"Proto Method": "Método Proto",
|
||||
"Proto Content": "Contenido Proto",
|
||||
"Economy": "Económico",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Platform": "Plataforma",
|
||||
"onebotPrivateMessage": "Privado",
|
||||
"onebotMessageType": "Tipo de Mensaje OneBot",
|
||||
|
@@ -415,8 +415,6 @@
|
||||
"For safety, must use secret key": "For safety, must use secret key",
|
||||
"Device Token": "Gailu tokena",
|
||||
"Platform": "Plataforma",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Altua",
|
||||
"Retry": "Errepikatu",
|
||||
|
@@ -568,7 +568,6 @@
|
||||
"SendKey": "کلید ارسال (SendKey)",
|
||||
"SecretAccessKey": "کلید دسترسی مخفی (AccessKey Secret)",
|
||||
"SignName": "نام امضا (SignName)",
|
||||
"Android": "اندروید",
|
||||
"Huawei": "هواوی",
|
||||
"WeCom Bot Key": "کلید ربات WeCom",
|
||||
"Setup Proxy": "تنظیم پروکسی",
|
||||
|
@@ -547,7 +547,6 @@
|
||||
"For safety, must use secret key": "Turvallisuuden vuoksi on käytettävä salaista avainta",
|
||||
"Device Token": "Laitteen tunnus",
|
||||
"Platform": "Alusta",
|
||||
"iOS": "iOS",
|
||||
"Bark Endpoint": "Bark päätepiste",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Korkea",
|
||||
@@ -564,7 +563,6 @@
|
||||
"promosmsAllowLongSMS": "Salli pitkät tekstiviestit",
|
||||
"Feishu WebHookUrl": "Feishu WebHookURL-osoite",
|
||||
"Internal Room Id": "Huoneen sisäinen tunnus",
|
||||
"Android": "Android",
|
||||
"Channel Name": "Kanavan nimi",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL-osoite",
|
||||
"Icon Emoji": "Ikoni Emoji",
|
||||
|
@@ -451,8 +451,6 @@
|
||||
"For safety, must use secret key": "Par sécurité, utilisation obligatoire de la clé secrète",
|
||||
"Device Token": "Jeton d'appareil",
|
||||
"Platform": "Plateforme",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Haute",
|
||||
"Retry": "Recommencez",
|
||||
|
@@ -445,8 +445,6 @@
|
||||
"For safety, must use secret key": "לבטיחות, חייב להשתמש במפתח סודיy",
|
||||
"Device Token": "אסימון מכשיר",
|
||||
"Platform": "פּלַטפוֹרמָה",
|
||||
"iOS": "iOS",
|
||||
"Android": "דְמוּי אָדָם",
|
||||
"Huawei": "huawei",
|
||||
"High": "High",
|
||||
"Retry": "נסה שוב",
|
||||
|
@@ -420,8 +420,6 @@
|
||||
"For safety, must use secret key": "Korištenje tajnog ključa je obavezno",
|
||||
"Device Token": "Token uređaja",
|
||||
"Platform": "Platforma",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Visoko",
|
||||
"Retry": "Ponovnih pokušaja",
|
||||
|
@@ -418,8 +418,6 @@
|
||||
"For safety, must use secret key": "Untuk keamaan Anda harus menggunakan kunci rahasia",
|
||||
"Device Token": "Token Perangkat",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Tinggi",
|
||||
"Retry": "Ulang",
|
||||
|
@@ -507,7 +507,6 @@
|
||||
"lineDevConsoleTo": "Line Developers Console - {0}",
|
||||
"Basic Settings": "基本設定",
|
||||
"User ID": "User ID",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"Device Token": "デバイストークン",
|
||||
"recurringIntervalMessage": "毎日1回実行する|{0} 日に1回実行する",
|
||||
|
@@ -413,8 +413,6 @@
|
||||
"For safety, must use secret key": "안전을 위해 꼭 Secret Key를 사용하세요.",
|
||||
"Device Token": "기기 Token",
|
||||
"Platform": "플랫폼",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "High",
|
||||
"Retry": "재시도",
|
||||
|
@@ -404,8 +404,6 @@
|
||||
"For safety, must use secret key": "Voor de veiligheid moet je de secret key gebruiken",
|
||||
"Device Token": "Apparaat Token",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Hoog",
|
||||
"Retry": "Opnieuw",
|
||||
|
@@ -414,8 +414,6 @@
|
||||
"For safety, must use secret key": "Ze względów bezpieczeństwa musisz użyć tajnego klucza",
|
||||
"Device Token": "Token urządzenia",
|
||||
"Platform": "Platforma",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Wysoki",
|
||||
"Retry": "Ponów",
|
||||
|
@@ -523,7 +523,6 @@
|
||||
"Example:": "Exemplo: {0}",
|
||||
"Read more:": "Leia mais em: {0}",
|
||||
"promosmsAllowLongSMS": "Permitir SMS grandes",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"smseagleTo": "Números Dos Telefones",
|
||||
"smseaglePriority": "Prioridade da mensagem (0-9, padrão=0)",
|
||||
|
@@ -421,8 +421,6 @@
|
||||
"For safety, must use secret key": "В целях безопасности необходимо использовать секретный ключ",
|
||||
"Device Token": "Токен устройства",
|
||||
"Platform": "Платформа",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "High",
|
||||
"Retry": "Повторить",
|
||||
|
@@ -404,8 +404,6 @@
|
||||
"For safety, must use secret key": "เพื่อความปลอดภัย จำเป็นต้องตั้งค่ากุญแจการเข้าถึง",
|
||||
"Device Token": "Device Token",
|
||||
"Platform": "แพลตฟอร์ม",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "สูง",
|
||||
"Retry": "ลองใหม่",
|
||||
|
@@ -408,8 +408,6 @@
|
||||
"For safety, must use secret key": "Güvenlik için gizli anahtar kullanılmalıdır",
|
||||
"Device Token": "Cihaz Tokeni",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "High",
|
||||
"Retry": "Tekrar",
|
||||
|
@@ -413,8 +413,6 @@
|
||||
"For safety, must use secret key": "Для безпеки необхідно використовувати секретний ключ",
|
||||
"Device Token": "Токен пристрою",
|
||||
"Platform": "Платформа",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Високий",
|
||||
"Retry": "Повтор",
|
||||
|
@@ -403,8 +403,6 @@
|
||||
"For safety, must use secret key": "Để an toàn, hãy dùng secret key",
|
||||
"Device Token": "Device Token",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "High",
|
||||
"Retry": "Retry",
|
||||
|
@@ -452,8 +452,6 @@
|
||||
"For safety, must use secret key": "出于安全考虑,必须使用加签密钥",
|
||||
"Device Token": "Apple Device Token",
|
||||
"Platform": "平台",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "华为",
|
||||
"High": "高",
|
||||
"Retry": "重试次数",
|
||||
|
@@ -694,7 +694,6 @@
|
||||
"Retry": "重試",
|
||||
"High": "高",
|
||||
"Huawei": "華為",
|
||||
"Android": "Android",
|
||||
"For safety, must use secret key": "為安全起見,必須使用 Secret Key",
|
||||
"SecretKey": "SecretKey",
|
||||
"WebHookUrl": "WebHookUrl",
|
||||
|
@@ -445,8 +445,6 @@
|
||||
"For safety, must use secret key": "為了安全起見,必須使用秘密金鑰",
|
||||
"Device Token": "裝置權杖",
|
||||
"Platform": "平台",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "華為",
|
||||
"High": "高",
|
||||
"Retry": "重試",
|
||||
|
@@ -82,10 +82,17 @@
|
||||
<option value="redis">
|
||||
Redis
|
||||
</option>
|
||||
<option value="tailscale-ping">
|
||||
Tailscale Ping
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div v-if="monitor.type === 'tailscale-ping'" class="alert alert-warning" role="alert">
|
||||
{{ $t("tailscalePingWarning") }}
|
||||
</div>
|
||||
|
||||
<!-- Friendly Name -->
|
||||
<div class="my-3">
|
||||
<label for="name" class="form-label">{{ $t("Friendly Name") }}</label>
|
||||
@@ -221,8 +228,8 @@
|
||||
</template>
|
||||
|
||||
<!-- Hostname -->
|
||||
<!-- TCP Port / Ping / DNS / Steam / MQTT / Radius only -->
|
||||
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' ||monitor.type === 'mqtt' || monitor.type === 'radius'" class="my-3">
|
||||
<!-- TCP Port / Ping / DNS / Steam / MQTT / Radius / Tailscale Ping only -->
|
||||
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' ||monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'tailscale-ping'" class="my-3">
|
||||
<label for="hostname" class="form-label">{{ $t("Hostname") }}</label>
|
||||
<input id="hostname" v-model="monitor.hostname" type="text" class="form-control" :pattern="`${monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern : ipOrHostnameRegexPattern}`" required>
|
||||
</div>
|
||||
@@ -366,42 +373,18 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- SQL Server / PostgreSQL / MySQL / Redis / MongoDB -->
|
||||
<template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres' || monitor.type === 'mysql' || monitor.type === 'redis' || monitor.type === 'mongodb'">
|
||||
<div class="my-3">
|
||||
<label for="connectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||
<input id="connectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" required>
|
||||
</div>
|
||||
</template>
|
||||
<!-- SQL Server / PostgreSQL / MySQL -->
|
||||
<template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres' || monitor.type === 'mysql'">
|
||||
<div class="my-3">
|
||||
<label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||
|
||||
<template v-if="monitor.type === 'sqlserver'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
<template v-if="monitor.type === 'postgres'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
<template v-if="monitor.type === 'mysql'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<label for="sqlQuery" class="form-label">{{ $t("Query") }}</label>
|
||||
<textarea id="sqlQuery" v-model="monitor.databaseQuery" class="form-control" placeholder="Example: select getdate()"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Redis -->
|
||||
<template v-if="monitor.type === 'redis'">
|
||||
<div class="my-3">
|
||||
<label for="redisConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||
<input id="redisConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- MongoDB -->
|
||||
<template v-if="monitor.type === 'mongodb'">
|
||||
<div class="my-3">
|
||||
<label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||
|
||||
<template v-if="monitor.type === 'mongodb'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
<textarea id="sqlQuery" v-model="monitor.databaseQuery" class="form-control" :placeholder="$t('Example:', [ 'select getdate()' ])" required></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
Reference in New Issue
Block a user