mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-17 03:34:51 -05:00
Merge remote-tracking branch 'origin/master' into test/add-cypress-tests
# Conflicts: # package.json
This commit is contained in:
commit
197d44981f
13
README.md
13
README.md
@ -23,7 +23,7 @@ VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollec
|
||||
|
||||
## ⭐ Features
|
||||
|
||||
* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server.
|
||||
* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server / Docker Containers.
|
||||
* Fancy, Reactive, Fast UI/UX.
|
||||
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications).
|
||||
* 20 second intervals.
|
||||
@ -157,7 +157,14 @@ You can mention me if you ask a question on Reddit.
|
||||
|
||||
## Contribute
|
||||
|
||||
### Beta Version
|
||||
### Test Pull Requests
|
||||
|
||||
There are a lot of pull requests right now, but I don't have time to test them all.
|
||||
|
||||
If you want to help, you can check this:
|
||||
https://github.com/louislam/uptime-kuma/wiki/Test-Pull-Requests
|
||||
|
||||
### Test Beta Version
|
||||
|
||||
Check out the latest beta release here: https://github.com/louislam/uptime-kuma/releases
|
||||
|
||||
@ -169,5 +176,5 @@ If you want to translate Uptime Kuma into your language, please read: https://gi
|
||||
|
||||
Feel free to correct my grammar in this README, source code, or wiki, as my mother language is not English and my grammar is not that great.
|
||||
|
||||
### Pull Requests
|
||||
### Create Pull Requests
|
||||
If you want to modify Uptime Kuma, this guideline may be useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md
|
||||
|
18
db/patch-add-docker-columns.sql
Normal file
18
db/patch-add-docker-columns.sql
Normal file
@ -0,0 +1,18 @@
|
||||
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
CREATE TABLE docker_host (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INT NOT NULL,
|
||||
docker_daemon VARCHAR(255),
|
||||
docker_type VARCHAR(255),
|
||||
name VARCHAR(255)
|
||||
);
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD docker_host INTEGER REFERENCES docker_host(id);
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD docker_container VARCHAR(255);
|
||||
|
||||
COMMIT;
|
18
db/patch-add-radius-monitor.sql
Normal file
18
db/patch-add-radius-monitor.sql
Normal file
@ -0,0 +1,18 @@
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD radius_username VARCHAR(255);
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD radius_password VARCHAR(255);
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD radius_calling_station_id VARCHAR(50);
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD radius_called_station_id VARCHAR(50);
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD radius_secret VARCHAR(255);
|
||||
|
||||
COMMIT
|
10
db/patch-monitor-add-resend-interval.sql
Normal file
10
db/patch-monitor-add-resend-interval.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD resend_interval INTEGER default 0 not null;
|
||||
|
||||
ALTER TABLE heartbeat
|
||||
ADD down_count INTEGER default 0 not null;
|
||||
|
||||
COMMIT;
|
@ -4,5 +4,5 @@ WORKDIR /app
|
||||
|
||||
# Install apprise, iputils for non-root ping, setpriv
|
||||
RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \
|
||||
pip3 --no-cache-dir install apprise==0.9.9 && \
|
||||
pip3 --no-cache-dir install apprise==1.0.0 && \
|
||||
rm -rf /root/.cache
|
||||
|
@ -11,7 +11,7 @@ WORKDIR /app
|
||||
RUN apt update && \
|
||||
apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
|
||||
sqlite3 iputils-ping util-linux dumb-init && \
|
||||
pip3 --no-cache-dir install apprise==0.9.9 && \
|
||||
pip3 --no-cache-dir install apprise==1.0.0 && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
apt --yes autoremove
|
||||
|
||||
|
@ -24,6 +24,36 @@ CMD ["node", "server/server.js"]
|
||||
FROM release AS nightly
|
||||
RUN npm run mark-as-nightly
|
||||
|
||||
# Build an image for testing pr
|
||||
FROM louislam/uptime-kuma:base-debian AS pr-test
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
|
||||
|
||||
## Install Git
|
||||
RUN apt update \
|
||||
&& apt --yes --no-install-recommends install curl \
|
||||
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||
&& apt update \
|
||||
&& apt --yes --no-install-recommends install git
|
||||
|
||||
## Empty the directory, because we have to clone the Git repo.
|
||||
RUN rm -rf ./* && chown node /app
|
||||
|
||||
USER node
|
||||
RUN git config --global user.email "no-reply@no-reply.com"
|
||||
RUN git config --global user.name "PR Tester"
|
||||
RUN git clone https://github.com/louislam/uptime-kuma.git .
|
||||
RUN npm ci
|
||||
|
||||
EXPOSE 3000 3001
|
||||
VOLUME ["/app/data"]
|
||||
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js
|
||||
CMD ["npm", "run", "start-pr-test"]
|
||||
|
||||
|
||||
# Upload the artifact to Github
|
||||
FROM louislam/uptime-kuma:base-debian AS upload-artifact
|
||||
|
33
extra/checkout-pr.js
Normal file
33
extra/checkout-pr.js
Normal file
@ -0,0 +1,33 @@
|
||||
const childProcess = require("child_process");
|
||||
|
||||
if (!process.env.UPTIME_KUMA_GH_REPO) {
|
||||
console.error("Please set a repo to the environment variable 'UPTIME_KUMA_GH_REPO' (e.g. mhkarimi1383:goalert-notification)");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let inputArray = process.env.UPTIME_KUMA_GH_REPO.split(":");
|
||||
|
||||
if (inputArray.length !== 2) {
|
||||
console.error("Invalid format. Please set a repo to the environment variable 'UPTIME_KUMA_GH_REPO' (e.g. mhkarimi1383:goalert-notification)");
|
||||
}
|
||||
|
||||
let name = inputArray[0];
|
||||
let branch = inputArray[1];
|
||||
|
||||
console.log("Checkout pr");
|
||||
|
||||
// Checkout the pr
|
||||
let result = childProcess.spawnSync("git", [ "remote", "add", name, `https://github.com/${name}/uptime-kuma` ]);
|
||||
|
||||
console.log(result.stdout.toString());
|
||||
console.error(result.stderr.toString());
|
||||
|
||||
result = childProcess.spawnSync("git", [ "fetch", name, branch ]);
|
||||
|
||||
console.log(result.stdout.toString());
|
||||
console.error(result.stderr.toString());
|
||||
|
||||
result = childProcess.spawnSync("git", [ "checkout", branch, "--force" ]);
|
||||
|
||||
console.log(result.stdout.toString());
|
||||
console.error(result.stderr.toString());
|
3540
package-lock.json
generated
3540
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uptime-kuma",
|
||||
"version": "1.17.1",
|
||||
"version": "1.18.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -38,8 +38,9 @@
|
||||
"build-docker-nightly": "npm run build && docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
|
||||
"build-docker-nightly-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push",
|
||||
"build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
|
||||
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test --target pr-test . --push",
|
||||
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
|
||||
"setup": "git checkout 1.17.1 && npm ci --production && npm run download-dist",
|
||||
"setup": "git checkout 1.18.0 && npm ci --production && npm run download-dist",
|
||||
"download-dist": "node extra/download-dist.js",
|
||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||
"reset-password": "node extra/reset-password.js",
|
||||
@ -59,13 +60,14 @@
|
||||
"release-beta": "node extra/beta/update-version.js && npm run build && node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:$VERSION -t louislam/uptime-kuma:beta . --target release --push && node ./extra/press-any-key.js && npm run upload-artifacts",
|
||||
"git-remove-tag": "git tag -d",
|
||||
"build-dist-and-restart": "npm run build && npm run start-server-dev",
|
||||
"start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev",
|
||||
"cy:test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --e2e",
|
||||
"cy:run": "npx cypress run --browser chrome --headless"
|
||||
},
|
||||
"dependencies": {
|
||||
"@louislam/sqlite3": "~15.0.6",
|
||||
"args-parser": "~1.3.0",
|
||||
"axios": "~0.26.1",
|
||||
"axios": "~0.27.0",
|
||||
"axios-ntlm": "^1.3.0",
|
||||
"badge-maker": "^3.3.1",
|
||||
"bcryptjs": "~2.4.3",
|
||||
@ -93,9 +95,12 @@
|
||||
"mqtt": "^4.2.8",
|
||||
"mssql": "^8.1.0",
|
||||
"node-cloudflared-tunnel": "~1.0.9",
|
||||
"node-radius-client": "^1.0.0",
|
||||
"nodemailer": "~6.6.5",
|
||||
"notp": "~2.0.3",
|
||||
"password-hash": "~1.2.2",
|
||||
"pg": "^8.7.3",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"prom-client": "~13.2.0",
|
||||
"prometheus-api-metrics": "~3.2.1",
|
||||
"redbean-node": "0.1.4",
|
||||
|
@ -125,10 +125,35 @@ async function sendInfo(socket) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send list of docker hosts to client
|
||||
* @param {Socket} socket Socket.io socket instance
|
||||
* @returns {Promise<Bean[]>}
|
||||
*/
|
||||
async function sendDockerHostList(socket) {
|
||||
const timeLogger = new TimeLogger();
|
||||
|
||||
let result = [];
|
||||
let list = await R.find("docker_host", " user_id = ? ", [
|
||||
socket.userID,
|
||||
]);
|
||||
|
||||
for (let bean of list) {
|
||||
result.push(bean.toJSON());
|
||||
}
|
||||
|
||||
io.to(socket.userID).emit("dockerHostList", result);
|
||||
|
||||
timeLogger.print("Send Docker Host List");
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sendNotificationList,
|
||||
sendImportantHeartbeatList,
|
||||
sendHeartbeatList,
|
||||
sendProxyList,
|
||||
sendInfo,
|
||||
sendDockerHostList
|
||||
};
|
||||
|
@ -53,6 +53,7 @@ class Database {
|
||||
"patch-2fa-invalidate-used-token.sql": true,
|
||||
"patch-notification_sent_history.sql": true,
|
||||
"patch-monitor-basic-auth.sql": true,
|
||||
"patch-add-docker-columns.sql": true,
|
||||
"patch-status-page.sql": true,
|
||||
"patch-proxy.sql": true,
|
||||
"patch-monitor-expiry-notification.sql": true,
|
||||
@ -61,6 +62,8 @@ class Database {
|
||||
"patch-add-clickable-status-page-link.sql": true,
|
||||
"patch-add-sqlserver-monitor.sql": true,
|
||||
"patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] },
|
||||
"patch-add-radius-monitor.sql": true,
|
||||
"patch-monitor-add-resend-interval.sql": true,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -147,6 +150,9 @@ class Database {
|
||||
await R.exec("PRAGMA cache_size = -12000");
|
||||
await R.exec("PRAGMA auto_vacuum = FULL");
|
||||
|
||||
// Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write
|
||||
await R.exec("PRAGMA busy_timeout = 5000");
|
||||
|
||||
// This ensures that an operating system crash or power failure will not corrupt the database.
|
||||
// FULL synchronous is very safe, but it is also slower.
|
||||
// Read more: https://sqlite.org/pragma.html#pragma_synchronous
|
||||
|
106
server/docker.js
Normal file
106
server/docker.js
Normal file
@ -0,0 +1,106 @@
|
||||
const axios = require("axios");
|
||||
const { R } = require("redbean-node");
|
||||
const version = require("../package.json").version;
|
||||
const https = require("https");
|
||||
|
||||
class DockerHost {
|
||||
/**
|
||||
* Save a docker host
|
||||
* @param {Object} dockerHost Docker host to save
|
||||
* @param {?number} dockerHostID ID of the docker host to update
|
||||
* @param {number} userID ID of the user who adds the docker host
|
||||
* @returns {Promise<Bean>}
|
||||
*/
|
||||
static async save(dockerHost, dockerHostID, userID) {
|
||||
let bean;
|
||||
|
||||
if (dockerHostID) {
|
||||
bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [ dockerHostID, userID ]);
|
||||
|
||||
if (!bean) {
|
||||
throw new Error("docker host not found");
|
||||
}
|
||||
|
||||
} else {
|
||||
bean = R.dispense("docker_host");
|
||||
}
|
||||
|
||||
bean.user_id = userID;
|
||||
bean.docker_daemon = dockerHost.dockerDaemon;
|
||||
bean.docker_type = dockerHost.dockerType;
|
||||
bean.name = dockerHost.name;
|
||||
|
||||
await R.store(bean);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a Docker host
|
||||
* @param {number} dockerHostID ID of the Docker host to delete
|
||||
* @param {number} userID ID of the user who created the Docker host
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
static async delete(dockerHostID, userID) {
|
||||
let bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [ dockerHostID, userID ]);
|
||||
|
||||
if (!bean) {
|
||||
throw new Error("docker host not found");
|
||||
}
|
||||
|
||||
// Delete removed proxy from monitors if exists
|
||||
await R.exec("UPDATE monitor SET docker_host = null WHERE docker_host = ?", [ dockerHostID ]);
|
||||
|
||||
await R.trash(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the amount of containers on the Docker host
|
||||
* @param {Object} dockerHost Docker host to check for
|
||||
* @returns {number} Total amount of containers on the host
|
||||
*/
|
||||
static async testDockerHost(dockerHost) {
|
||||
const options = {
|
||||
url: "/containers/json?all=true",
|
||||
headers: {
|
||||
"Accept": "*/*",
|
||||
"User-Agent": "Uptime-Kuma/" + version
|
||||
},
|
||||
httpsAgent: new https.Agent({
|
||||
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
|
||||
rejectUnauthorized: false,
|
||||
}),
|
||||
};
|
||||
|
||||
if (dockerHost.dockerType === "socket") {
|
||||
options.socketPath = dockerHost.dockerDaemon;
|
||||
} else if (dockerHost.dockerType === "tcp") {
|
||||
options.baseURL = dockerHost.dockerDaemon;
|
||||
}
|
||||
|
||||
let res = await axios.request(options);
|
||||
|
||||
if (Array.isArray(res.data)) {
|
||||
|
||||
if (res.data.length > 1) {
|
||||
|
||||
if ("ImageID" in res.data[0]) {
|
||||
return res.data.length;
|
||||
} else {
|
||||
throw new Error("Invalid Docker response, is it Docker really a daemon?");
|
||||
}
|
||||
|
||||
} else {
|
||||
return res.data.length;
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Error("Invalid Docker response, is it Docker really a daemon?");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DockerHost,
|
||||
};
|
19
server/model/docker_host.js
Normal file
19
server/model/docker_host.js
Normal file
@ -0,0 +1,19 @@
|
||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||
|
||||
class DockerHost extends BeanModel {
|
||||
/**
|
||||
* Returns an object that ready to parse to JSON
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id,
|
||||
userID: this.user_id,
|
||||
dockerDaemon: this.docker_daemon,
|
||||
dockerType: this.docker_type,
|
||||
name: this.name,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DockerHost;
|
@ -7,7 +7,7 @@ dayjs.extend(timezone);
|
||||
const axios = require("axios");
|
||||
const { Prometheus } = require("../prometheus");
|
||||
const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
|
||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, mqttAsync, setSetting, httpNtlm } = require("../util-server");
|
||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mqttAsync, setSetting, httpNtlm, radius } = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||
const { Notification } = require("../notification");
|
||||
@ -79,6 +79,7 @@ class Monitor extends BeanModel {
|
||||
type: this.type,
|
||||
interval: this.interval,
|
||||
retryInterval: this.retryInterval,
|
||||
resendInterval: this.resendInterval,
|
||||
keyword: this.keyword,
|
||||
expiryNotification: this.isEnabledExpiryNotification(),
|
||||
ignoreTls: this.getIgnoreTls(),
|
||||
@ -88,6 +89,9 @@ class Monitor extends BeanModel {
|
||||
dns_resolve_type: this.dns_resolve_type,
|
||||
dns_resolve_server: this.dns_resolve_server,
|
||||
dns_last_result: this.dns_last_result,
|
||||
pushToken: this.pushToken,
|
||||
docker_container: this.docker_container,
|
||||
docker_host: this.docker_host,
|
||||
proxyId: this.proxy_id,
|
||||
notificationIDList,
|
||||
tags: tags,
|
||||
@ -100,6 +104,11 @@ class Monitor extends BeanModel {
|
||||
authMethod: this.authMethod,
|
||||
authWorkstation: this.authWorkstation,
|
||||
authDomain: this.authDomain,
|
||||
radiusUsername: this.radiusUsername,
|
||||
radiusPassword: this.radiusPassword,
|
||||
radiusCalledStationId: this.radiusCalledStationId,
|
||||
radiusCallingStationId: this.radiusCallingStationId,
|
||||
radiusSecret: this.radiusSecret,
|
||||
};
|
||||
|
||||
if (includeSensitiveData) {
|
||||
@ -206,6 +215,7 @@ class Monitor extends BeanModel {
|
||||
bean.monitor_id = this.id;
|
||||
bean.time = R.isoDateTimeMillis(dayjs.utc());
|
||||
bean.status = DOWN;
|
||||
bean.downCount = previousBeat?.downCount || 0;
|
||||
|
||||
if (this.isUpsideDown()) {
|
||||
bean.status = flipStatus(bean.status);
|
||||
@ -468,6 +478,35 @@ class Monitor extends BeanModel {
|
||||
} else {
|
||||
throw new Error("Server not found on Steam");
|
||||
}
|
||||
} else if (this.type === "docker") {
|
||||
log.debug(`[${this.name}] Prepare Options for Axios`);
|
||||
|
||||
const dockerHost = await R.load("docker_host", this.docker_host);
|
||||
|
||||
const options = {
|
||||
url: `/containers/${this.docker_container}/json`,
|
||||
headers: {
|
||||
"Accept": "*/*",
|
||||
"User-Agent": "Uptime-Kuma/" + version,
|
||||
},
|
||||
httpsAgent: new https.Agent({
|
||||
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
|
||||
rejectUnauthorized: ! this.getIgnoreTls(),
|
||||
}),
|
||||
};
|
||||
|
||||
if (dockerHost._dockerType === "socket") {
|
||||
options.socketPath = dockerHost._dockerDaemon;
|
||||
} else if (dockerHost._dockerType === "tcp") {
|
||||
options.baseURL = dockerHost._dockerDaemon;
|
||||
}
|
||||
|
||||
log.debug(`[${this.name}] Axios Request`);
|
||||
let res = await axios.request(options);
|
||||
if (res.data.State.Running) {
|
||||
bean.status = UP;
|
||||
bean.msg = "";
|
||||
}
|
||||
} else if (this.type === "mqtt") {
|
||||
bean.msg = await mqttAsync(this.hostname, this.mqttTopic, this.mqttSuccessMessage, {
|
||||
port: this.port,
|
||||
@ -484,6 +523,38 @@ class Monitor extends BeanModel {
|
||||
bean.msg = "";
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
} else if (this.type === "postgres") {
|
||||
let startTime = dayjs().valueOf();
|
||||
|
||||
await postgresQuery(this.databaseConnectionString, this.databaseQuery);
|
||||
|
||||
bean.msg = "";
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
} else if (this.type === "radius") {
|
||||
let startTime = dayjs().valueOf();
|
||||
try {
|
||||
const resp = await radius(
|
||||
this.hostname,
|
||||
this.radiusUsername,
|
||||
this.radiusPassword,
|
||||
this.radiusCalledStationId,
|
||||
this.radiusCallingStationId,
|
||||
this.radiusSecret
|
||||
);
|
||||
if (resp.code) {
|
||||
bean.msg = resp.code;
|
||||
}
|
||||
bean.status = UP;
|
||||
} catch (error) {
|
||||
bean.status = DOWN;
|
||||
if (error.response?.code) {
|
||||
bean.msg = error.response.code;
|
||||
} else {
|
||||
bean.msg = error.message;
|
||||
}
|
||||
}
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
} else {
|
||||
bean.msg = "Unknown Monitor Type";
|
||||
bean.status = PENDING;
|
||||
@ -525,12 +596,27 @@ class Monitor extends BeanModel {
|
||||
log.debug("monitor", `[${this.name}] sendNotification`);
|
||||
await Monitor.sendNotification(isFirstBeat, this, bean);
|
||||
|
||||
// Reset down count
|
||||
bean.downCount = 0;
|
||||
|
||||
// Clear Status Page Cache
|
||||
log.debug("monitor", `[${this.name}] apicache clear`);
|
||||
apicache.clear();
|
||||
|
||||
} else {
|
||||
bean.important = false;
|
||||
|
||||
if (bean.status === DOWN && this.resendInterval > 0) {
|
||||
++bean.downCount;
|
||||
if (bean.downCount >= this.resendInterval) {
|
||||
// Send notification again, because we are still DOWN
|
||||
log.debug("monitor", `[${this.name}] sendNotification again: Down Count: ${bean.downCount} | Resend Interval: ${this.resendInterval}`);
|
||||
await Monitor.sendNotification(isFirstBeat, this, bean);
|
||||
|
||||
// Reset down count
|
||||
bean.downCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bean.status === UP) {
|
||||
@ -541,7 +627,7 @@ class Monitor extends BeanModel {
|
||||
}
|
||||
log.warn("monitor", `Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`);
|
||||
} else {
|
||||
log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`);
|
||||
log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type} | Down Count: ${bean.downCount} | Resend Interval: ${this.resendInterval}`);
|
||||
}
|
||||
|
||||
log.debug("monitor", `[${this.name}] Send to socket`);
|
||||
|
@ -12,9 +12,7 @@ const { default: axios } = require("axios");
|
||||
|
||||
// bark is an APN bridge that sends notifications to Apple devices.
|
||||
|
||||
const barkNotificationGroup = "UptimeKuma";
|
||||
const barkNotificationAvatar = "https://github.com/louislam/uptime-kuma/raw/master/public/icon.png";
|
||||
const barkNotificationSound = "telegraph";
|
||||
const successMessage = "Successes!";
|
||||
|
||||
class Bark extends NotificationProvider {
|
||||
@ -50,13 +48,23 @@ class Bark extends NotificationProvider {
|
||||
* @param {string} postUrl URL to append parameters to
|
||||
* @returns {string}
|
||||
*/
|
||||
appendAdditionalParameters(postUrl) {
|
||||
// grouping all our notifications
|
||||
postUrl += "?group=" + barkNotificationGroup;
|
||||
appendAdditionalParameters(notification, postUrl) {
|
||||
// set icon to uptime kuma icon, 11kb should be fine
|
||||
postUrl += "&icon=" + barkNotificationAvatar;
|
||||
// grouping all our notifications
|
||||
if (notification.barkGroup != null) {
|
||||
postUrl += "&group=" + notification.barkGroup;
|
||||
} else {
|
||||
// default name
|
||||
postUrl += "&group=" + "UptimeKuma";
|
||||
}
|
||||
// picked a sound, this should follow system's mute status when arrival
|
||||
postUrl += "&sound=" + barkNotificationSound;
|
||||
if (notification.barkSound != null) {
|
||||
postUrl += "&sound=" + notification.barkSound;
|
||||
} else {
|
||||
// default sound
|
||||
postUrl += "&sound=" + "telegraph";
|
||||
}
|
||||
return postUrl;
|
||||
}
|
||||
|
||||
|
35
server/notification-providers/goalert.js
Normal file
35
server/notification-providers/goalert.js
Normal file
@ -0,0 +1,35 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { UP } = require("../../src/util");
|
||||
|
||||
class GoAlert extends NotificationProvider {
|
||||
|
||||
name = "GoAlert";
|
||||
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
let okMsg = "Sent Successfully.";
|
||||
try {
|
||||
let closeAction = "close";
|
||||
let data = {
|
||||
summary: msg,
|
||||
};
|
||||
if (heartbeatJSON != null && heartbeatJSON["status"] === UP) {
|
||||
data["action"] = closeAction;
|
||||
}
|
||||
let headers = {
|
||||
"Content-Type": "multipart/form-data",
|
||||
};
|
||||
let config = {
|
||||
headers: headers
|
||||
};
|
||||
let resp = await axios.post(`${notification.goAlertBaseURL}/api/v2/generic/incoming?token=${notification.goAlertToken}`, data, config);
|
||||
return okMsg;
|
||||
|
||||
} catch (error) {
|
||||
let msg = (error.response.data) ? error.response.data : "Error without response";
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GoAlert;
|
38
server/notification-providers/home-assistant.js
Normal file
38
server/notification-providers/home-assistant.js
Normal file
@ -0,0 +1,38 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
|
||||
const defaultNotificationService = "notify";
|
||||
|
||||
class HomeAssistant extends NotificationProvider {
|
||||
name = "HomeAssistant";
|
||||
|
||||
async send(notification, message, monitor = null, heartbeat = null) {
|
||||
const notificationService = notification?.notificationService || defaultNotificationService;
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
`${notification.homeAssistantUrl}/api/services/notify/${notificationService}`,
|
||||
{
|
||||
title: "Uptime Kuma",
|
||||
message,
|
||||
...(notificationService !== "persistent_notification" && { data: {
|
||||
name: monitor?.name,
|
||||
status: heartbeat?.status,
|
||||
} }),
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${notification.longLivedAccessToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return "Sent Successfully.";
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HomeAssistant;
|
43
server/notification-providers/linenotify.js
Normal file
43
server/notification-providers/linenotify.js
Normal file
@ -0,0 +1,43 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const qs = require("qs");
|
||||
const { DOWN, UP } = require("../../src/util");
|
||||
|
||||
class LineNotify extends NotificationProvider {
|
||||
|
||||
name = "LineNotify";
|
||||
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
let okMsg = "Sent Successfully.";
|
||||
try {
|
||||
let lineAPIUrl = "https://notify-api.line.me/api/notify";
|
||||
let config = {
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Authorization": "Bearer " + notification.lineNotifyAccessToken
|
||||
}
|
||||
};
|
||||
if (heartbeatJSON == null) {
|
||||
let testMessage = {
|
||||
"message": msg,
|
||||
};
|
||||
await axios.post(lineAPIUrl, qs.stringify(testMessage), config);
|
||||
} else if (heartbeatJSON["status"] === DOWN) {
|
||||
let downMessage = {
|
||||
"message": "\n[🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||
};
|
||||
await axios.post(lineAPIUrl, qs.stringify(downMessage), config);
|
||||
} else if (heartbeatJSON["status"] === UP) {
|
||||
let upMessage = {
|
||||
"message": "\n[✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||
};
|
||||
await axios.post(lineAPIUrl, qs.stringify(upMessage), config);
|
||||
}
|
||||
return okMsg;
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LineNotify;
|
@ -12,7 +12,9 @@ const Feishu = require("./notification-providers/feishu");
|
||||
const GoogleChat = require("./notification-providers/google-chat");
|
||||
const Gorush = require("./notification-providers/gorush");
|
||||
const Gotify = require("./notification-providers/gotify");
|
||||
const HomeAssistant = require("./notification-providers/home-assistant");
|
||||
const Line = require("./notification-providers/line");
|
||||
const LineNotify = require("./notification-providers/linenotify");
|
||||
const LunaSea = require("./notification-providers/lunasea");
|
||||
const Matrix = require("./notification-providers/matrix");
|
||||
const Mattermost = require("./notification-providers/mattermost");
|
||||
@ -36,6 +38,7 @@ const TechulusPush = require("./notification-providers/techulus-push");
|
||||
const Telegram = require("./notification-providers/telegram");
|
||||
const Webhook = require("./notification-providers/webhook");
|
||||
const WeCom = require("./notification-providers/wecom");
|
||||
const GoAlert = require("./notification-providers/goalert");
|
||||
|
||||
class Notification {
|
||||
|
||||
@ -60,7 +63,9 @@ class Notification {
|
||||
new GoogleChat(),
|
||||
new Gorush(),
|
||||
new Gotify(),
|
||||
new HomeAssistant(),
|
||||
new Line(),
|
||||
new LineNotify(),
|
||||
new LunaSea(),
|
||||
new Matrix(),
|
||||
new Mattermost(),
|
||||
@ -84,6 +89,7 @@ class Notification {
|
||||
new Telegram(),
|
||||
new Webhook(),
|
||||
new WeCom(),
|
||||
new GoAlert(),
|
||||
];
|
||||
|
||||
for (let item of list) {
|
||||
|
@ -136,6 +136,7 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
|
||||
const heartbeat = await Monitor.getPreviousHeartbeat(requestedMonitorId);
|
||||
const state = overrideValue !== undefined ? overrideValue : heartbeat.status === 1;
|
||||
|
||||
badgeValues.label = label ? label : "";
|
||||
badgeValues.color = state ? upColor : downColor;
|
||||
badgeValues.message = label ?? state ? upLabel : downLabel;
|
||||
}
|
||||
|
@ -119,13 +119,14 @@ if (config.demoMode) {
|
||||
}
|
||||
|
||||
// Must be after io instantiation
|
||||
const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo, sendProxyList } = require("./client");
|
||||
const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo, sendProxyList, sendDockerHostList } = require("./client");
|
||||
const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler");
|
||||
const databaseSocketHandler = require("./socket-handlers/database-socket-handler");
|
||||
const TwoFA = require("./2fa");
|
||||
const StatusPage = require("./model/status_page");
|
||||
const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudflaredStop } = require("./socket-handlers/cloudflared-socket-handler");
|
||||
const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler");
|
||||
const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler");
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
@ -165,12 +166,20 @@ let needSetup = false;
|
||||
|
||||
// Entry Page
|
||||
app.get("/", async (request, response) => {
|
||||
log.debug("entry", `Request Domain: ${request.hostname}`);
|
||||
let hostname = request.hostname;
|
||||
if (await setting("trustProxy")) {
|
||||
const proxy = request.headers["x-forwarded-host"];
|
||||
if (proxy) {
|
||||
hostname = proxy;
|
||||
}
|
||||
}
|
||||
|
||||
if (request.hostname in StatusPage.domainMappingList) {
|
||||
log.debug("entry", `Request Domain: ${hostname}`);
|
||||
|
||||
if (hostname in StatusPage.domainMappingList) {
|
||||
log.debug("entry", "This is a status page domain");
|
||||
|
||||
let slug = StatusPage.domainMappingList[request.hostname];
|
||||
let slug = StatusPage.domainMappingList[hostname];
|
||||
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
|
||||
|
||||
} else if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) {
|
||||
@ -247,7 +256,9 @@ let needSetup = false;
|
||||
// ***************************
|
||||
|
||||
socket.on("loginByToken", async (token, callback) => {
|
||||
log.info("auth", `Login by token. IP=${getClientIp(socket)}`);
|
||||
const clientIP = await server.getClientIP(socket);
|
||||
|
||||
log.info("auth", `Login by token. IP=${clientIP}`);
|
||||
|
||||
try {
|
||||
let decoded = jwt.verify(token, jwtSecret);
|
||||
@ -263,14 +274,14 @@ let needSetup = false;
|
||||
afterLogin(socket, user);
|
||||
log.debug("auth", "afterLogin ok");
|
||||
|
||||
log.info("auth", `Successfully logged in user ${decoded.username}. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `Successfully logged in user ${decoded.username}. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
});
|
||||
} else {
|
||||
|
||||
log.info("auth", `Inactive or deleted user ${decoded.username}. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `Inactive or deleted user ${decoded.username}. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
@ -279,7 +290,7 @@ let needSetup = false;
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
log.error("auth", `Invalid token. IP=${getClientIp(socket)}`);
|
||||
log.error("auth", `Invalid token. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
@ -290,7 +301,9 @@ let needSetup = false;
|
||||
});
|
||||
|
||||
socket.on("login", async (data, callback) => {
|
||||
log.info("auth", `Login by username + password. IP=${getClientIp(socket)}`);
|
||||
const clientIP = await server.getClientIP(socket);
|
||||
|
||||
log.info("auth", `Login by username + password. IP=${clientIP}`);
|
||||
|
||||
// Checking
|
||||
if (typeof callback !== "function") {
|
||||
@ -303,7 +316,7 @@ let needSetup = false;
|
||||
|
||||
// Login Rate Limit
|
||||
if (! await loginRateLimiter.pass(callback)) {
|
||||
log.info("auth", `Too many failed requests for user ${data.username}. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `Too many failed requests for user ${data.username}. IP=${clientIP}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -313,7 +326,7 @@ let needSetup = false;
|
||||
if (user.twofa_status === 0) {
|
||||
afterLogin(socket, user);
|
||||
|
||||
log.info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `Successfully logged in user ${data.username}. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
@ -325,7 +338,7 @@ let needSetup = false;
|
||||
|
||||
if (user.twofa_status === 1 && !data.token) {
|
||||
|
||||
log.info("auth", `2FA token required for user ${data.username}. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `2FA token required for user ${data.username}. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
tokenRequired: true,
|
||||
@ -343,7 +356,7 @@ let needSetup = false;
|
||||
socket.userID,
|
||||
]);
|
||||
|
||||
log.info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `Successfully logged in user ${data.username}. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
@ -353,7 +366,7 @@ let needSetup = false;
|
||||
});
|
||||
} else {
|
||||
|
||||
log.warn("auth", `Invalid token provided for user ${data.username}. IP=${getClientIp(socket)}`);
|
||||
log.warn("auth", `Invalid token provided for user ${data.username}. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
@ -363,7 +376,7 @@ let needSetup = false;
|
||||
}
|
||||
} else {
|
||||
|
||||
log.warn("auth", `Incorrect username or password for user ${data.username}. IP=${getClientIp(socket)}`);
|
||||
log.warn("auth", `Incorrect username or password for user ${data.username}. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
@ -435,6 +448,8 @@ let needSetup = false;
|
||||
});
|
||||
|
||||
socket.on("save2FA", async (currentPassword, callback) => {
|
||||
const clientIP = await server.getClientIP(socket);
|
||||
|
||||
try {
|
||||
if (! await twoFaRateLimiter.pass(callback)) {
|
||||
return;
|
||||
@ -447,7 +462,7 @@ let needSetup = false;
|
||||
socket.userID,
|
||||
]);
|
||||
|
||||
log.info("auth", `Saved 2FA token. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `Saved 2FA token. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
@ -455,7 +470,7 @@ let needSetup = false;
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
log.error("auth", `Error changing 2FA token. IP=${getClientIp(socket)}`);
|
||||
log.error("auth", `Error changing 2FA token. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
@ -465,6 +480,8 @@ let needSetup = false;
|
||||
});
|
||||
|
||||
socket.on("disable2FA", async (currentPassword, callback) => {
|
||||
const clientIP = await server.getClientIP(socket);
|
||||
|
||||
try {
|
||||
if (! await twoFaRateLimiter.pass(callback)) {
|
||||
return;
|
||||
@ -474,7 +491,7 @@ let needSetup = false;
|
||||
await doubleCheckPassword(socket, currentPassword);
|
||||
await TwoFA.disable2FA(socket.userID);
|
||||
|
||||
log.info("auth", `Disabled 2FA token. IP=${getClientIp(socket)}`);
|
||||
log.info("auth", `Disabled 2FA token. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
@ -482,7 +499,7 @@ let needSetup = false;
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
log.error("auth", `Error disabling 2FA token. IP=${getClientIp(socket)}`);
|
||||
log.error("auth", `Error disabling 2FA token. IP=${clientIP}`);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
@ -653,6 +670,7 @@ let needSetup = false;
|
||||
bean.basic_auth_pass = monitor.basic_auth_pass;
|
||||
bean.interval = monitor.interval;
|
||||
bean.retryInterval = monitor.retryInterval;
|
||||
bean.resendInterval = monitor.resendInterval;
|
||||
bean.hostname = monitor.hostname;
|
||||
bean.maxretries = monitor.maxretries;
|
||||
bean.port = parseInt(monitor.port);
|
||||
@ -665,6 +683,8 @@ let needSetup = false;
|
||||
bean.dns_resolve_type = monitor.dns_resolve_type;
|
||||
bean.dns_resolve_server = monitor.dns_resolve_server;
|
||||
bean.pushToken = monitor.pushToken;
|
||||
bean.docker_container = monitor.docker_container;
|
||||
bean.docker_host = monitor.docker_host;
|
||||
bean.proxyId = Number.isInteger(monitor.proxyId) ? monitor.proxyId : null;
|
||||
bean.mqttUsername = monitor.mqttUsername;
|
||||
bean.mqttPassword = monitor.mqttPassword;
|
||||
@ -675,6 +695,11 @@ let needSetup = false;
|
||||
bean.authMethod = monitor.authMethod;
|
||||
bean.authWorkstation = monitor.authWorkstation;
|
||||
bean.authDomain = monitor.authDomain;
|
||||
bean.radiusUsername = monitor.radiusUsername;
|
||||
bean.radiusPassword = monitor.radiusPassword;
|
||||
bean.radiusCalledStationId = monitor.radiusCalledStationId;
|
||||
bean.radiusCallingStationId = monitor.radiusCallingStationId;
|
||||
bean.radiusSecret = monitor.radiusSecret;
|
||||
|
||||
await R.store(bean);
|
||||
|
||||
@ -1255,6 +1280,7 @@ let needSetup = false;
|
||||
authDomain: monitorListData[i].authDomain,
|
||||
interval: monitorListData[i].interval,
|
||||
retryInterval: retryInterval,
|
||||
resendInterval: monitorListData[i].resendInterval || 0,
|
||||
hostname: monitorListData[i].hostname,
|
||||
maxretries: monitorListData[i].maxretries,
|
||||
port: monitorListData[i].port,
|
||||
@ -1423,6 +1449,7 @@ let needSetup = false;
|
||||
cloudflaredSocketHandler(socket);
|
||||
databaseSocketHandler(socket);
|
||||
proxySocketHandler(socket);
|
||||
dockerSocketHandler(socket);
|
||||
|
||||
log.debug("server", "added all socket handlers");
|
||||
|
||||
@ -1527,6 +1554,7 @@ async function afterLogin(socket, user) {
|
||||
let monitorList = await server.sendMonitorList(socket);
|
||||
sendNotificationList(socket);
|
||||
sendProxyList(socket);
|
||||
sendDockerHostList(socket);
|
||||
|
||||
await sleep(500);
|
||||
|
||||
@ -1681,10 +1709,6 @@ async function shutdownFunction(signal) {
|
||||
await cloudflaredStop();
|
||||
}
|
||||
|
||||
function getClientIp(socket) {
|
||||
return socket.client.conn.remoteAddress.replace(/^.*:/, "");
|
||||
}
|
||||
|
||||
/** Final function called before application exits */
|
||||
function finalFunction() {
|
||||
log.info("server", "Graceful shutdown successful!");
|
||||
|
79
server/socket-handlers/docker-socket-handler.js
Normal file
79
server/socket-handlers/docker-socket-handler.js
Normal file
@ -0,0 +1,79 @@
|
||||
const { sendDockerHostList } = require("../client");
|
||||
const { checkLogin } = require("../util-server");
|
||||
const { DockerHost } = require("../docker");
|
||||
const { log } = require("../../src/util");
|
||||
|
||||
/**
|
||||
* Handlers for docker hosts
|
||||
* @param {Socket} socket Socket.io instance
|
||||
*/
|
||||
module.exports.dockerSocketHandler = (socket) => {
|
||||
socket.on("addDockerHost", async (dockerHost, dockerHostID, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
let dockerHostBean = await DockerHost.save(dockerHost, dockerHostID, socket.userID);
|
||||
await sendDockerHostList(socket);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Saved",
|
||||
id: dockerHostBean.id,
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("deleteDockerHost", async (dockerHostID, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
await DockerHost.delete(dockerHostID, socket.userID);
|
||||
await sendDockerHostList(socket);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Deleted",
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("testDockerHost", async (dockerHost, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
let amount = await DockerHost.testDockerHost(dockerHost);
|
||||
let msg;
|
||||
|
||||
if (amount > 1) {
|
||||
msg = "Connected Successfully. Amount of containers: " + amount;
|
||||
} else {
|
||||
msg = "Connected Successfully, but there are no containers?";
|
||||
}
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg,
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
log.error("docker", e);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
@ -202,7 +202,11 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||
relationBean.weight = monitorOrder++;
|
||||
relationBean.group_id = groupBean.id;
|
||||
relationBean.monitor_id = monitor.id;
|
||||
relationBean.send_url = monitor.sendUrl;
|
||||
|
||||
if (monitor.sendUrl !== undefined) {
|
||||
relationBean.send_url = monitor.sendUrl;
|
||||
}
|
||||
|
||||
await R.store(relationBean);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ const { log } = require("../src/util");
|
||||
const Database = require("./database");
|
||||
const util = require("util");
|
||||
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
|
||||
const { Settings } = require("./settings");
|
||||
|
||||
/**
|
||||
* `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue.
|
||||
@ -50,7 +51,6 @@ class UptimeKumaServer {
|
||||
|
||||
log.info("server", "Creating express and socket.io instance");
|
||||
this.app = express();
|
||||
|
||||
if (sslKey && sslCert) {
|
||||
log.info("server", "Server Type: HTTPS");
|
||||
this.httpServer = https.createServer({
|
||||
@ -129,6 +129,22 @@ class UptimeKumaServer {
|
||||
|
||||
errorLogStream.end();
|
||||
}
|
||||
|
||||
async getClientIP(socket) {
|
||||
let clientIP = socket.client.conn.remoteAddress;
|
||||
|
||||
if (clientIP === undefined) {
|
||||
clientIP = "";
|
||||
}
|
||||
|
||||
if (await Settings.get("trustProxy")) {
|
||||
return socket.client.conn.request.headers["x-forwarded-for"]
|
||||
|| socket.client.conn.request.headers["x-real-ip"]
|
||||
|| clientIP.replace(/^.*:/, "");
|
||||
} else {
|
||||
return clientIP.replace(/^.*:/, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@ -11,8 +11,16 @@ const mqtt = require("mqtt");
|
||||
const chroma = require("chroma-js");
|
||||
const { badgeConstants } = require("./config");
|
||||
const mssql = require("mssql");
|
||||
const { Client } = require("pg");
|
||||
const postgresConParse = require("pg-connection-string").parse;
|
||||
const { NtlmClient } = require("axios-ntlm");
|
||||
const { Settings } = require("./settings");
|
||||
const radiusClient = require("node-radius-client");
|
||||
const {
|
||||
dictionaries: {
|
||||
rfc2865: { file, attributes },
|
||||
},
|
||||
} = require("node-radius-utils");
|
||||
|
||||
// From ping-lite
|
||||
exports.WIN = /^win/.test(process.platform);
|
||||
@ -251,10 +259,67 @@ exports.mssqlQuery = function (connectionString, query) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a query on Postgres
|
||||
* @param {string} connectionString The database connection string
|
||||
* @param {string} query The query to validate the database with
|
||||
* @returns {Promise<(string[]|Object[]|Object)>}
|
||||
*/
|
||||
exports.postgresQuery = function (connectionString, query) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const config = postgresConParse(connectionString);
|
||||
|
||||
if (config.password === "") {
|
||||
// See https://github.com/brianc/node-postgres/issues/1927
|
||||
return reject(new Error("Password is undefined."));
|
||||
}
|
||||
|
||||
const client = new Client({ connectionString });
|
||||
|
||||
client.connect();
|
||||
|
||||
return client.query(query)
|
||||
.then(res => {
|
||||
resolve(res);
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err);
|
||||
})
|
||||
.finally(() => {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.radius = function (
|
||||
hostname,
|
||||
username,
|
||||
password,
|
||||
calledStationId,
|
||||
callingStationId,
|
||||
secret,
|
||||
) {
|
||||
const client = new radiusClient({
|
||||
host: hostname,
|
||||
dictionaries: [ file ],
|
||||
});
|
||||
|
||||
return client.accessRequest({
|
||||
secret: secret,
|
||||
attributes: [
|
||||
[ attributes.USER_NAME, username ],
|
||||
[ attributes.USER_PASSWORD, password ],
|
||||
[ attributes.CALLING_STATION_ID, callingStationId ],
|
||||
[ attributes.CALLED_STATION_ID, calledStationId ],
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve value of setting based on key
|
||||
* @param {string} key Key of setting to retrieve
|
||||
* @returns {Promise<any>} Value
|
||||
* @deprecated Use await Settings.get(key)
|
||||
*/
|
||||
exports.setting = async function (key) {
|
||||
return await Settings.get(key);
|
||||
|
177
src/components/DockerHostDialog.vue
Normal file
177
src/components/DockerHostDialog.vue
Normal file
@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<form @submit.prevent="submit">
|
||||
<div ref="modal" class="modal fade" tabindex="-1" data-bs-backdrop="static">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ $t("Setup Docker Host") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="docker-name" class="form-label">{{ $t("Friendly Name") }}</label>
|
||||
<input id="docker-name" v-model="dockerHost.name" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="docker-type" class="form-label">{{ $t("Connection Type") }}</label>
|
||||
<select id="docker-type" v-model="dockerHost.dockerType" class="form-select">
|
||||
<option v-for="type in connectionTypes" :key="type" :value="type">{{ $t(type) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="docker-daemon" class="form-label">{{ $t("Docker Daemon") }}</label>
|
||||
<input id="docker-daemon" v-model="dockerHost.dockerDaemon" type="text" class="form-control" required>
|
||||
|
||||
<div class="form-text">
|
||||
{{ $t("Examples") }}:
|
||||
<ul>
|
||||
<li>/var/run/docker.sock</li>
|
||||
<li>tcp://localhost:2375</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button v-if="id" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm">
|
||||
{{ $t("Delete") }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning" :disabled="processing" @click="test">
|
||||
{{ $t("Test") }}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="processing">
|
||||
<div v-if="processing" class="spinner-border spinner-border-sm me-1"></div>
|
||||
{{ $t("Save") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteDockerHost">
|
||||
{{ $t("deleteDockerHostMsg") }}
|
||||
</Confirm>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Modal } from "bootstrap";
|
||||
import Confirm from "./Confirm.vue";
|
||||
import { useToast } from "vue-toastification";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Confirm,
|
||||
},
|
||||
props: {},
|
||||
emits: [ "added" ],
|
||||
data() {
|
||||
return {
|
||||
model: null,
|
||||
processing: false,
|
||||
id: null,
|
||||
connectionTypes: [ "socket", "tcp" ],
|
||||
dockerHost: {
|
||||
name: "",
|
||||
dockerDaemon: "",
|
||||
dockerType: "",
|
||||
// Do not set default value here, please scroll to show()
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.modal = new Modal(this.$refs.modal);
|
||||
},
|
||||
methods: {
|
||||
|
||||
deleteConfirm() {
|
||||
this.modal.hide();
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
show(dockerHostID) {
|
||||
if (dockerHostID) {
|
||||
let found = false;
|
||||
|
||||
this.id = dockerHostID;
|
||||
|
||||
for (let n of this.$root.dockerHostList) {
|
||||
if (n.id === dockerHostID) {
|
||||
this.dockerHost = n;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
toast.error("Docker Host not found!");
|
||||
}
|
||||
|
||||
} else {
|
||||
this.id = null;
|
||||
this.dockerHost = {
|
||||
name: "",
|
||||
dockerType: "socket",
|
||||
dockerDaemon: "/var/run/docker.sock",
|
||||
};
|
||||
}
|
||||
|
||||
this.modal.show();
|
||||
},
|
||||
|
||||
submit() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("addDockerHost", this.dockerHost, this.id, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
|
||||
if (res.ok) {
|
||||
this.modal.hide();
|
||||
|
||||
// Emit added event, doesn't emit edit.
|
||||
if (! this.id) {
|
||||
this.$emit("added", res.id);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
test() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("testDockerHost", this.dockerHost, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
});
|
||||
},
|
||||
|
||||
deleteDockerHost() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("deleteDockerHost", this.id, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
|
||||
if (res.ok) {
|
||||
this.modal.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../assets/vars.scss";
|
||||
|
||||
.dark {
|
||||
.modal-dialog .form-text, .modal-dialog p {
|
||||
color: $dark-font-color;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -2,9 +2,6 @@
|
||||
<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>
|
||||
<div class="form-text">
|
||||
<p><span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}</p>
|
||||
</div>
|
||||
<i18n-t tag="div" keypath="wayToGetTeamsURL" class="form-text">
|
||||
<a
|
||||
href="https://github.com/Finb/Bark"
|
||||
@ -12,4 +9,45 @@
|
||||
>{{ $t("here") }}</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="Bark Group" class="form-label">{{ $t("Bark Group") }}</label>
|
||||
<input id="Bark Group" v-model="$parent.notification.barkGroup" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="Bark Sound" class="form-label">{{ $t("Bark Sound") }}</label>
|
||||
<select id="Bark Sound" v-model="$parent.notification.barkSound" class="form-select" required>
|
||||
<option value="alarm">alarm</option>
|
||||
<option value="anticipate">anticipate</option>
|
||||
<option value="bell">bell</option>
|
||||
<option value="birdsong">birdsong</option>
|
||||
<option value="bloom">bloom</option>
|
||||
<option value="calypso">calypso</option>
|
||||
<option value="chime">chime</option>
|
||||
<option value="choo">choo</option>
|
||||
<option value="descent">descent</option>
|
||||
<option value="electronic">electronic</option>
|
||||
<option value="fanfare">fanfare</option>
|
||||
<option value="glass">glass</option>
|
||||
<option value="gotosleep">gotosleep</option>
|
||||
<option value="healthnotification">healthnotification</option>
|
||||
<option value="horn">horn</option>
|
||||
<option value="ladder">ladder</option>
|
||||
<option value="mailsent">mailsent</option>
|
||||
<option value="minuet">minuet</option>
|
||||
<option value="multiwayinvitation">multiwayinvitation</option>
|
||||
<option value="newmail">newmail</option>
|
||||
<option value="newsflash">newsflash</option>
|
||||
<option value="noir">noir</option>
|
||||
<option value="paymentsuccess">paymentsuccess</option>
|
||||
<option value="shake">shake</option>
|
||||
<option value="sherwoodforest">sherwoodforest</option>
|
||||
<option value="silence">silence</option>
|
||||
<option value="spell">spell</option>
|
||||
<option value="suspense">suspense</option>
|
||||
<option value="telegraph">telegraph</option>
|
||||
<option value="tiptoes">tiptoes</option>
|
||||
<option value="typewriters">typewriters</option>
|
||||
<option value="update">update</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
|
30
src/components/notifications/GoAlert.vue
Normal file
30
src/components/notifications/GoAlert.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="goalert-base-url" class="form-label">{{ $t("Base URL") }}</label>
|
||||
<div class="input-group mb-3">
|
||||
<input id="goalert-base-url" v-model="$parent.notification.goAlertBaseURL" type="text" class="form-control" required>
|
||||
</div>
|
||||
<i18n-t tag="div" keypath="goAlertInfo" class="form-text">
|
||||
<a href="https://goalert.me" target="_blank">https://goalert.me</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="goalert-token" class="form-label">{{ $t("Token") }}</label>
|
||||
<HiddenInput id="goalert-token" v-model="$parent.notification.goAlertToken" autocomplete="one-time-code" :required="true"></HiddenInput>
|
||||
|
||||
<div class="form-text">
|
||||
{{ $t("goAlertIntegrationKeyInfo") }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
},
|
||||
};
|
||||
</script>
|
40
src/components/notifications/HomeAssistant.vue
Normal file
40
src/components/notifications/HomeAssistant.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="homeAssistantUrl" class="form-label">{{ $t("Home Assistant URL") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<input id="homeAssistantUrl" v-model="$parent.notification.homeAssistantUrl" type="url" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="longLivedAccessToken" class="form-label">{{ $t("Long-Lived Access Token") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<input id="longLivedAccessToken" v-model="$parent.notification.longLivedAccessToken" type="text" class="form-control" required>
|
||||
|
||||
<div class="form-text">
|
||||
<p>{{ $t("Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="notificationService" class="form-label">{{ $t("Notification Service") }}</label>
|
||||
<input id="notificationService" v-model="$parent.notification.notificationService" type="text" :placeholder="$t('default: notify all devices')" class="form-control">
|
||||
|
||||
<div class="form-text">
|
||||
<p>{{ $t("A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.") }}</p>
|
||||
<p>{{ $t("Automations can optionally be triggered in Home Assistant:") }}</p>
|
||||
<p>
|
||||
{{ $t("Trigger type:") }} <code>Event</code><br />
|
||||
{{ $t("Event type:") }} <code>call_service</code><br />
|
||||
{{ $t("Event data:") }}
|
||||
</p>
|
||||
<pre>domain: notify
|
||||
service: mobile_app_my_phone # change to your device name
|
||||
service_data:
|
||||
title: Uptime Kuma
|
||||
data:
|
||||
status: 0 # 0=down 1=up
|
||||
# name: Optional Uptime Kuma Monitor Name to filter by</pre>
|
||||
<p>
|
||||
{{ $t("Then choose an action, for example switch the scene to where an RGB light is red.") }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
9
src/components/notifications/LineNotify.vue
Normal file
9
src/components/notifications/LineNotify.vue
Normal file
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="line-notify-access-token" class="form-label">{{ $t("Access Token") }}</label>
|
||||
<input id="line-notify-access-token" v-model="$parent.notification.lineNotifyAccessToken" type="text" class="form-control" :required="true">
|
||||
</div>
|
||||
<i18n-t tag="div" keypath="wayToGetLineNotifyToken" class="form-text" style="margin-top: 8px;">
|
||||
<a href="https://notify-bot.line.me/" target="_blank">https://notify-bot.line.me/</a>
|
||||
</i18n-t>
|
||||
</template>
|
@ -10,7 +10,9 @@ import Feishu from "./Feishu.vue";
|
||||
import GoogleChat from "./GoogleChat.vue";
|
||||
import Gorush from "./Gorush.vue";
|
||||
import Gotify from "./Gotify.vue";
|
||||
import HomeAssistant from "./HomeAssistant.vue";
|
||||
import Line from "./Line.vue";
|
||||
import LineNotify from "./LineNotify.vue";
|
||||
import LunaSea from "./LunaSea.vue";
|
||||
import Matrix from "./Matrix.vue";
|
||||
import Mattermost from "./Mattermost.vue";
|
||||
@ -34,6 +36,7 @@ import TechulusPush from "./TechulusPush.vue";
|
||||
import Telegram from "./Telegram.vue";
|
||||
import Webhook from "./Webhook.vue";
|
||||
import WeCom from "./WeCom.vue";
|
||||
import GoAlert from "./GoAlert.vue";
|
||||
|
||||
/**
|
||||
* Manage all notification form.
|
||||
@ -53,7 +56,9 @@ const NotificationFormList = {
|
||||
"GoogleChat": GoogleChat,
|
||||
"gorush": Gorush,
|
||||
"gotify": Gotify,
|
||||
"HomeAssistant": HomeAssistant,
|
||||
"line": Line,
|
||||
"LineNotify": LineNotify,
|
||||
"lunasea": LunaSea,
|
||||
"matrix": Matrix,
|
||||
"mattermost": Mattermost,
|
||||
@ -77,6 +82,7 @@ const NotificationFormList = {
|
||||
"telegram": Telegram,
|
||||
"webhook": Webhook,
|
||||
"WeCom": WeCom,
|
||||
"GoAlert": GoAlert,
|
||||
};
|
||||
|
||||
export default NotificationFormList;
|
||||
|
48
src/components/settings/Docker.vue
Normal file
48
src/components/settings/Docker.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="dockerHost-list my-4">
|
||||
<p v-if="$root.dockerHostList.length === 0">
|
||||
{{ $t("Not available, please setup.") }}
|
||||
</p>
|
||||
|
||||
<ul class="list-group mb-3" style="border-radius: 1rem;">
|
||||
<li v-for="(dockerHost, index) in $root.dockerHostList" :key="index" class="list-group-item">
|
||||
{{ dockerHost.name }}<br>
|
||||
<a href="#" @click="$refs.dockerHostDialog.show(dockerHost.id)">{{ $t("Edit") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button class="btn btn-primary me-2" type="button" @click="$refs.dockerHostDialog.show()">
|
||||
{{ $t("Setup Docker Host") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DockerHostDialog ref="dockerHostDialog" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DockerHostDialog from "../../components/DockerHostDialog.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DockerHostDialog,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
|
||||
computed: {
|
||||
settings() {
|
||||
return this.$parent.$parent.$parent.settings;
|
||||
},
|
||||
saveSettings() {
|
||||
return this.$parent.$parent.$parent.saveSettings;
|
||||
},
|
||||
settingsLoaded() {
|
||||
return this.$parent.$parent.$parent.settingsLoaded;
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
@ -91,6 +91,51 @@
|
||||
{{ $t("For example: nginx, Apache and Traefik.") }} <br />
|
||||
{{ $t("Please read") }} <a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy</a>.
|
||||
</div>
|
||||
|
||||
<h4 class="my-4">{{ $t("HTTP Headers") }}</h4>
|
||||
<div class="my-3">
|
||||
<label class="form-label">
|
||||
{{ $t("Trust Proxy") }}
|
||||
</label>
|
||||
<div class="form-check">
|
||||
<input
|
||||
id="trustProxyYes"
|
||||
v-model="settings.trustProxy"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="trustProxyYes"
|
||||
:value="true"
|
||||
required
|
||||
/>
|
||||
<label class="form-check-label" for="trustProxyYes">
|
||||
{{ $t("Yes") }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input
|
||||
id="trustProxyNo"
|
||||
v-model="settings.trustProxy"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="flexRadioDefault"
|
||||
:value="false"
|
||||
required
|
||||
/>
|
||||
<label class="form-check-label" for="trustProxyNo">
|
||||
{{ $t("No") }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-text">
|
||||
{{ $t("trustProxyDescription") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button class="btn btn-primary" type="submit" @click="saveSettings()">
|
||||
{{ $t("Save") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -113,6 +158,12 @@ export default {
|
||||
settings() {
|
||||
return this.$parent.$parent.$parent.settings;
|
||||
},
|
||||
saveSettings() {
|
||||
return this.$parent.$parent.$parent.saveSettings;
|
||||
},
|
||||
settingsLoaded() {
|
||||
return this.$parent.$parent.$parent.settingsLoaded;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
|
@ -11,6 +11,7 @@ const languageList = {
|
||||
"es-ES": "Español",
|
||||
"eu": "Euskara",
|
||||
"fa": "Farsi",
|
||||
"pt-PT": "Português (Portugal)",
|
||||
"pt-BR": "Português (Brasileiro)",
|
||||
"fr-FR": "Français (France)",
|
||||
"hu": "Magyar",
|
||||
|
@ -380,7 +380,7 @@ export default {
|
||||
deleteProxyMsg: "Сигурни ли сте, че желаете да изтриете това прокси за всички монитори?",
|
||||
proxyDescription: "За да функционират трябва да бъдат зададени към монитор.",
|
||||
enableProxyDescription: "Това прокси няма да има ефект върху заявките за мониторинг, докато не бъде активирано. Може да контролирате временното деактивиране на проксито от всички монитори чрез статуса на активиране.",
|
||||
setAsDefaultProxyDescription: "Това проки ще бъде включено по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.",
|
||||
setAsDefaultProxyDescription: "Това прокси ще бъде включено по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.",
|
||||
"Certificate Chain": "Верига на сертификата",
|
||||
Valid: "Валиден",
|
||||
Invalid: "Невалиден",
|
||||
@ -536,4 +536,30 @@ export default {
|
||||
Domain: "Домейн",
|
||||
Workstation: "Работна станция",
|
||||
disableCloudflaredNoAuthMsg: "Тъй като сте в режим \"No Auth mode\", парола не се изисква.",
|
||||
wayToGetLineNotifyToken: "Може да получите токен код за достъп от {0}",
|
||||
resendEveryXTimes: "Изпращай повторно на всеки {0} пъти",
|
||||
resendDisabled: "Повторното изпращане е изключено",
|
||||
"Resend Notification if Down X times consequently": "Повторно изпращане на известие, ако е недостъпен X пъти последователно",
|
||||
"Bark Group": "Bark група",
|
||||
"Bark Sound": "Bark звук",
|
||||
"HTTP Headers": "HTTP хедъри",
|
||||
"Trust Proxy": "Trust Proxy",
|
||||
HomeAssistant: "Home Assistant",
|
||||
RadiusSecret: "Radius таен код",
|
||||
RadiusSecretDescription: "Споделен таен код между клиент и сървър",
|
||||
RadiusCalledStationId: "Повиквана станция ID",
|
||||
RadiusCalledStationIdDescription: "Идентификатор на повикваното устройство",
|
||||
RadiusCallingStationId: "Повикваща станция ID",
|
||||
RadiusCallingStationIdDescription: "Идентификатор на повикващото устройство",
|
||||
"Setup Docker Host": "Настройка на Docker хост",
|
||||
"Connection Type": "Тип свързване",
|
||||
"Docker Daemon": "Docker демон",
|
||||
deleteDockerHostMsg: "Сигурни ли сте, че желаете да изтриете този Docker хост за всички монитори?",
|
||||
socket: "Сокет",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker контейнер",
|
||||
"Container Name / ID": "Име на контейнер / ID",
|
||||
"Docker Host": "Docker хост",
|
||||
"Docker Hosts": "Docker хостове",
|
||||
trustProxyDescription: "Trust 'X-Forwarded-*' headers. Ако искате да получавате правилния IP адрес на клиента, а Uptime Kuma е зад системи като Nginx или Apache, трябва да разрешите тази опция.",
|
||||
};
|
||||
|
@ -2,18 +2,21 @@ export default {
|
||||
languageName: "Czech",
|
||||
checkEverySecond: "Kontrolovat každých {0} sekund",
|
||||
retryCheckEverySecond: "Opakovat každých {0} sekund",
|
||||
resendEveryXTimes: "Znovu zaslat {0}krát",
|
||||
resendDisabled: "Opakované zasílání je vypnuté",
|
||||
retriesDescription: "Maximální počet pokusů před označením služby jako nedostupné a odesláním oznámení",
|
||||
ignoreTLSError: "Ignorovat TLS/SSL chyby na HTTPS stránkách",
|
||||
upsideDownModeDescription: "Pomocí této možnosti změníte způsob vyhodnocování stavu. Pokud je služba dosažitelná, je NEDOSTUPNÁ.",
|
||||
maxRedirectDescription: "Maximální počet přesměrování, která se mají následovat. Nastavením hodnoty 0 zakážete přesměrování.",
|
||||
acceptedStatusCodesDescription: "Vyberte stavové kódy, které jsou považovány za úspěšnou odpověď.",
|
||||
passwordNotMatchMsg: "Hesla se neshodují",
|
||||
notificationDescription: "Pro zajištění funkčnosti oznámení je nutné je přiřadit dohledu.",
|
||||
notificationDescription: "Pro zajištění funkčnosti oznámení je nutné jej přiřadit dohledu.",
|
||||
keywordDescription: "Vyhledat klíčové slovo v prosté odpovědi HTML nebo JSON. Při hledání se rozlišuje velikost písmen.",
|
||||
pauseDashboardHome: "Pozastavit",
|
||||
deleteMonitorMsg: "Opravdu chcete odstranit tento dohled?",
|
||||
deleteNotificationMsg: "Opravdu chcete odstranit toto oznámení pro všechny dohledy?",
|
||||
resolverserverDescription: "Cloudflare je výchozí server. Resolver server můžete kdykoli změnit.",
|
||||
dnsPortDescription: "Port DNS serveru. Standardně běží na portu 53. V případě potřeby jej můžete kdykoli změnit.",
|
||||
resolverserverDescription: "Cloudflare je výchozí server. V případě potřeby můžete Resolver server kdykoli změnit.",
|
||||
rrtypeDescription: "Vyberte typ záznamu o prostředku, který chcete monitorovat",
|
||||
pauseMonitorMsg: "Opravdu chcete dohled pozastavit?",
|
||||
enableDefaultNotificationDescription: "Toto oznámení bude standardně aktivní pro nové dohledy. V případě potřeby můžete oznámení stále zakázat na úrovni jednotlivých dohledů.",
|
||||
@ -70,7 +73,8 @@ export default {
|
||||
Port: "Port",
|
||||
"Heartbeat Interval": "Heartbeat interval",
|
||||
Retries: "Počet pokusů",
|
||||
"Heartbeat Retry Interval": "Interval opakování prezenčního signálu",
|
||||
"Heartbeat Retry Interval": "Interval opakování heartbeatu",
|
||||
"Resend Notification if Down X times consequently": "Znovu zaslat oznámení, pokud je služba nedostupná Xkrát za sebou",
|
||||
Advanced: "Rozšířené",
|
||||
"Upside Down Mode": "Inverzní režim",
|
||||
"Max. Redirects": "Max. Přesměrování",
|
||||
@ -195,7 +199,7 @@ export default {
|
||||
"Chat ID": "ID chatu",
|
||||
supportTelegramChatID: "Podpora přímého chatu / skupiny / ID chatu kanálu",
|
||||
wayToGetTelegramChatID: "ID chatu můžete získat tak, že robotovi zašlete zprávu a přejdete na tuto adresu URL, kde zobrazíte chat_id:",
|
||||
"YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE",
|
||||
"YOUR BOT TOKEN HERE": "SEM ZADEJTE TOKEN VAŠEHO CHATBOTA",
|
||||
chatIDNotFound: "ID chatu nebylo nalezeno; nejprve tomuto robotovi zašlete zprávu",
|
||||
webhook: "Webhook",
|
||||
"Post URL": "URL adresa příspěvku",
|
||||
@ -241,6 +245,7 @@ export default {
|
||||
"rocket.chat": "Rocket.Chat",
|
||||
pushover: "Pushover",
|
||||
pushy: "Pushy",
|
||||
PushByTechulus: "Push by Techulus",
|
||||
octopush: "Octopush",
|
||||
promosms: "PromoSMS",
|
||||
clicksendsms: "ClickSend SMS",
|
||||
@ -301,15 +306,19 @@ export default {
|
||||
Body: "Tělo",
|
||||
Headers: "Hlavičky",
|
||||
PushUrl: "Push URL",
|
||||
HeadersInvalidFormat: "The request headers are not valid JSON: ",
|
||||
BodyInvalidFormat: "The request body is not valid JSON: ",
|
||||
HeadersInvalidFormat: "Hlaviča žádosti není platný JSON: ",
|
||||
BodyInvalidFormat: "Text žádosti není platný JSON: ",
|
||||
"Monitor History": "Historie dohledu",
|
||||
clearDataOlderThan: "Historie dohledu bude uchovávána po dobu {0} dní.",
|
||||
PasswordsDoNotMatch: "Hesla se neshodují.",
|
||||
records: "záznamů",
|
||||
"One record": "Jeden záznam",
|
||||
steamApiKeyDescription: "For monitoring a Steam Game Server you need a Steam Web-API key. You can register your API key here: ",
|
||||
steamApiKeyDescription: "Pro monitorování Steam Game Servere je nutné zadat Steam Web-API klíč. Svůj API klíč získáte na následující stránce: ",
|
||||
"Current User": "Aktuálně přihlášený uživatel",
|
||||
topic: "Topic",
|
||||
topicExplanation: "MQTT topic, který chcete sledovat",
|
||||
successMessage: "Zpráva o úspěchu",
|
||||
successMessageExplanation: "MQTT zpráva považovaná za úspěšnou",
|
||||
recent: "Poslední",
|
||||
Done: "Hotovo",
|
||||
Info: "Informace",
|
||||
@ -327,6 +336,8 @@ export default {
|
||||
info: "informace",
|
||||
warning: "upozornění",
|
||||
danger: "riziko",
|
||||
error: "chyba",
|
||||
critical: "kritické",
|
||||
primary: "primární",
|
||||
light: "světlý",
|
||||
dark: "tmavý",
|
||||
@ -355,13 +366,214 @@ export default {
|
||||
serwersmsPhoneNumber: "Telefonní číslo",
|
||||
serwersmsSenderName: "Odesílatel SMS (registrováno prostřednictvím zákaznického portálu)",
|
||||
"stackfield": "Stackfield",
|
||||
Customize: "Přizpůsobit",
|
||||
"Custom Footer": "Vlastní patička",
|
||||
"Custom CSS": "Vlastní CSS",
|
||||
smtpDkimSettings: "Nastavení DKIM",
|
||||
smtpDkimDesc: "Informace o použití naleznete v {0} Nodemailer DKIM.",
|
||||
documentation: "dokumentaci",
|
||||
smtpDkimDomain: "Název domény",
|
||||
smtpDkimKeySelector: "Selector klíče",
|
||||
smtpDkimKeySelector: "Selektor klíče",
|
||||
smtpDkimPrivateKey: "Privátní klíč",
|
||||
smtpDkimHashAlgo: "Hashovací algoritmus (volitelné)",
|
||||
smtpDkimheaderFieldNames: "Podepisovat tyto hlavičky (volitelné)",
|
||||
smtpDkimskipFields: "Nepodepisovat tyto hlavičky (volitelné)",
|
||||
wayToGetPagerDutyKey: "Získat jej můžete v sekci Service -> Service Directory -> (vyberte službu) -> Integrations -> Add integration. Následně vyhledejte \"Events API V2\". Více informace naleznete na adrese {0}",
|
||||
"Integration Key": "Integration Key",
|
||||
"Integration URL": "Integration URL",
|
||||
"Auto resolve or acknowledged": "Auto resolve or acknowledged",
|
||||
"do nothing": "do nothing",
|
||||
"auto acknowledged": "auto acknowledged",
|
||||
"auto resolve": "auto resolve",
|
||||
gorush: "Gorush",
|
||||
alerta: "Alerta",
|
||||
alertaApiEndpoint: "API Endpoint",
|
||||
alertaEnvironment: "Prostředí",
|
||||
alertaApiKey: "API Key",
|
||||
alertaAlertState: "Stav upozornění",
|
||||
alertaRecoverState: "Stav obnovení",
|
||||
deleteStatusPageMsg: "Opravdu chcete odstranit tuto stavovou stránku?",
|
||||
Proxies: "Proxy",
|
||||
default: "Výchozí",
|
||||
enabled: "Zapnuto",
|
||||
setAsDefault: "Nastavit jako výchozí",
|
||||
deleteProxyMsg: "Opravdu chcete odstranit tuto proxy ze všech dohledů?",
|
||||
proxyDescription: "Pro zajištění funkčnosti musí být proxy přiřazena dohledům.",
|
||||
enableProxyDescription: "Tato proxy neovlivní žádosti dohledu do doby, než ji aktivujete. Změnou tohoto nastavení dočasně zakážete použití proxy ve všech dohledech.",
|
||||
setAsDefaultProxyDescription: "Tato proxy se použije pro všechny nové dohledy. V případě potřeby můžete její využívání zakázat v konkrétním dohledu.",
|
||||
"Certificate Chain": "Řetězec certifikátu",
|
||||
Valid: "Platný",
|
||||
Invalid: "Neplatný",
|
||||
AccessKeyId: "AccessKey ID",
|
||||
SecretAccessKey: "AccessKey Secret",
|
||||
PhoneNumbers: "PhoneNumbers",
|
||||
TemplateCode: "TemplateCode",
|
||||
SignName: "SignName",
|
||||
"Sms template must contain parameters: ": "Sms template must contain parameters: ",
|
||||
"Bark Endpoint": "Bark Endpoint",
|
||||
"Bark Group": "Bark Group",
|
||||
"Bark Sound": "Bark Sound",
|
||||
WebHookUrl: "WebHookUrl",
|
||||
SecretKey: "SecretKey",
|
||||
"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",
|
||||
Topic: "Topic",
|
||||
"WeCom Bot Key": "WeCom Bot Key",
|
||||
"Setup Proxy": "Setup Proxy",
|
||||
"Proxy Protocol": "Proxy Protocol",
|
||||
"Proxy Server": "Proxy Server",
|
||||
"Proxy server has authentication": "Proxy server vyžaduje ověření",
|
||||
User: "Uživatel",
|
||||
Installed: "Nainstalováno",
|
||||
"Not installed": "Nenainstalováno",
|
||||
Running: "Běží",
|
||||
"Not running": "Neběží",
|
||||
"Remove Token": "Odstranit token",
|
||||
Start: "Spustit",
|
||||
Stop: "Zastavit",
|
||||
"Uptime Kuma": "Uptime Kuma",
|
||||
"Add New Status Page": "Přidat novou stavovou stránku",
|
||||
Slug: "Slug",
|
||||
"Accept characters:": "Přípustné znaky:",
|
||||
startOrEndWithOnly: "Počáteční a koncový znak může být pouze {0}",
|
||||
"No consecutive dashes": "Nesmí se opakovat pomlčky",
|
||||
Next: "Další",
|
||||
"The slug is already taken. Please choose another slug.": "Slug s tímto názvem již existuje. Prosím, zadejte jiný název.",
|
||||
"No Proxy": "Žádná proxy",
|
||||
Authentication: "Ověření",
|
||||
"HTTP Basic Auth": "HTTP Basic ověření",
|
||||
"New Status Page": "Nová stavová stránka",
|
||||
"Page Not Found": "Stránka nenalezena",
|
||||
"Reverse Proxy": "Reverzní proxy",
|
||||
Backup: "Záloha",
|
||||
About: "O programu",
|
||||
wayToGetCloudflaredURL: "(Stáhnout cloudflared z {0})",
|
||||
cloudflareWebsite: "Webová stránka Cloudflare",
|
||||
"Message:": "Zpráva:",
|
||||
"Don't know how to get the token? Please read the guide:": "Nevíte jak získat? Prosím, přečtěte si tuto příručku:",
|
||||
"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.": "Stávající připojení mohlo být ztraceno, pokud jste připojeni prostřednictvím Cloudflare tunelu. Opravdu jej chcete zastavit? Pro potvrzení zadejte své současné heslo.",
|
||||
"HTTP Headers": "HTTP hlavičky",
|
||||
"Trust Proxy": "Důvěryhodná proxy",
|
||||
"Other Software": "Jiný software",
|
||||
"For example: nginx, Apache and Traefik.": "Například nginx, Apache nebo Traefik.",
|
||||
"Please read": "Prosím, přečtěte si informace na adrese",
|
||||
"Subject:": "Předmět:",
|
||||
"Valid To:": "Platnost do:",
|
||||
"Days Remaining:": "Počet zbývajících dní:",
|
||||
"Issuer:": "Vydavatel:",
|
||||
"Fingerprint:": "Otisk:",
|
||||
"No status pages": "Žádná stavová stránka",
|
||||
"Domain Name Expiry Notification": "Oznámení na blížící se konec platnosti doménového jména",
|
||||
Proxy: "Proxy",
|
||||
"Date Created": "Datum vytvoření",
|
||||
HomeAssistant: "Home Assistant",
|
||||
onebotHttpAddress: "OneBot HTTP adresa",
|
||||
onebotMessageType: "Typ OneBot zprávy",
|
||||
onebotGroupMessage: "Skupinová",
|
||||
onebotPrivateMessage: "Soukromá",
|
||||
onebotUserOrGroupId: "ID skupiny/uživatele",
|
||||
onebotSafetyTips: "Z důvodu bezpečnosti je nutné zadat přístupový token",
|
||||
"PushDeer Key": "PushDeer klíč",
|
||||
"Footer Text": "Text v patičce",
|
||||
"Show Powered By": "Zobrazit \"Zajišťuje\"",
|
||||
"Domain Names": "Názvy domén",
|
||||
signedInDisp: "Přihlášen jako {0}",
|
||||
signedInDispDisabled: "Ověření je vypnuté.",
|
||||
RadiusSecret: "Radius Secret",
|
||||
RadiusSecretDescription: "Sdílený tajný klíč mezi klientem a serverem",
|
||||
RadiusCalledStationId: "ID volaného zařízení",
|
||||
RadiusCalledStationIdDescription: "Identifikátor volaného zařízení",
|
||||
RadiusCallingStationId: "ID volajícího zařízení",
|
||||
RadiusCallingStationIdDescription: "Identifikátor volajícího zařízení",
|
||||
"Certificate Expiry Notification": "Oznámení na blížící se konec platnosti certifikátu",
|
||||
"API Username": "API Username",
|
||||
"API Key": "API Key",
|
||||
"Recipient Number": "Číslo příjemce",
|
||||
"From Name/Number": "Jméno/číslo odesílatele",
|
||||
"Leave blank to use a shared sender number.": "Ponechte prázdné, pokud chcete použít číslo sdíleného příjemce.",
|
||||
"Octopush API Version": "Octopush API verze",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
endpoint: "endpoint",
|
||||
octopushAPIKey: "\"API key\" ze sekce HTTP API credentials na nástěnce",
|
||||
octopushLogin: "\"Login\" ze sekce HTTP API credentials na nástěnce",
|
||||
promosmsLogin: "API Login Name",
|
||||
promosmsPassword: "API Password",
|
||||
"pushoversounds pushover": "Pushover (výchozí)",
|
||||
"pushoversounds bike": "Bike",
|
||||
"pushoversounds bugle": "Bugle",
|
||||
"pushoversounds cashregister": "Cash Register",
|
||||
"pushoversounds classical": "Classical",
|
||||
"pushoversounds cosmic": "Cosmic",
|
||||
"pushoversounds falling": "Falling",
|
||||
"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 (dlouhý)",
|
||||
"pushoversounds climb": "Climb (dlouhý)",
|
||||
"pushoversounds persistent": "Persistent (dlouhý)",
|
||||
"pushoversounds echo": "Pushover Echo (dlouhý)",
|
||||
"pushoversounds updown": "Up Down (dlouhý)",
|
||||
"pushoversounds vibrate": "Pouze vibrace",
|
||||
"pushoversounds none": "Žádný (ticho)",
|
||||
pushyAPIKey: "Secret API Key",
|
||||
pushyToken: "Token zařízení",
|
||||
"Show update if available": "Zobrazit aktualizace, pokud jsou k dispozici",
|
||||
"Also check beta release": "Kontrolovat také dostupnost beta verzí",
|
||||
"Using a Reverse Proxy?": "Používáte reverzní proxy??",
|
||||
"Check how to config it for WebSocket": "Zjistěte, jak ji nakonfigurovat pro WebSockety",
|
||||
"Steam Game Server": "Steam Game Server",
|
||||
"Most likely causes:": "Nejčastější důvody:",
|
||||
"The resource is no longer available.": "Zdroj již není k dispozici.",
|
||||
"There might be a typing error in the address.": "Při zadávání adresy jste udělali chybu.",
|
||||
"What you can try:": "Co můžete vyzkoušet:",
|
||||
"Retype the address.": "Znovu zadat adresu.",
|
||||
"Go back to the previous page.": "Vrátit se na předchozí stránku.",
|
||||
"Coming Soon": "Připravujeme",
|
||||
wayToGetClickSendSMSToken: "API Username a API Key získáte na adrese {0} .",
|
||||
"Connection String": "Connection String",
|
||||
Query: "Dotaz",
|
||||
settingsCertificateExpiry: "Platnost TLS certifikátu",
|
||||
certificationExpiryDescription: "Aktivovat oznámení nad HTTPS dohledy, pokud platnost TSL certifikátu vyprší za:",
|
||||
"Setup Docker Host": "Nastavit Docker hostitele",
|
||||
"Connection Type": "Typ připojení",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
deleteDockerHostMsg: "Opravdu chcete odstranit tohoto docker hostitele ze všech dohledů?",
|
||||
socket: "Socket",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker kontejner",
|
||||
"Container Name / ID": "ID / název kontejneru",
|
||||
"Docker Host": "Docker hostitel",
|
||||
"Docker Hosts": "Docker hostitelé",
|
||||
"ntfy Topic": "ntfy Topic",
|
||||
"Domain": "Doména",
|
||||
"Workstation": "Pracovní stanice",
|
||||
disableCloudflaredNoAuthMsg: "Používáte režim bez ověření, heslo není vyžadováno.",
|
||||
trustProxyDescription: "Důvěřovat 'X-Forwarded-*' hlavičkám. Pokud chcete získat správnou IP adresu klientů a vaše instance Uptime Kuma je schována za Nginx nebo Apache, měli byste tuto možnost zapnout.",
|
||||
wayToGetLineNotifyToken: "Přístupový token můžete získat na adrese {0}",
|
||||
Examples: "Příklady",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "Dlouhodobý přístupový 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. ": "Pro vytvoření dlouhodobého přístupový tokenu klikněte na název svého profilu (v levém dolním rohu) a následně v dolní části stránky klikněte na tlačítko Create Token. ",
|
||||
"Notification Service": "Oznamovací služba",
|
||||
"default: notify all devices": "výchozí: upozornit všechny zařízení",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Seznam dostupných oznamovacích služeb naleznete v Home Assistant v sekci \"Developer Tools > Services\", kde vyhledejte \"notification\" pro zjištění názvu zařízení.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Automatizaci můžete volitelně aktivovat prostřednictvím Home Assistant:",
|
||||
"Trigger type:": "Typ podmínky spuštění:",
|
||||
"Event type:": "Typ události:",
|
||||
"Event data:": "Data události:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Následně vyberte akci, například přepnutí scény z RGB světla na červenou.",
|
||||
"Frontend Version": "Verze frontendu",
|
||||
"Frontend Version do not match backend version!": "Verze frontendu neodpovídá verzi backendu!",
|
||||
};
|
||||
|
@ -165,7 +165,10 @@ export default {
|
||||
Pink: "Pink",
|
||||
"Search...": "Suchen...",
|
||||
"Heartbeat Retry Interval": "Überprüfungsintervall",
|
||||
"Resend Notification if Down X times consequently": "Benachrichtigung erneut senden, wenn Inaktiv X mal hintereinander",
|
||||
retryCheckEverySecond: "Alle {0} Sekunden neu versuchen",
|
||||
resendEveryXTimes: "Erneut versenden alle {0} mal",
|
||||
resendDisabled: "Erneut versenden deaktiviert",
|
||||
"Import Backup": "Backup importieren",
|
||||
"Export Backup": "Backup exportieren",
|
||||
"Avg. Ping": "Durchschn. Ping",
|
||||
@ -455,4 +458,122 @@ export default {
|
||||
"Domain Names": "Domainnamen",
|
||||
signedInDisp: "Angemeldet als {0}",
|
||||
signedInDispDisabled: "Authentifizierung deaktiviert.",
|
||||
dnsPortDescription: "DNS server port. Standard ist 53. Der Port kann jederzeit geändert werden.",
|
||||
topic: "Thema",
|
||||
topicExplanation: "MQTT Thema für den monitor",
|
||||
successMessage: "Erfolgsnachricht",
|
||||
successMessageExplanation: "MQTT Nachricht, die als Erfolg angesehen wird",
|
||||
error: "Fehler",
|
||||
critical: "kritisch",
|
||||
wayToGetPagerDutyKey: "Dieser kann unter Service -> Service Directory -> (Select a service) -> Integrations -> Add integration gefunden werden. Hier muss nach \"Events API V2\" gesucht werden. Mehr informationen {0}",
|
||||
"Integration Key": "Schlüssel der Integration",
|
||||
"Integration URL": "URL der Integration",
|
||||
"Auto resolve or acknowledged": "Automatisch lösen oder bestätigen",
|
||||
"do nothing": "nichts tun",
|
||||
"auto acknowledged": "automatisch bestätigen",
|
||||
"auto resolve": "automatisch lösen",
|
||||
"Bark Group": "Bark Gruppe",
|
||||
"Bark Sound": "Bark Klang",
|
||||
"HTTP Headers": "HTTP Kopfzeilen",
|
||||
"Trust Proxy": "Vertrauenswürdiger Proxy",
|
||||
Proxy: "Proxy",
|
||||
HomeAssistant: "Home Assistant",
|
||||
onebotHttpAddress: "OneBot HTTP Adresse",
|
||||
onebotMessageType: "OneBot Nachrichtentyp",
|
||||
onebotGroupMessage: "Gruppe",
|
||||
onebotPrivateMessage: "Privat",
|
||||
onebotUserOrGroupId: "Gruppe/Nutzer ID",
|
||||
onebotSafetyTips: "Zur Sicherheit ein access token setzen",
|
||||
"PushDeer Key": "PushDeer Schlüssel",
|
||||
RadiusSecret: "Radius Geheimnis",
|
||||
RadiusSecretDescription: "Geteiltes Geheimnis zwischen Client und Server",
|
||||
RadiusCalledStationId: "ID der angesprochenen Station",
|
||||
RadiusCalledStationIdDescription: "Identifikation des angesprochenen Geräts",
|
||||
RadiusCallingStationId: "ID der ansprechenden Station",
|
||||
RadiusCallingStationIdDescription: "Identifikation des ansprechenden Geräts",
|
||||
"Certificate Expiry Notification": "Benachrichtigung ablaufendes Zertifikat",
|
||||
"API Username": "API Nutzername",
|
||||
"API Key": "API Schlüssel",
|
||||
"Recipient Number": "Empfängernummer",
|
||||
"From Name/Number": "Von Name/Nummer",
|
||||
"Leave blank to use a shared sender number.": "Leer lassen um eine geteilte Sendernummer zu nutzen.",
|
||||
"Octopush API Version": "Octopush API Version",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
endpoint: "Endpunkt",
|
||||
octopushAPIKey: "\"API Schlüssel\" der HTTP API Zugangsdaten im control panel",
|
||||
octopushLogin: "\"Login\" der HTTP API Zugangsdaten im control panel",
|
||||
promosmsLogin: "API Login Name",
|
||||
promosmsPassword: "API Password",
|
||||
"pushoversounds pushover": "Pushover (Standard)",
|
||||
"pushoversounds bike": "Fahrrad",
|
||||
"pushoversounds bugle": "Signalhorn",
|
||||
"pushoversounds cashregister": "Kasse",
|
||||
"pushoversounds classical": "Klassisch",
|
||||
"pushoversounds cosmic": "Kosmisch",
|
||||
"pushoversounds falling": "Abfallend",
|
||||
"pushoversounds gamelan": "Gamelan",
|
||||
"pushoversounds incoming": "Eingang",
|
||||
"pushoversounds intermission": "Pause",
|
||||
"pushoversounds magic": "Magisch",
|
||||
"pushoversounds mechanical": "Mechanisch",
|
||||
"pushoversounds pianobar": "Piano Bar",
|
||||
"pushoversounds siren": "Sirene",
|
||||
"pushoversounds spacealarm": "Space Alarm",
|
||||
"pushoversounds tugboat": "Schlepper Horn",
|
||||
"pushoversounds alien": "Außerirdisch (lang)",
|
||||
"pushoversounds climb": "Ansteigende (lang)",
|
||||
"pushoversounds persistent": "Hartnäckig (lang)",
|
||||
"pushoversounds echo": "Pushover Echo (lang)",
|
||||
"pushoversounds updown": "Auf und Ab (lang)",
|
||||
"pushoversounds vibrate": "Nur vibrieren",
|
||||
"pushoversounds none": "Nichts (Stille)",
|
||||
pushyAPIKey: "Geheimer API Schlüssel",
|
||||
pushyToken: "Gerätetoken",
|
||||
"Show update if available": "Verfügbare Updates anzeigen",
|
||||
"Also check beta release": "Auch nach beta Versionen schauen",
|
||||
"Using a Reverse Proxy?": "Wird ein Reverse Proxy genutzt?",
|
||||
"Check how to config it for WebSocket": "Prüfen, wie er für die Nutzung mit WebSocket konfiguriert wird",
|
||||
"Steam Game Server": "Steam Game Server",
|
||||
"Most likely causes:": "Wahrscheinliche Ursachen:",
|
||||
"The resource is no longer available.": "Die Quelle ist nicht mehr verfügbar.",
|
||||
"There might be a typing error in the address.": "Es gibt einen Tippfehler in der Adresse.",
|
||||
"What you can try:": "Was du versuchen kannst:",
|
||||
"Retype the address.": "Schreibe die Adresse erneut.",
|
||||
"Go back to the previous page.": "Gehe zur vorigen Seite.",
|
||||
"Coming Soon": "Kommt bald",
|
||||
wayToGetClickSendSMSToken: "Du kannst einen API Nutzernamen und Schlüssel unter {0} erhalten.",
|
||||
"Connection String": "Verbindungstext",
|
||||
Query: "Abfrage",
|
||||
settingsCertificateExpiry: "TLS Zertifikatsablauf",
|
||||
certificationExpiryDescription: "HTTPS Monitore senden eine Benachrichtigung, wenn das Zertifikat abläuft in:",
|
||||
"Setup Docker Host": "Docker Host einrichten",
|
||||
"Connection Type": "Verbindungstyp",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
deleteDockerHostMsg: "Bist du sicher diesen docker host für alle Monitore zu löschen?",
|
||||
socket: "Socket",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker Container",
|
||||
"Container Name / ID": "Container Name / ID",
|
||||
"Docker Host": "Docker Host",
|
||||
"Docker Hosts": "Docker Hosts",
|
||||
"ntfy Topic": "ntfy Thema",
|
||||
Domain: "Domain",
|
||||
Workstation: "Workstation",
|
||||
disableCloudflaredNoAuthMsg: "Du bist im nicht-authentifizieren modus, ein Passwort wird nicht benötigt.",
|
||||
trustProxyDescription: "Vertraue 'X-Forwarded-*' headern. Wenn man die richtige client IP haben möchte und Uptime Kuma hinter einem Proxy wie Nginx or Apache läuft, wollte dies aktiviert werden.",
|
||||
wayToGetLineNotifyToken: "Du kannst hier ein Token erhalten: {0}",
|
||||
Examples: "Beispiele",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "Lange gültiges 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. ": "Lange gültige Access Token können durch klicken auf den Profilnamen (unten links) und dann einen Klick auf Create Token am Ende erstellt werden. ",
|
||||
"Notification Service": "Benachrichtigungsdienst",
|
||||
"default: notify all devices": "standard: Alle Geräte benachrichtigen",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Eine Liste der Benachrichtigungsdiesnte kann im Home Assistant unter \"Developer Tools > Services\" gefunden werden, wnen man nach \"notification\" sucht um den Geräte-/Telefonnamen zu finden.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Automatisierungen können optional im Home Assistant ausgelöst werden:",
|
||||
"Trigger type:": "Auslösertyp:",
|
||||
"Event type:": "Ereignistyp:",
|
||||
"Event data:": "Ereignis daten:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.",
|
||||
"Frontend Version": "Frontend Version",
|
||||
"Frontend Version do not match backend version!": "Die Frontend Version stimmt nicht mit der backend version überein!",
|
||||
};
|
||||
|
@ -2,6 +2,8 @@ export default {
|
||||
languageName: "English",
|
||||
checkEverySecond: "Check every {0} seconds",
|
||||
retryCheckEverySecond: "Retry every {0} seconds",
|
||||
resendEveryXTimes: "Resend every {0} times",
|
||||
resendDisabled: "Resend disabled",
|
||||
retriesDescription: "Maximum retries before the service is marked as down and a notification is sent",
|
||||
ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
|
||||
upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
|
||||
@ -72,6 +74,7 @@ export default {
|
||||
"Heartbeat Interval": "Heartbeat Interval",
|
||||
Retries: "Retries",
|
||||
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
|
||||
"Resend Notification if Down X times consequently": "Resend Notification if Down X times consequently",
|
||||
Advanced: "Advanced",
|
||||
"Upside Down Mode": "Upside Down Mode",
|
||||
"Max. Redirects": "Max. Redirects",
|
||||
@ -408,6 +411,8 @@ export default {
|
||||
SignName: "SignName",
|
||||
"Sms template must contain parameters: ": "Sms template must contain parameters: ",
|
||||
"Bark Endpoint": "Bark Endpoint",
|
||||
"Bark Group": "Bark Group",
|
||||
"Bark Sound": "Bark Sound",
|
||||
WebHookUrl: "WebHookUrl",
|
||||
SecretKey: "SecretKey",
|
||||
"For safety, must use secret key": "For safety, must use secret key",
|
||||
@ -453,6 +458,8 @@ export default {
|
||||
"Message:": "Message:",
|
||||
"Don't know how to get the token? Please read the guide:": "Don't know how to get the token? Please read the guide:",
|
||||
"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.": "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.",
|
||||
"HTTP Headers": "HTTP Headers",
|
||||
"Trust Proxy": "Trust Proxy",
|
||||
"Other Software": "Other Software",
|
||||
"For example: nginx, Apache and Traefik.": "For example: nginx, Apache and Traefik.",
|
||||
"Please read": "Please read",
|
||||
@ -465,6 +472,7 @@ export default {
|
||||
"Domain Name Expiry Notification": "Domain Name Expiry Notification",
|
||||
Proxy: "Proxy",
|
||||
"Date Created": "Date Created",
|
||||
HomeAssistant: "Home Assistant",
|
||||
onebotHttpAddress: "OneBot HTTP Address",
|
||||
onebotMessageType: "OneBot Message Type",
|
||||
onebotGroupMessage: "Group",
|
||||
@ -477,6 +485,12 @@ export default {
|
||||
"Domain Names": "Domain Names",
|
||||
signedInDisp: "Signed in as {0}",
|
||||
signedInDispDisabled: "Auth Disabled.",
|
||||
RadiusSecret: "Radius Secret",
|
||||
RadiusSecretDescription: "Shared Secret between client and server",
|
||||
RadiusCalledStationId: "Called Station Id",
|
||||
RadiusCalledStationIdDescription: "Identifier of the called device",
|
||||
RadiusCallingStationId: "Calling Station Id",
|
||||
RadiusCallingStationIdDescription: "Identifier of the calling device",
|
||||
"Certificate Expiry Notification": "Certificate Expiry Notification",
|
||||
"API Username": "API Username",
|
||||
"API Key": "API Key",
|
||||
@ -485,7 +499,7 @@ export default {
|
||||
"Leave blank to use a shared sender number.": "Leave blank to use a shared sender number.",
|
||||
"Octopush API Version": "Octopush API Version",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"endpoint": "endpoint",
|
||||
endpoint: "endpoint",
|
||||
octopushAPIKey: "\"API key\" from HTTP API credentials in control panel",
|
||||
octopushLogin: "\"Login\" from HTTP API credentials in control panel",
|
||||
promosmsLogin: "API Login Name",
|
||||
@ -529,11 +543,41 @@ export default {
|
||||
"Coming Soon": "Coming Soon",
|
||||
wayToGetClickSendSMSToken: "You can get API Username and API Key from {0} .",
|
||||
"Connection String": "Connection String",
|
||||
"Query": "Query",
|
||||
Query: "Query",
|
||||
settingsCertificateExpiry: "TLS Certificate Expiry",
|
||||
certificationExpiryDescription: "HTTPS Monitors trigger notification when TLS certificate expires in:",
|
||||
"Setup Docker Host": "Setup Docker Host",
|
||||
"Connection Type": "Connection Type",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
deleteDockerHostMsg: "Are you sure want to delete this docker host for all monitors?",
|
||||
socket: "Socket",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker Container",
|
||||
"Container Name / ID": "Container Name / ID",
|
||||
"Docker Host": "Docker Host",
|
||||
"Docker Hosts": "Docker Hosts",
|
||||
"ntfy Topic": "ntfy Topic",
|
||||
"Domain": "Domain",
|
||||
"Workstation": "Workstation",
|
||||
disableCloudflaredNoAuthMsg: "You are in No Auth mode, password is not require.",
|
||||
Domain: "Domain",
|
||||
Workstation: "Workstation",
|
||||
disableCloudflaredNoAuthMsg: "You are in No Auth mode, a password is not required.",
|
||||
trustProxyDescription: "Trust 'X-Forwarded-*' headers. If you want to get the correct client IP and your Uptime Kuma is behind such as Nginx or Apache, you should enable this.",
|
||||
wayToGetLineNotifyToken: "You can get an access token from {0}",
|
||||
Examples: "Examples",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "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": "Notification Service",
|
||||
"default: notify all devices": "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.": "A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Automations can optionally be triggered in Home Assistant:",
|
||||
"Trigger type:": "Trigger type:",
|
||||
"Event type:": "Event type:",
|
||||
"Event data:": "Event data:",
|
||||
"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.",
|
||||
"Frontend Version": "Frontend Version",
|
||||
"Frontend Version do not match backend version!": "Frontend Version do not match backend version!",
|
||||
"Base URL": "Base URL",
|
||||
goAlertInfo: "GoAlert is a An open source application for on-call scheduling, automated escalations and notifications (like SMS or voice calls). Automatically engage the right person, the right way, and at the right time! {0}",
|
||||
goAlertIntegrationKeyInfo: "Get generic API integration key for the service in this format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" usually the value of token parameter of copied URL.",
|
||||
goAlert: "GoAlert",
|
||||
};
|
||||
|
@ -7,8 +7,8 @@ export default {
|
||||
maxRedirectDescription: "Número máximo de direcciones a seguir. Establecer a 0 para deshabilitar.",
|
||||
acceptedStatusCodesDescription: "Seleccionar los códigos de estado que se consideran como respuesta exitosa.",
|
||||
passwordNotMatchMsg: "La contraseña repetida no coincide.",
|
||||
notificationDescription: "Por favor asigne una notificación a el/los monitor(es) para hacerlos funcional(es).",
|
||||
keywordDescription: "Palabra clave en HTML plano o respuesta JSON y es sensible a mayúsculas",
|
||||
notificationDescription: "Por favor asigna una notificación a el/los monitor(es) para hacerlos funcional(es).",
|
||||
keywordDescription: "Palabra clave en HTML plano o respuesta JSON, es sensible a mayúsculas",
|
||||
pauseDashboardHome: "Pausado",
|
||||
deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?",
|
||||
deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?",
|
||||
@ -35,7 +35,7 @@ export default {
|
||||
Pause: "Pausar",
|
||||
Name: "Nombre",
|
||||
Status: "Estado",
|
||||
DateTime: "Fecha y Hora",
|
||||
DateTime: "Fecha y hora",
|
||||
Message: "Mensaje",
|
||||
"No important events": "No hay eventos importantes",
|
||||
Resume: "Reanudar",
|
||||
@ -50,7 +50,7 @@ export default {
|
||||
"-hour": "-hora",
|
||||
Response: "Respuesta",
|
||||
Ping: "Ping",
|
||||
"Monitor Type": "Tipo de Monitor",
|
||||
"Monitor Type": "Tipo de monitor",
|
||||
Keyword: "Palabra clave",
|
||||
"Friendly Name": "Nombre sencillo",
|
||||
URL: "URL",
|
||||
@ -60,11 +60,11 @@ export default {
|
||||
Retries: "Reintentos",
|
||||
Advanced: "Avanzado",
|
||||
"Upside Down Mode": "Modo invertido",
|
||||
"Max. Redirects": "Redirecciones Máximas",
|
||||
"Max. Redirects": "Redirecciones máximas",
|
||||
"Accepted Status Codes": "Códigos de estado aceptados",
|
||||
Save: "Guardar",
|
||||
Notifications: "Notificaciones",
|
||||
"Not available, please setup.": "No disponible, por favor configúrelo.",
|
||||
"Not available, please setup.": "No disponible, por favor configúralo.",
|
||||
"Setup Notification": "Configurar notificación",
|
||||
Light: "Claro",
|
||||
Dark: "Oscuro",
|
||||
@ -82,8 +82,8 @@ export default {
|
||||
"New Password": "Nueva contraseña",
|
||||
"Repeat New Password": "Repetir nueva contraseña",
|
||||
"Update Password": "Actualizar contraseña",
|
||||
"Disable Auth": "Deshabilitar Autenticación",
|
||||
"Enable Auth": "Habilitar Autenticación",
|
||||
"Disable Auth": "Deshabilitar autenticación",
|
||||
"Enable Auth": "Habilitar autenticación",
|
||||
"disableauth.message1": "Seguro que deseas <strong>deshabilitar la autenticación</strong>?",
|
||||
"disableauth.message2": "Es para <strong>quien implementa autenticación de terceros</strong> ante Uptime Kuma como por ejemplo Cloudflare Access.",
|
||||
"Please use this option carefully!": "Por favor usar con cuidado.",
|
||||
@ -104,32 +104,32 @@ export default {
|
||||
Test: "Test",
|
||||
"Certificate Info": "Información del certificado",
|
||||
"Resolver Server": "Servidor de resolución",
|
||||
"Resource Record Type": "Tipo de Registro",
|
||||
"Resource Record Type": "Tipo de registro",
|
||||
"Last Result": "Último resultado",
|
||||
"Create your admin account": "Crea tu cuenta de administrador",
|
||||
"Repeat Password": "Repetir contraseña",
|
||||
respTime: "Tiempo de resp. (ms)",
|
||||
notAvailableShort: "N/A",
|
||||
Create: "Crear",
|
||||
clearEventsMsg: "¿Está seguro de que desea eliminar todos los eventos de este monitor?",
|
||||
clearHeartbeatsMsg: "¿Está seguro de que desea eliminar todos los latidos de este monitor?",
|
||||
confirmClearStatisticsMsg: "¿Está seguro de que desea eliminar TODAS las estadísticas?",
|
||||
"Clear Data": "Borrar Datos",
|
||||
clearEventsMsg: "¿Estás seguro de que deseas eliminar todos los eventos de este monitor?",
|
||||
clearHeartbeatsMsg: "¿Estás seguro de que deseas eliminar todos los latidos de este monitor?",
|
||||
confirmClearStatisticsMsg: "¿Estás seguro de que deseas eliminar TODAS las estadísticas?",
|
||||
"Clear Data": "Borrar datos",
|
||||
Events: "Eventos",
|
||||
Heartbeats: "Latidos",
|
||||
"Auto Get": "Obtener automáticamente",
|
||||
enableDefaultNotificationDescription: "Para cada nuevo monitor, esta notificación estará habilitada de forma predeterminada. Aún puede deshabilitar la notificación por separado para cada monitor.",
|
||||
enableDefaultNotificationDescription: "Para cada nuevo monitor, esta notificación estará habilitada de forma predeterminada. Aún puedes deshabilitar la notificación por separado para cada monitor.",
|
||||
"Default enabled": "Habilitado por defecto",
|
||||
"Also apply to existing monitors": "También se aplica a monitores existentes",
|
||||
Export: "Exportar",
|
||||
Import: "Importar",
|
||||
backupDescription: "Puede hacer una copia de seguridad de todos los monitores y todas las notificaciones en un archivo JSON.",
|
||||
backupDescription: "Puedes hacer una copia de seguridad de todos los monitores y todas las notificaciones en un archivo JSON.",
|
||||
backupDescription2: "PD: el historial y los datos de eventos no están incluidos.",
|
||||
backupDescription3: "Los datos confidenciales, como los tokens de notificación, se incluyen en el archivo de exportación. Guárdelo con cuidado.",
|
||||
alertNoFile: "Seleccione un archivo para importar.",
|
||||
alertWrongFileType: "Seleccione un archivo JSON.",
|
||||
twoFAVerifyLabel: "Ingrese su token para verificar que 2FA está funcionando",
|
||||
tokenValidSettingsMsg: "¡El token es válido! Ahora puede guardar la configuración de 2FA.",
|
||||
backupDescription3: "Los datos confidenciales, como los tokens de notificación, se incluyen en el archivo de exportación. Guárdalo con cuidado.",
|
||||
alertNoFile: "Selecciona un archivo para importar.",
|
||||
alertWrongFileType: "Selecciona un archivo JSON.",
|
||||
twoFAVerifyLabel: "Ingresa tu token para verificar que 2FA está funcionando",
|
||||
tokenValidSettingsMsg: "¡El token es válido! Ahora puedes guardar la configuración de 2FA.",
|
||||
confirmEnableTwoFAMsg: "¿Estás seguro de que quieres habilitar 2FA?",
|
||||
confirmDisableTwoFAMsg: "¿Estás seguro de que quieres desactivar 2FA?",
|
||||
"Apply on all existing monitors": "Aplicar en todos los monitores existentes",
|
||||
@ -145,19 +145,19 @@ export default {
|
||||
"Show URI": "Mostrar URI",
|
||||
"Clear all statistics": "Borrar todas las estadísticas",
|
||||
retryCheckEverySecond: "Reintentar cada {0} segundo.",
|
||||
importHandleDescription: "Elija 'Omitir existente' si desea omitir todos los monitores o notificaciones con el mismo nombre. 'Sobrescribir' eliminará todos los monitores y notificaciones existentes.",
|
||||
confirmImportMsg: "¿Estás seguro de importar la copia de seguridad? Asegúrese de haber seleccionado la opción de importación correcta.",
|
||||
importHandleDescription: "Elige 'Omitir existente' si deseas omitir todos los monitores o notificaciones con el mismo nombre. 'Sobrescribir' eliminará todos los monitores y notificaciones existentes.",
|
||||
confirmImportMsg: "¿Estás seguro de importar la copia de seguridad? Asegúrate de haber seleccionado la opción de importación correcta.",
|
||||
"Heartbeat Retry Interval": "Intervalo de reintento de latido",
|
||||
"Import Backup": "Importar copia de seguridad",
|
||||
"Export Backup": "Exportar copia de seguridad",
|
||||
"Skip existing": "Omitir existente",
|
||||
Overwrite: "Sobrescribir",
|
||||
Options: "Opciones",
|
||||
"Keep both": "Mantén ambos",
|
||||
"Keep both": "Manténer ambos",
|
||||
Tags: "Etiquetas",
|
||||
"Add New below or Select...": "Agregar nuevo a continuación o Seleccionar...",
|
||||
"Tag with this name already exist.": "La etiqueta con este nombre ya existe.",
|
||||
"Tag with this value already exist.": "La etiqueta con este valor ya existe.",
|
||||
"Add New below or Select...": "Agregar nuevo a continuación o seleccionar...",
|
||||
"Tag with this name already exist.": "Una etiqueta con este nombre ya existe.",
|
||||
"Tag with this value already exist.": "Una etiqueta con este valor ya existe.",
|
||||
color: "color",
|
||||
"value (optional)": "valor (opcional)",
|
||||
Gray: "Gris",
|
||||
@ -172,17 +172,17 @@ export default {
|
||||
"Avg. Ping": "Ping promedio",
|
||||
"Avg. Response": "Respuesta promedio",
|
||||
"Entry Page": "Página de entrada",
|
||||
statusPageNothing: "No hay nada aquí, agregue un grupo o un monitor.",
|
||||
statusPageNothing: "No hay nada aquí, agrega un grupo o un monitor.",
|
||||
"No Services": "Sin servicio",
|
||||
"All Systems Operational": "Todos los sistemas están operativos",
|
||||
"Partially Degraded Service": "Servicio parcialmente degradado",
|
||||
"Degraded Service": "Servicio degradado",
|
||||
"Add Group": "Agregar Grupo",
|
||||
"Add Group": "Agregar grupo",
|
||||
"Add a monitor": "Agregar un monitor",
|
||||
"Edit Status Page": "Editar página de estado",
|
||||
"Go to Dashboard": "Ir al panel de control",
|
||||
"Status Page": "Página de estado",
|
||||
"Status Pages": "Página de estado",
|
||||
"Status Pages": "Páginas de estado",
|
||||
telegram: "Telegram",
|
||||
webhook: "Webhook",
|
||||
smtp: "Email (SMTP)",
|
||||
@ -205,5 +205,5 @@ export default {
|
||||
clearDataOlderThan: "Mantener los datos del historial del monitor durante {0} días.",
|
||||
records: "registros",
|
||||
"One record": "Un registro",
|
||||
steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesita una clave Steam Web-API. Puede registrar su clave API aquí: ",
|
||||
steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesitas una clave Steam Web-API. Puedes registrar tu clave API aquí: ",
|
||||
};
|
||||
|
@ -177,8 +177,16 @@ export default {
|
||||
"Add a monitor": "Ajouter une sonde",
|
||||
"Edit Status Page": "Modifier la page de statut",
|
||||
"Go to Dashboard": "Accéder au tableau de bord",
|
||||
"Status Page": "Status Page",
|
||||
"Status Pages": "Status Pages",
|
||||
"Status Page": "Page de statut",
|
||||
"Status Pages": "Pages de statut",
|
||||
"New Status Page": "Ajouter page de statut",
|
||||
"Add New Status Page": "Ajouter une page de statut",
|
||||
"No status pages": "Aucune page de statut.",
|
||||
"Accept characters:": "Caractères acceptés:",
|
||||
startOrEndWithOnly: "Commence uniquement par {0}",
|
||||
"No consecutive dashes": "Pas de double tirets",
|
||||
Next: "Continuer",
|
||||
"Setup Proxy": "Configuer Proxy",
|
||||
defaultNotificationName: "Ma notification {notification} numéro ({number})",
|
||||
here: "ici",
|
||||
Required: "Requis",
|
||||
@ -236,7 +244,7 @@ export default {
|
||||
octopush: "Octopush",
|
||||
promosms: "PromoSMS",
|
||||
lunasea: "LunaSea",
|
||||
apprise: "Apprise (Support 50+ Notification services)",
|
||||
apprise: "Apprise (Prend en charge plus de 50 services de notification)",
|
||||
pushbullet: "Pushbullet",
|
||||
line: "Line Messenger",
|
||||
mattermost: "Mattermost",
|
||||
@ -261,7 +269,7 @@ export default {
|
||||
"Read more": "En savoir plus",
|
||||
appriseInstalled: "Apprise est installé.",
|
||||
appriseNotInstalled: "Apprise n'est pas installé. {0}",
|
||||
"Access Token": "Access Token",
|
||||
"Access Token": "Token d'accès",
|
||||
"Channel access token": "Token d'accès au canal",
|
||||
"Line Developers Console": "Ligne console de développeurs",
|
||||
lineDevConsoleTo: "Ligne console de développeurs - {0}",
|
||||
@ -309,4 +317,118 @@ export default {
|
||||
alertaApiKey: "Clé de l'API",
|
||||
alertaAlertState: "État de l'Alerte",
|
||||
alertaRecoverState: "État de récupération",
|
||||
resendEveryXTimes: "Renvoyez toutes les {0} fois",
|
||||
resendDisabled: "Renvoi désactivé",
|
||||
dnsPortDescription: "Port du serveur DNS. La valeur par défaut est 53. Vous pouvez modifier le port à tout moment.",
|
||||
"Resend Notification if Down X times consequently": "Renvoyer la notification a partir d'un certain temps",
|
||||
"Push URL": "Push URL",
|
||||
needPushEvery: "Vous devez appeler cette URL toutes les {0} secondes.",
|
||||
pushOptionalParams: "parametres optionnels: {0}",
|
||||
"disableauth.message1": "Voulez-vous vraiment <strong>désactiver l'authentification</strong>?",
|
||||
"disableauth.message2": "Il est conçu pour les scénarios <strong>où vous avez l'intention d'implémenter une authentification tierce</strong> devant Uptime Kuma, comme Cloudflare Access, Authelia ou d'autres mécanismes d'authentification.",
|
||||
"Please use this option carefully!": "Veuillez utiliser cette option avec précaution !",
|
||||
PushByTechulus: "Pousser par Techulus",
|
||||
GoogleChat: "Google Chat (Google Workspace uniquement)",
|
||||
Done: "Fait",
|
||||
Info: "Info",
|
||||
Security: "Sécurité",
|
||||
"Steam API Key": "Clé API Steam",
|
||||
"Shrink Database": "Réduire la base de données",
|
||||
"Pick a RR-Type...": "Pick a RR-Type...",
|
||||
"Pick Accepted Status Codes...": "Pick Accepted Status Codes...",
|
||||
Default: "Défaut",
|
||||
"HTTP Options": "HTTP Options",
|
||||
"Create Incident": "Créer un incident",
|
||||
Title: "Titre",
|
||||
Content: "Contenu",
|
||||
Style: "Style",
|
||||
info: "info",
|
||||
warning: "Attention",
|
||||
danger: "danger",
|
||||
error: "Erreur",
|
||||
critical: "critique",
|
||||
primary: "primaire",
|
||||
light: "blanc",
|
||||
dark: "Noir",
|
||||
Post: "Post",
|
||||
"Please input title and content": "Veuillez entrer le titre et le contenu",
|
||||
Created: "Created",
|
||||
"Last Updated": "Dernière mise à jour",
|
||||
Unpin: "Détacher",
|
||||
"Switch to Light Theme": "Passer au thème clair",
|
||||
"Switch to Dark Theme": "Passer au thème sombre",
|
||||
"Show Tags": "Voir les étiquettes",
|
||||
"Hide Tags": "Masquer les étiquettes",
|
||||
Description: "Description",
|
||||
"No monitors available.": "Aucun moniteur disponible.",
|
||||
"Add one": "En rajouter un",
|
||||
"No Monitors": "Aucun moniteur",
|
||||
"Untitled Group": "Groupe sans titre",
|
||||
Services: "Services",
|
||||
Discard: "Annuler",
|
||||
Cancel: "Annuler",
|
||||
shrinkDatabaseDescription: "Déclencher la base de données VACUUM pour SQLite. Si votre base de données est créée après 1.10.0, AUTO_VACUUM est déjà activé et cette action n'est pas nécessaire.",
|
||||
serwersmsAPIUser: "Nom d'utilisateur de l'API (incl. webapi_ prefix)",
|
||||
serwersmsAPIPassword: "Mot de passe API",
|
||||
serwersmsPhoneNumber: "Numéro de téléphone",
|
||||
serwersmsSenderName: "Nom de l'expéditeur du SMS (enregistré via le portail client)",
|
||||
Customize: "Personnaliser",
|
||||
"Custom Footer": "Pied de page personnalisé",
|
||||
"Custom CSS": "CSS personnalisé",
|
||||
deleteStatusPageMsg: "Voulez-vous vraiment supprimer cette page d'état ?",
|
||||
Proxies: "Proxies",
|
||||
default: "Défaut",
|
||||
enabled: "Activé",
|
||||
setAsDefault: "Définir par défaut",
|
||||
deleteProxyMsg: "Voulez-vous vraiment supprimer ce proxy pour tous les moniteurs ?",
|
||||
proxyDescription: "Les proxys doivent être affectés à un moniteur pour fonctionner.",
|
||||
enableProxyDescription: "Ce proxy n'aura pas d'effet sur les demandes de moniteur tant qu'il n'est pas activé. Vous pouvez contrôler la désactivation temporaire du proxy de tous les moniteurs en fonction de l'état d'activation.",
|
||||
setAsDefaultProxyDescription: "Ce proxy sera activé par défaut pour les nouveaux moniteurs. Vous pouvez toujours désactiver le proxy séparément pour chaque moniteur.",
|
||||
Valid: "Valide",
|
||||
Invalid: "Non valide",
|
||||
User: "Utilisateur",
|
||||
Installed: "Installé",
|
||||
"Not installed": "Pas installé",
|
||||
"Remove Token": "Supprimer le jeton",
|
||||
Slug: "chemin",
|
||||
"The slug is already taken. Please choose another slug.": "Le chemin est déjà pris. Veuillez choisir un autre chemin.",
|
||||
Authentication: "Authentication",
|
||||
"Page Not Found": "Page non trouvée",
|
||||
Backup: "Sauvegarde",
|
||||
About: "À propos de",
|
||||
"Footer Text": "Texte de pied de page",
|
||||
"Domain Names": "Noms de domaine",
|
||||
signedInDisp: "Connecté en tant que {0}",
|
||||
signedInDispDisabled: "Authentification désactivée.",
|
||||
"Show update if available": "Afficher la mise à jour si disponible",
|
||||
"Also check beta release": "Vérifiez également la version bêta",
|
||||
"Steam Game Server": "Serveur de jeu Steam",
|
||||
"Most likely causes:": "Causes les plus probables:",
|
||||
"The resource is no longer available.": "La ressource n'est plus disponible.",
|
||||
"There might be a typing error in the address.": "Il se peut qu'il y ait une erreur de frappe dans l'adresse.",
|
||||
"What you can try:": "Ce que vous pouvez essayer:",
|
||||
"Retype the address.": "Retapez l'adresse.",
|
||||
"Go back to the previous page.": "Retournez à la page précédente.",
|
||||
"Coming Soon": "À venir",
|
||||
settingsCertificateExpiry: "Expiration du certificat TLS",
|
||||
certificationExpiryDescription: "Les moniteurs HTTPS déclenchent une notification lorsque le certificat TLS expire dans:",
|
||||
"Setup Docker Host": "Configurer l'hôte Docker",
|
||||
"Connection Type": "Type de connexion",
|
||||
deleteDockerHostMsg: "Voulez-vous vraiment supprimer cet hôte Docker pour tous les moniteurs ?",
|
||||
"Container Name / ID": "Nom / ID du conteneur",
|
||||
"Docker Host": "Hôte Docker",
|
||||
"Docker Hosts": "Hôtes Docker",
|
||||
Domain: "Domaine",
|
||||
trustProxyDescription: "Faire confiance aux en-têtes 'X-Forwarded-*'. Si vous souhaitez obtenir la bonne adresse IP client et que votre Uptime Kuma est en retard, comme Nginx ou Apache, vous devez l'activer.",
|
||||
wayToGetLineNotifyToken: "Vous pouvez obtenir un jeton d'accès auprès de {0}",
|
||||
Examples: "Exemples",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Un jeton d'accès de longue durée peut être créé en cliquant sur le nom de votre profil (en bas à gauche) et en faisant défiler vers le bas, puis cliquez sur Créer un jeton. ",
|
||||
"Notification Service": "Service de notifications",
|
||||
"default: notify all devices": "par défaut: notifier tous les appareils",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Une liste des services de notification peut être trouvée dans Home Assistant sous \"Outils de développement > Services\" recherchez \"notification\" pour trouver le nom de votre appareil/téléphone.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Les automatisations peuvent éventuellement être déclenchées dans Home Assistant:",
|
||||
"Trigger type:": "Type de déclencheur:",
|
||||
"Event type:": "Type d'événement:",
|
||||
"Event data:": "Données d'événement:",
|
||||
};
|
||||
|
@ -80,7 +80,7 @@ export default {
|
||||
pushOptionalParams: "Neobavezni parametri: {0}",
|
||||
Save: "Spremi",
|
||||
Notifications: "Obavijesti",
|
||||
"Not available, please setup.": "Obavijesti nisu dostupne, potrebno dodati novu obavijest.",
|
||||
"Not available, please setup.": "Nije dostupno, potrebno je dodati novu stavku.",
|
||||
"Setup Notification": "Dodaj obavijest",
|
||||
Light: "Svijetli način",
|
||||
Dark: "Tamni način",
|
||||
@ -129,7 +129,7 @@ export default {
|
||||
Export: "Izvoz",
|
||||
Import: "Uvoz",
|
||||
respTime: "Vrijeme odgovora (ms)",
|
||||
notAvailableShort: "N/A",
|
||||
notAvailableShort: "ne postoji",
|
||||
"Default enabled": "Omogući za nove monitore",
|
||||
"Apply on all existing monitors": "Primijeni na postojeće monitore",
|
||||
Create: "Kreiraj",
|
||||
@ -375,4 +375,207 @@ export default {
|
||||
alertaAlertState: "Stanje upozorenja",
|
||||
alertaRecoverState: "Stanje oporavka",
|
||||
deleteStatusPageMsg: "Sigurno želite obrisati ovu statusnu stranicu?",
|
||||
resendEveryXTimes: "Ponovno pošalji svakih {0} puta",
|
||||
resendDisabled: "Ponovno slanje je onemogućeno",
|
||||
dnsPortDescription: "Port DNS poslužitelja. Zadana vrijednost je 53. Moguće je promijeniti ga u svakom trenutku.",
|
||||
"Resend Notification if Down X times consequently": "Ponovno pošalji obavijest ako je usluga nedostupna više puta zaredom",
|
||||
topic: "Tema",
|
||||
topicExplanation: "MQTT tema koja će se monitorirati",
|
||||
successMessage: "Poruka o uspjehu",
|
||||
successMessageExplanation: "MQTT poruka koja se smatra uspješnom",
|
||||
error: "greška",
|
||||
critical: "kritično",
|
||||
Customize: "Customize",
|
||||
"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}",
|
||||
"Integration Key": "Ključ integracije",
|
||||
"Integration URL": "URL integracije",
|
||||
"Auto resolve or acknowledged": "Automatsko razrješavanje i priznavanje",
|
||||
"do nothing": "Ne radi ništa",
|
||||
"auto acknowledged": "Automatsko priznavanje",
|
||||
"auto resolve": "Automatsko razrješavanje",
|
||||
Proxies: "Proxy poslužitelji",
|
||||
default: "Zadano",
|
||||
enabled: "Omogućeno",
|
||||
setAsDefault: "Postavi kao zadano",
|
||||
deleteProxyMsg: "Sigurno želite obrisati ovaj proxy za sve monitore?",
|
||||
proxyDescription: "Proxy poslužitelji moraju biti dodijeljni monitoru kako bi funkcionirali.",
|
||||
enableProxyDescription: "Onemogućeni proxy poslužitelj neće imati učinak na zahtjeve monitora. Možete privremeno onemogućiti proxy poslužitelja za sve monitore.",
|
||||
setAsDefaultProxyDescription: "Ovaj proxy poslužitelj bit će odmah omogućen za nove monitore. I dalje ga možete onemogućiti za svaki monitor zasebno.",
|
||||
"Certificate Chain": "Lanac certifikata",
|
||||
Valid: "Važeći",
|
||||
Invalid: "Nevažeći",
|
||||
AccessKeyId: "AccessKey ID",
|
||||
SecretAccessKey: "AccessKey tajni ključ",
|
||||
PhoneNumbers: "Telefonski brojevi",
|
||||
TemplateCode: "Predložak koda",
|
||||
SignName: "Potpis",
|
||||
"Sms template must contain parameters: ": "SMS predložak mora sadržavati parametre: ",
|
||||
"Bark Endpoint": "Bark krajnja točka (endpoint)",
|
||||
"Bark Group": "Bark grupa",
|
||||
"Bark Sound": "Bark zvuk",
|
||||
WebHookUrl: "WebHookUrl",
|
||||
SecretKey: "Tajni ključ",
|
||||
"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",
|
||||
Topic: "Tema",
|
||||
"WeCom Bot Key": "WeCom ključ Bota",
|
||||
"Setup Proxy": "Dodaj proxy poslužitelj",
|
||||
"Proxy Protocol": "Protokol",
|
||||
"Proxy Server": "Proxy poslužitelj",
|
||||
"Proxy server has authentication": "Proxy poslužitelj ima autentikaciju",
|
||||
User: "Korisnik",
|
||||
Installed: "Instalirano",
|
||||
"Not installed": "Nije instalirano",
|
||||
Running: "Pokrenuto",
|
||||
"Not running": "Nije pokrenuto",
|
||||
"Remove Token": "Ukloni Token",
|
||||
Start: "Pokreni",
|
||||
Stop: "Zaustavi",
|
||||
"Uptime Kuma": "Uptime Kuma",
|
||||
"Add New Status Page": "Dodaj novu statusnu stranicu",
|
||||
Slug: "Slug",
|
||||
"Accept characters:": "Dozvoljeni znakovi:",
|
||||
startOrEndWithOnly: "Započinje ili završava znakovima {0}",
|
||||
"No consecutive dashes": "Bez uzastopnih povlaka",
|
||||
Next: "Sljedeće",
|
||||
"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",
|
||||
"New Status Page": "Dodaj statusnu stranicu",
|
||||
"Page Not Found": "Stranica nije pronađena",
|
||||
"Reverse Proxy": "Reverzni proxy",
|
||||
Backup: "Sigurnosno kopiranje",
|
||||
About: "O Uptime Kumi",
|
||||
wayToGetCloudflaredURL: "(Preuzmite cloudflared s {0})",
|
||||
cloudflareWebsite: "Cloudflare web stranice",
|
||||
"Message:": "Poruka:",
|
||||
"Don't know how to get the token? Please read the guide:": "Ne znate kako doći do tokena? Pročitajte vodič:",
|
||||
"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.": "Trenutna veza možda bude prekinuta jer se koristi Cloudflare tuneliranje. Sigurno želite zaustaviti? Unesite lozinku za potvrdu.",
|
||||
"HTTP Headers": "HTTP zaglavlja",
|
||||
"Trust Proxy": "Vjeruj proxy poslužitelju",
|
||||
"Other Software": "Ostali programi",
|
||||
"For example: nginx, Apache and Traefik.": "Primjerice: nginx, Apache ili Traefik.",
|
||||
"Please read": "Molimo pročitajte",
|
||||
"Subject:": "Predmet:",
|
||||
"Valid To:": "Valjano do:",
|
||||
"Days Remaining:": "Preostalo dana:",
|
||||
"Issuer:": "Izdavatelj:",
|
||||
"Fingerprint:": "Fingerprint:",
|
||||
"No status pages": "Nema statusnih stranica",
|
||||
"Domain Name Expiry Notification": "Obavijest za istek domena",
|
||||
Proxy: "Proxy",
|
||||
"Date Created": "Datum stvaranja",
|
||||
HomeAssistant: "Home Assistant",
|
||||
onebotHttpAddress: "OneBot HTTP adresa",
|
||||
onebotMessageType: "OneBot tip poruke",
|
||||
onebotGroupMessage: "Grupna",
|
||||
onebotPrivateMessage: "Privatna",
|
||||
onebotUserOrGroupId: "ID korisnika/grupe",
|
||||
onebotSafetyTips: "Pristupni token mora biti postavljen",
|
||||
"PushDeer Key": "PushDeer ključ",
|
||||
"Footer Text": "Tekst podnožja",
|
||||
"Show Powered By": "Pokaži natpis 'Pokreće...'",
|
||||
"Domain Names": "Domene",
|
||||
signedInDisp: "Prijavljeni ste kao {0}",
|
||||
signedInDispDisabled: "Autentikacija onemogućena.",
|
||||
RadiusSecret: "Radius Tajna",
|
||||
RadiusSecretDescription: "Dijeljena Tajna između klijenta i poslužitelja",
|
||||
RadiusCalledStationId: "Called Station ID",
|
||||
RadiusCalledStationIdDescription: "Identifikator pozivne stanice",
|
||||
RadiusCallingStationId: "Calling Station ID",
|
||||
RadiusCallingStationIdDescription: "Identifikator pozivajuće stanice",
|
||||
"Certificate Expiry Notification": "Obavijest za istek certifikata",
|
||||
"API Username": "API korisničko ime",
|
||||
"API Key": "API ključ",
|
||||
"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",
|
||||
endpoint: "krajnja točka (endpoint)",
|
||||
octopushAPIKey: "\"API ključ\" iz HTTP API postavki",
|
||||
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 classical": "Classical",
|
||||
"pushoversounds cosmic": "Cosmic",
|
||||
"pushoversounds falling": "Falling",
|
||||
"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)",
|
||||
pushyAPIKey: "Tajni API ključ",
|
||||
pushyToken: "Token uređaja",
|
||||
"Show update if available": "Pokaži moguću nadogradnju",
|
||||
"Also check beta release": "Provjeravaj i za beta izdanja",
|
||||
"Using a Reverse Proxy?": "Koristi li se reverzni proxy?",
|
||||
"Check how to config it for WebSocket": "Provjerite kako se konfigurira za WebSocket protokol",
|
||||
"Steam Game Server": "Steam poslužitelj igre",
|
||||
"Most likely causes:": "Najvjerojatniji uzroci:",
|
||||
"The resource is no longer available.": "Resurs više nije dostupan.",
|
||||
"There might be a typing error in the address.": "Možda je nastala greška pri upisu adrese.",
|
||||
"What you can try:": "Što možete pokušati:",
|
||||
"Retype the address.": "Ponovno napišite adresu.",
|
||||
"Go back to the previous page.": "Vratite se na prethodnu stranicu.",
|
||||
"Coming Soon": "Dolazi uskoro",
|
||||
wayToGetClickSendSMSToken: "Možete dobiti API korisničko ime i API ključ sa {0}.",
|
||||
"Connection String": "Tekst veze",
|
||||
Query: "Upit",
|
||||
settingsCertificateExpiry: "TLS istek certifikata",
|
||||
certificationExpiryDescription: "HTTPS monitori će obavijesiti kada je istek TLS certifikata za:",
|
||||
"Setup Docker Host": "Dodaj Docker domaćina",
|
||||
"Connection Type": "Tip veze",
|
||||
"Docker Daemon": "Docker daemon",
|
||||
deleteDockerHostMsg: "Sigurno želite izbrisati ovog Docker domaćina za sve monitore?",
|
||||
socket: "Docker socket",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker kontejner",
|
||||
"Container Name / ID": "Naziv / ID kontejnera",
|
||||
"Docker Host": "Docker domaćin",
|
||||
"Docker Hosts": "Docker domaćini",
|
||||
"ntfy Topic": "ntfy tema",
|
||||
Domain: "Domena",
|
||||
Workstation: "Radna stanica",
|
||||
disableCloudflaredNoAuthMsg: "Lozinka nije nužna dok je isključena autentikacija.",
|
||||
trustProxyDescription: "Vjeruj 'X-Forwarded-*' zaglavljima. Ako želite dobiti ispravnu IP adresu klijenta i Uptime Kuma je iza reverznog proxy poslužitelja, trebate omogućiti ovo.",
|
||||
wayToGetLineNotifyToken: "Možete dobiti pristupni token sa {0}",
|
||||
Examples: "Primjeri",
|
||||
"Home Assistant URL": "URL Home Assistanta",
|
||||
"Long-Lived Access Token": "Dugotrajni pristupni 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. ": "Dugotrajni pristupni token može se kreirati klikom na korisničko ime (dolje lijevo) u Home Assistantu, pomicanjem do dna, te klikom na 'Create Token'. ",
|
||||
"Notification Service": "Notification Service",
|
||||
"default: notify all devices": "zadano ponašanje: obavijesti sve uređaje",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Popis servisa za obavijesti u Home Assistantu nalaze se pod \"Developer Tools > Services\" te pretražiti \"notification\".",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Automacije se mogu okinuti u Home Assistantu:",
|
||||
"Trigger type:": "Tip triggera:",
|
||||
"Event type:": "Tip eventa:",
|
||||
"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!",
|
||||
};
|
||||
|
@ -7,25 +7,25 @@ export default {
|
||||
upsideDownModeDescription: "Se il servizio risulta raggiungibile viene marcato come \"DOWN\".",
|
||||
maxRedirectDescription: "Numero massimo di redirezionamenti consentito. Per disabilitare, impostare \"0\".",
|
||||
acceptedStatusCodesDescription: "Elenco di codici di stato HTTP che sono considerati validi.",
|
||||
passwordNotMatchMsg: "La password non coincide.",
|
||||
passwordNotMatchMsg: "La password non corrisponde.",
|
||||
notificationDescription: "Assegnare la notifica a uno o più oggetti monitorati per metterla in funzione.",
|
||||
keywordDescription: "Cerca la parola chiave nella risposta in html o JSON e fai distinzione tra maiuscole e minuscole",
|
||||
pauseDashboardHome: "In Pausa",
|
||||
deleteMonitorMsg: "Si è certi di voler eliminare questo oggetto monitorato?",
|
||||
deleteNotificationMsg: "Si è certi di voler eliminare questa notifica per tutti gli oggetti monitorati?",
|
||||
resolverserverDescription: "Cloudflare è il server predefinito, è possibile cambiare il server DNS.",
|
||||
deleteMonitorMsg: "Sei sicuro di voler eliminare questo oggetto monitorato?",
|
||||
deleteNotificationMsg: "Sei sicuro di voler eliminare questa notifica per tutti gli oggetti monitorati?",
|
||||
resolverserverDescription: "Cloudflare è il server predefinito ma è possibile cambiare il server DNS.",
|
||||
rrtypeDescription: "Scegliere il tipo di RR che si vuole monitorare",
|
||||
pauseMonitorMsg: "Si è certi di voler mettere in pausa?",
|
||||
pauseMonitorMsg: "Sei sicuro di voler mettere in pausa?",
|
||||
enableDefaultNotificationDescription: "Per ogni nuovo monitor questa notifica sarà abilitata di default. È comunque possibile disabilitare la notifica singolarmente.",
|
||||
clearEventsMsg: "Si è certi di voler eliminare tutti gli eventi per questo servizio?",
|
||||
clearHeartbeatsMsg: "Si è certi di voler eliminare tutti gli intervalli di controllo per questo servizio?",
|
||||
confirmClearStatisticsMsg: "Si è certi di voler eliminare TUTTE le statistiche?",
|
||||
clearEventsMsg: "Sei sicuro di voler eliminare tutti gli eventi per questo servizio?",
|
||||
clearHeartbeatsMsg: "Sei sicuro di voler eliminare tutti gli intervalli di controllo per questo servizio?",
|
||||
confirmClearStatisticsMsg: "Sei sicuro di voler eliminare TUTTE le statistiche?",
|
||||
importHandleDescription: "Selezionare \"Ignora esistenti\" se si vuole ignorare l'importazione dei monitor o delle notifiche con lo stesso nome. \"Sovrascrivi\" rimpiazzerà tutti i monitor e le notifiche presenti con quelli nel backup.",
|
||||
confirmImportMsg: "Si è certi di voler importare il backup? Essere certi di aver selezionato l'opzione corretta di importazione.",
|
||||
confirmImportMsg: "Sei sicuro di voler importare il backup? Controlla di aver selezionato l'opzione corretta di importazione.",
|
||||
twoFAVerifyLabel: "Digita il token per verificare che l'autenticazione a due fattori funzioni correttamente:",
|
||||
tokenValidSettingsMsg: "Il token è valido! È ora possibile salvare le impostazioni.",
|
||||
confirmEnableTwoFAMsg: "Si è certi di voler abilitare l'autenticazione a due fattori?",
|
||||
confirmDisableTwoFAMsg: "Si è certi di voler disabilitare l'autenticazione a due fattori?",
|
||||
confirmEnableTwoFAMsg: "Sei sicuro di voler abilitare l'autenticazione a due fattori?",
|
||||
confirmDisableTwoFAMsg: "Sei sicuro di voler disabilitare l'autenticazione a due fattori?",
|
||||
Settings: "Impostazioni",
|
||||
Dashboard: "Dashboard",
|
||||
"New Update": "Nuovo aggiornamento disponibile!",
|
||||
|
@ -3,7 +3,7 @@ export default {
|
||||
checkEverySecond: "{0}초마다 확인해요.",
|
||||
retryCheckEverySecond: "{0}초마다 다시 확인해요.",
|
||||
retriesDescription: "서비스가 중단된 후 알림을 보내기 전 최대 재시도 횟수",
|
||||
ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 에러 무시하기",
|
||||
ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 오류 무시하기",
|
||||
upsideDownModeDescription: "서버 상태를 반대로 표시해요. 서버가 작동하면 오프라인으로 표시할 거예요.",
|
||||
maxRedirectDescription: "최대 리다이렉트 횟수예요. 0을 입력하면 리다이렉트를 꺼요.",
|
||||
acceptedStatusCodesDescription: "응답 성공으로 간주할 상태 코드를 정해요.",
|
||||
@ -30,7 +30,7 @@ export default {
|
||||
Dashboard: "대시보드",
|
||||
"New Update": "새로운 업데이트",
|
||||
Language: "언어",
|
||||
Appearance: "외형",
|
||||
Appearance: "디스플레이",
|
||||
Theme: "테마",
|
||||
General: "일반",
|
||||
Version: "버전",
|
||||
@ -78,7 +78,7 @@ export default {
|
||||
Notifications: "알림",
|
||||
"Not available, please setup.": "존재하지 않아요, 새로운 거 하나 만드는 건 어때요?",
|
||||
"Setup Notification": "알림 설정",
|
||||
Light: "라이트",
|
||||
Light: "화이트",
|
||||
Dark: "다크",
|
||||
Auto: "자동",
|
||||
"Theme - Heartbeat Bar": "테마 - 하트비트 바",
|
||||
@ -91,7 +91,7 @@ export default {
|
||||
"Discourage search engines from indexing site": "검색 엔진 인덱싱 거부",
|
||||
"Change Password": "비밀번호 변경",
|
||||
"Current Password": "기존 비밀번호",
|
||||
"New Password": "새로운 비밀번호",
|
||||
"New Password": "새 비밀번호",
|
||||
"Repeat New Password": "새로운 비밀번호 재입력",
|
||||
"Update Password": "비밀번호 변경",
|
||||
"Disable Auth": "인증 비활성화",
|
||||
@ -109,14 +109,14 @@ export default {
|
||||
Password: "비밀번호",
|
||||
"Remember me": "비밀번호 기억하기",
|
||||
Login: "로그인",
|
||||
"No Monitors, please": "모니터링이 없어요,",
|
||||
"add one": "하나 추가해봐요",
|
||||
"No Monitors, please": "모니터링이 현재 없어요,",
|
||||
"add one": "한번 추가해보실레요?",
|
||||
"Notification Type": "알림 종류",
|
||||
Email: "이메일",
|
||||
Test: "테스트",
|
||||
"Certificate Info": "인증서 정보",
|
||||
"Resolver Server": "Resolver 서버",
|
||||
"Resource Record Type": "자원 레코드 유형",
|
||||
"Resource Record Type": "리소스 레코드 유형",
|
||||
"Last Result": "최근 결과",
|
||||
"Create your admin account": "관리자 계정 만들기",
|
||||
"Repeat Password": "비밀번호 재입력",
|
||||
@ -208,19 +208,19 @@ export default {
|
||||
smtpBCC: "숨은 참조",
|
||||
discord: "Discord",
|
||||
"Discord Webhook URL": "Discord Webhook URL",
|
||||
wayToGetDiscordURL: "서버 설정 -> 연동 -> 웹후크 보기 -> 새 웹후크에서 얻을 수 있어요.",
|
||||
wayToGetDiscordURL: "서버 설정 -> 연동 -> 웹후크 보기 -> 새 웹후크에서 얻을 수 있어요!",
|
||||
"Bot Display Name": "표시 이름",
|
||||
"Prefix Custom Message": "접두사 메시지",
|
||||
"Hello @everyone is...": "{'@'}everyone 서버 상태 알림이에요...",
|
||||
teams: "Microsoft Teams",
|
||||
"Webhook URL": "Webhook URL",
|
||||
wayToGetTeamsURL: "{0}에서 Webhook을 어떻게 만드는지 알아봐요.",
|
||||
wayToGetTeamsURL: "{0}에서 Webhook을 어떻게 만드는지 알아보세요!",
|
||||
signal: "Signal",
|
||||
Number: "숫자",
|
||||
Recipients: "받는 사람",
|
||||
needSignalAPI: "REST API를 사용하는 Signal 클라이언트가 있어야 해요.",
|
||||
wayToCheckSignalURL: "밑에 URL을 확인해 URL 설정 방법을 볼 수 있어요.",
|
||||
signalImportant: "중요: 받는 사람의 그룹과 숫자는 섞을 수 없어요!",
|
||||
signalImportant: "경고: 받는 사람의 그룹과 숫자는 섞을 수 없어요!",
|
||||
gotify: "Gotify",
|
||||
"Application Token": "애플리케이션 토큰",
|
||||
"Server URL": "서버 URL",
|
||||
@ -230,8 +230,8 @@ export default {
|
||||
"Channel Name": "채널 이름",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||
aboutWebhooks: "Webhook에 대한 설명: {0}",
|
||||
aboutChannelName: "Webhook 채널을 우회하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널",
|
||||
aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Project Github 페이지로 설정해요.",
|
||||
aboutChannelName: "Webhook 채널을 무시하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널",
|
||||
aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Github Project 페이지로 설정해요.",
|
||||
emojiCheatSheet: "이모지 목록 시트: {0}",
|
||||
"rocket.chat": "Rocket.chat",
|
||||
pushover: "Pushover",
|
||||
@ -243,8 +243,8 @@ export default {
|
||||
pushbullet: "Pushbullet",
|
||||
line: "Line Messenger",
|
||||
mattermost: "Mattermost",
|
||||
"User Key": "사용자 키",
|
||||
Device: "장치",
|
||||
"User Key": "유저 키",
|
||||
Device: "디바이스",
|
||||
"Message Title": "메시지 제목",
|
||||
"Notification Sound": "알림음",
|
||||
"More info on:": "자세한 정보: {0}",
|
||||
@ -254,7 +254,7 @@ export default {
|
||||
octopushTypePremium: "프리미엄 (빠름) - 알림 기능에 적합해요)",
|
||||
octopushTypeLowCost: "저렴한 요금 (느림) - 가끔 차단될 수 있어요)",
|
||||
"Check octopush prices": "{0}에서 Octopush 가격을 확인할 수 있어요.",
|
||||
octopushPhoneNumber: "휴대전화 번호 (intl format, eg : +33612345678) ",
|
||||
octopushPhoneNumber: "휴대전화 번호 (intl format, 예시: +821023456789) ",
|
||||
octopushSMSSender: "보내는 사람 이름 : 3-11개의 영숫자 및 여백공간 (a-z, A-Z, 0-9)",
|
||||
"LunaSea Device ID": "LunaSea 장치 ID",
|
||||
"Apprise URL": "Apprise URL",
|
||||
@ -324,17 +324,17 @@ export default {
|
||||
Content: "내용",
|
||||
Style: "스타일",
|
||||
info: "정보",
|
||||
warning: "경고",
|
||||
danger: "위험",
|
||||
warning: "주의",
|
||||
danger: "경고",
|
||||
primary: "기본",
|
||||
light: "라이트",
|
||||
light: "화이트",
|
||||
dark: "다크",
|
||||
Post: "올리기",
|
||||
Post: "게시",
|
||||
"Please input title and content": "제목과 내용을 작성해주세요.",
|
||||
Created: "생성 날짜",
|
||||
"Last Updated": "마지막 업데이트",
|
||||
Unpin: "제거",
|
||||
"Switch to Light Theme": "라이트 테마로 전환",
|
||||
"Switch to Light Theme": "화이트 테마로 전환",
|
||||
"Switch to Dark Theme": "다크 테마로 전환",
|
||||
"Show Tags": "태그 보이기",
|
||||
"Hide Tags": "태그 숨기기",
|
||||
@ -361,8 +361,8 @@ export default {
|
||||
topicExplanation: "모니터링할 MQTT Topic",
|
||||
successMessage: "성공 메시지",
|
||||
successMessageExplanation: "성공으로 간주되는 MQTT 메시지",
|
||||
error: "error",
|
||||
critical: "critical",
|
||||
error: "오류",
|
||||
critical: "크리티컬",
|
||||
Customize: "커스터마이즈",
|
||||
"Custom Footer": "커스텀 Footer",
|
||||
"Custom CSS": "커스텀 CSS",
|
||||
@ -406,7 +406,7 @@ export default {
|
||||
PhoneNumbers: "휴대전화 번호",
|
||||
TemplateCode: "템플릿 코드",
|
||||
SignName: "SignName",
|
||||
"Sms template must contain parameters: ": "Sms 템플릿은 다음과 같은 파라미터가 포함되어야 해요:",
|
||||
"Sms template must contain parameters: ": "SMS 템플릿은 다음과 같은 파라미터가 포함되어야 해요:",
|
||||
"Bark Endpoint": "Bark Endpoint",
|
||||
WebHookUrl: "웹훅 URL",
|
||||
SecretKey: "Secret Key",
|
||||
@ -518,14 +518,14 @@ export default {
|
||||
"Show update if available": "사용 가능한 경우에 업데이트 표시",
|
||||
"Also check beta release": "베타 릴리즈 확인",
|
||||
"Using a Reverse Proxy?": "리버스 프록시를 사용하시나요?",
|
||||
"Check how to config it for WebSocket": "웹소켓에 대한 설정 방법 확인",
|
||||
"Check how to config it for WebSocket": "웹소켓 대한 설정 방법",
|
||||
"Steam Game Server": "스팀 게임 서버",
|
||||
"Most likely causes:": "원인:",
|
||||
"The resource is no longer available.": "더이상 사용할 수 없어요.",
|
||||
"The resource is no longer available.": "더 이상 사용할 수 없어요...",
|
||||
"There might be a typing error in the address.": "주소에 오탈자가 있을 수 있어요.",
|
||||
"What you can try:": "해결 방법:",
|
||||
"Retype the address.": "주소 다시 입력하기",
|
||||
"Go back to the previous page.": "이전 페이지로 돌아가기",
|
||||
"Coming Soon": "Coming Soon",
|
||||
"Coming Soon": "Coming Soon...",
|
||||
wayToGetClickSendSMSToken: "{0}에서 API 사용자 이름과 키를 얻을 수 있어요.",
|
||||
};
|
||||
|
203
src/languages/pt-PT.js
Normal file
203
src/languages/pt-PT.js
Normal file
@ -0,0 +1,203 @@
|
||||
export default {
|
||||
languageName: "Português (Portugal)",
|
||||
checkEverySecond: "Verificar a cada {0} segundos.",
|
||||
retryCheckEverySecond: "Tentar novamente a cada {0} segundos.",
|
||||
retriesDescription: "Máximo de tentativas antes que o serviço seja marcado como inativo e uma notificação seja enviada",
|
||||
ignoreTLSError: "Ignorar erros TLS/SSL para sites HTTPS",
|
||||
upsideDownModeDescription: "Inverte o status de cabeça para baixo. Se o serviço estiver acessível, ele está OFFLINE.",
|
||||
maxRedirectDescription: "Número máximo de redirecionamentos a seguir. Define como 0 para desativar redirecionamentos.",
|
||||
acceptedStatusCodesDescription: "Seleciona os códigos de status que são considerados uma resposta bem-sucedida.",
|
||||
passwordNotMatchMsg: "A senha repetida não corresponde.",
|
||||
notificationDescription: "Atribuir uma notificação ao (s) monitor (es) para que funcione.",
|
||||
keywordDescription: "Pesquisa a palavra-chave em HTML simples ou resposta JSON e diferencia maiúsculas de minúsculas",
|
||||
pauseDashboardHome: "Pausa",
|
||||
deleteMonitorMsg: "Tens a certeza de que queres excluir este monitor?",
|
||||
deleteNotificationMsg: "Tens a certeza de que queres excluir esta notificação para todos os monitores?",
|
||||
resolverserverDescription: "A Cloudflare é o servidor padrão, podes alterar o servidor 'resolvedor' a qualquer momento.",
|
||||
rrtypeDescription: "Seleciona o RR-Type que queres monitorizar",
|
||||
pauseMonitorMsg: "Tens a certeza que queres fazer uma pausa?",
|
||||
enableDefaultNotificationDescription: "Para cada monitor novo esta notificação vai estar activa por padrão. Podes também desativar a notificação separadamente para cada monitor.",
|
||||
clearEventsMsg: "Tens a certeza que queres excluir todos os eventos deste monitor?",
|
||||
clearHeartbeatsMsg: "Tens a certeza de que queres excluir todos os heartbeats deste monitor?",
|
||||
confirmClearStatisticsMsg: "Tens a certeza que queres excluir TODAS as estatísticas?",
|
||||
importHandleDescription: "Escolhe 'Ignorar existente' se quiseres ignorar todos os monitores ou notificações com o mesmo nome. 'Substituir' excluirá todos os monitores e notificações existentes.",
|
||||
confirmImportMsg: "Tens a certeza que queres importar o backup? Certifica-te que selecionaste a opção de importação correta.",
|
||||
twoFAVerifyLabel: "Insire o teu token para verificares se o 2FA está a funcionar",
|
||||
tokenValidSettingsMsg: "O token é válido! Agora podes salvar as configurações do 2FA.",
|
||||
confirmEnableTwoFAMsg: "Tens a certeza de que queres habilitar 2FA?",
|
||||
confirmDisableTwoFAMsg: "Tens a certeza de que queres desativar 2FA?",
|
||||
Settings: "Configurações",
|
||||
Dashboard: "Dashboard",
|
||||
"New Update": "Nova Atualização",
|
||||
Language: "Linguagem",
|
||||
Appearance: "Aparência",
|
||||
Theme: "Tema",
|
||||
General: "Geral",
|
||||
Version: "Versão",
|
||||
"Check Update On GitHub": "Verificar atualização no Github",
|
||||
List: "Lista",
|
||||
Add: "Adicionar",
|
||||
"Add New Monitor": "Adicionar novo monitor",
|
||||
"Quick Stats": "Estatísticas rápidas",
|
||||
Up: "On",
|
||||
Down: "Off",
|
||||
Pending: "Pendente",
|
||||
Unknown: "Desconhecido",
|
||||
Pause: "Pausa",
|
||||
Name: "Nome",
|
||||
Status: "Status",
|
||||
DateTime: "Data hora",
|
||||
Message: "Mensagem",
|
||||
"No important events": "Nenhum evento importante",
|
||||
Resume: "Resumo",
|
||||
Edit: "Editar",
|
||||
Delete: "Apagar",
|
||||
Current: "Atual",
|
||||
Uptime: "Tempo de atividade",
|
||||
"Cert Exp.": "Cert Exp.",
|
||||
day: "dia | dias",
|
||||
"-day": "-dia",
|
||||
hour: "hora",
|
||||
"-hour": "-hora",
|
||||
Response: "Resposta",
|
||||
Ping: "Ping",
|
||||
"Monitor Type": "Tipo de Monitor",
|
||||
Keyword: "Palavra-Chave",
|
||||
"Friendly Name": "Nome Amigável",
|
||||
URL: "URL",
|
||||
Hostname: "Hostname",
|
||||
Port: "Porta",
|
||||
"Heartbeat Interval": "Intervalo de Heartbeats",
|
||||
Retries: "Novas tentativas",
|
||||
"Heartbeat Retry Interval": "Intervalo de repetição de Heartbeats",
|
||||
Advanced: "Avançado",
|
||||
"Upside Down Mode": "Modo de cabeça para baixo",
|
||||
"Max. Redirects": "Redirecionamento Máx.",
|
||||
"Accepted Status Codes": "Status Code Aceitáveis",
|
||||
Save: "Guardar",
|
||||
Notifications: "Notificações",
|
||||
"Not available, please setup.": "Não disponível, por favor configura.",
|
||||
"Setup Notification": "Configurar Notificação",
|
||||
Light: "Claro",
|
||||
Dark: "Escuro",
|
||||
Auto: "Auto",
|
||||
"Theme - Heartbeat Bar": "Tema - Barra de Heartbeat",
|
||||
Normal: "Normal",
|
||||
Bottom: "Inferior",
|
||||
None: "Nenhum",
|
||||
Timezone: "Fuso horário",
|
||||
"Search Engine Visibility": "Visibilidade do mecanismo de pesquisa",
|
||||
"Allow indexing": "Permitir Indexação",
|
||||
"Discourage search engines from indexing site": "Desencorajar que motores de busca indexem o site",
|
||||
"Change Password": "Mudar senha",
|
||||
"Current Password": "Senha atual",
|
||||
"New Password": "Nova Senha",
|
||||
"Repeat New Password": "Repetir Nova Senha",
|
||||
"Update Password": "Atualizar Senha",
|
||||
"Disable Auth": "Desativar Autenticação",
|
||||
"Enable Auth": "Ativar Autenticação",
|
||||
"disableauth.message1": "Tens a certeza que queres <strong>desativar a autenticação</strong>?",
|
||||
"disableauth.message2": "Isso é para <strong>alguém que tem autenticação de terceiros</strong> em frente ao 'UpTime Kuma' como o Cloudflare Access.",
|
||||
"Please use this option carefully!": "Por favor, utiliza esta opção com cuidado.",
|
||||
Logout: "Logout",
|
||||
Leave: "Sair",
|
||||
"I understand, please disable": "Eu entendo, por favor desativa.",
|
||||
Confirm: "Confirmar",
|
||||
Yes: "Sim",
|
||||
No: "Não",
|
||||
Username: "Utilizador",
|
||||
Password: "Senha",
|
||||
"Remember me": "Lembra-me",
|
||||
Login: "Autenticar",
|
||||
"No Monitors, please": "Nenhum monitor, por favor",
|
||||
"add one": "adicionar um",
|
||||
"Notification Type": "Tipo de Notificação",
|
||||
Email: "Email",
|
||||
Test: "Testar",
|
||||
"Certificate Info": "Info. do Certificado ",
|
||||
"Resolver Server": "Resolver Servidor",
|
||||
"Resource Record Type": "Tipo de registro de aplicação",
|
||||
"Last Result": "Último resultado",
|
||||
"Create your admin account": "Cria a tua conta de admin",
|
||||
"Repeat Password": "Repete a senha",
|
||||
"Import Backup": "Importar Backup",
|
||||
"Export Backup": "Exportar Backup",
|
||||
Export: "Exportar",
|
||||
Import: "Importar",
|
||||
respTime: "Tempo de Resp. (ms)",
|
||||
notAvailableShort: "N/A",
|
||||
"Default enabled": "Padrão habilitado",
|
||||
"Apply on all existing monitors": "Aplicar em todos os monitores existentes",
|
||||
Create: "Criar",
|
||||
"Clear Data": "Limpar Dados",
|
||||
Events: "Eventos",
|
||||
Heartbeats: "Heartbeats",
|
||||
"Auto Get": "Obter Automático",
|
||||
backupDescription: "Podes fazer backup de todos os monitores e todas as notificações num arquivo JSON.",
|
||||
backupDescription2: "OBS: Os dados do histórico e do evento não estão incluídos.",
|
||||
backupDescription3: "Dados confidenciais, como tokens de notificação, estão incluídos no arquivo de exportação, mantem-no com cuidado.",
|
||||
alertNoFile: "Seleciona um arquivo para importar.",
|
||||
alertWrongFileType: "Seleciona um arquivo JSON.",
|
||||
"Clear all statistics": "Limpar todas as estatísticas",
|
||||
"Skip existing": "Saltar existente",
|
||||
Overwrite: "Sobrescrever",
|
||||
Options: "Opções",
|
||||
"Keep both": "Manter os dois",
|
||||
"Verify Token": "Verificar Token",
|
||||
"Setup 2FA": "Configurar 2FA",
|
||||
"Enable 2FA": "Ativar 2FA",
|
||||
"Disable 2FA": "Desativar 2FA",
|
||||
"2FA Settings": "Configurações do 2FA ",
|
||||
"Two Factor Authentication": "Autenticação de Dois Fatores",
|
||||
Active: "Ativo",
|
||||
Inactive: "Inativo",
|
||||
Token: "Token",
|
||||
"Show URI": "Mostrar URI",
|
||||
Tags: "Tag",
|
||||
"Add New below or Select...": "Adicionar Novo abaixo ou Selecionar ...",
|
||||
"Tag with this name already exist.": "Já existe uma etiqueta com este nome.",
|
||||
"Tag with this value already exist.": "Já existe uma etiqueta com este valor.",
|
||||
color: "cor",
|
||||
"value (optional)": "valor (opcional)",
|
||||
Gray: "Cinza",
|
||||
Red: "Vermelho",
|
||||
Orange: "Laranja",
|
||||
Green: "Verde",
|
||||
Blue: "Azul",
|
||||
Indigo: "Índigo",
|
||||
Purple: "Roxo",
|
||||
Pink: "Rosa",
|
||||
"Search...": "Pesquisa...",
|
||||
"Avg. Ping": "Ping Médio.",
|
||||
"Avg. Response": "Resposta Média. ",
|
||||
"Status Page": "Página de Status",
|
||||
"Status Pages": "Página de Status",
|
||||
"Entry Page": "Página de entrada",
|
||||
statusPageNothing: "Nada aqui, por favor, adiciona um grupo ou monitor.",
|
||||
"No Services": "Nenhum Serviço",
|
||||
"All Systems Operational": "Todos os Serviços Operacionais",
|
||||
"Partially Degraded Service": "Serviço parcialmente degradados",
|
||||
"Degraded Service": "Serviço Degradado",
|
||||
"Add Group": "Adicionar Grupo",
|
||||
"Add a monitor": "Adicionar um monitor",
|
||||
"Edit Status Page": "Editar Página de Status",
|
||||
"Go to Dashboard": "Ir para o dashboard",
|
||||
telegram: "Telegram",
|
||||
webhook: "Webhook",
|
||||
smtp: "Email (SMTP)",
|
||||
discord: "Discord",
|
||||
teams: "Microsoft Teams",
|
||||
signal: "Signal",
|
||||
gotify: "Gotify",
|
||||
slack: "Slack",
|
||||
"rocket.chat": "Rocket.chat",
|
||||
pushover: "Pushover",
|
||||
pushy: "Pushy",
|
||||
octopush: "Octopush",
|
||||
promosms: "PromoSMS",
|
||||
lunasea: "LunaSea",
|
||||
apprise: "Apprise (Support 50+ Notification services)",
|
||||
pushbullet: "Pushbullet",
|
||||
line: "Line Messenger",
|
||||
mattermost: "Mattermost",
|
||||
};
|
@ -206,10 +206,10 @@ export default {
|
||||
smtp: "Email (SMTP)",
|
||||
secureOptionNone: "None / STARTTLS (25, 587)",
|
||||
secureOptionTLS: "TLS (465)",
|
||||
"Ignore TLS Error": "Ignore TLS Error",
|
||||
"From Email": "From Email",
|
||||
emailCustomSubject: "Custom Subject",
|
||||
"To Email": "To Email",
|
||||
"Ignore TLS Error": "เพิกเฉยข้อผิดพลาด TLS",
|
||||
"From Email": "จากอีเมล",
|
||||
emailCustomSubject: "หัวข้อที่กำหนดเอง",
|
||||
"To Email": "ถึงอีเมล",
|
||||
smtpCC: "CC",
|
||||
smtpBCC: "BCC",
|
||||
discord: "Discord",
|
||||
@ -518,4 +518,63 @@ export default {
|
||||
"Go back to the previous page.": "กลับไปที่หน้าก่อนหน้า",
|
||||
"Coming Soon": "เร็ว ๆ นี้",
|
||||
wayToGetClickSendSMSToken: "คุณสามารถรับ API Username และ API Key ได้จาก {0}",
|
||||
wayToGetLineNotifyToken: "คุณสามารถรับ access token ได้จาก {0}",
|
||||
resendEveryXTimes: "ส่งซ้ำทุก {0} ครั้ง",
|
||||
resendDisabled: "การส่งซ้ำถูกปิดใช้งาน",
|
||||
dnsPortDescription: "พอร์ตของเซิร์ฟเวอร์ DNS, ค่าเริ่มต้นคือ 53, คุณสามารถเปลี่ยนพอร์ตตอนไหนก็ได้",
|
||||
"Resend Notification if Down X times consequently": "ส่งการแจ้งเตือนซ้ำถ้าออฟไลน์ครบ X ครั้ง",
|
||||
error: "เกิดข้อผิดพลาด",
|
||||
critical: "วิกฤต",
|
||||
wayToGetPagerDutyKey: "คุณสามารถรับได้โดยการไปที่ Service -> Service Directory -> (Select a service) -> Integrations -> Add integration, และค้นหา \"Events API V2\", สำหรับข้อมูลเพิ่มเติม {0}",
|
||||
"Integration Key": "Integration Key",
|
||||
"Integration URL": "Integration URL",
|
||||
"Auto resolve or acknowledged": "แก้ไขอัตโนมัติหรือยอมรับ",
|
||||
"do nothing": "ไม่ทำอะไร",
|
||||
"auto acknowledged": "ยอมรับอัตโนมัติ",
|
||||
"auto resolve": "แก้ไขอัตโนมัติ",
|
||||
"Bark Group": "กลุ่มที่จะประกาศ",
|
||||
"Bark Sound": "เสียงประกาศ",
|
||||
Authentication: "การตรวจสอบสิทธิ์",
|
||||
"HTTP Headers": "HTTP Headers",
|
||||
"Trust Proxy": "Trust Proxy",
|
||||
HomeAssistant: "Home Assistant",
|
||||
RadiusSecret: "Radius Secret",
|
||||
RadiusSecretDescription: "แบ่งปันข้อมูลลับระหว่างผู้ใช้งานและเซิร์ฟเวอร์",
|
||||
RadiusCalledStationId: "Called Station Id",
|
||||
RadiusCalledStationIdDescription: "Identifier of the called device",
|
||||
RadiusCallingStationId: "Calling Station Id",
|
||||
RadiusCallingStationIdDescription: "Identifier of the calling device",
|
||||
"Connection String": "Connection String",
|
||||
Query: "Query",
|
||||
settingsCertificateExpiry: "วันหมดอายุใบรับรอง TLS",
|
||||
certificationExpiryDescription: "การตรวจสอบ HTTPS แจ้งเตือนใบอนุญาติ TLS จะหมดอายุใน:",
|
||||
"Setup Docker Host": "Setup Docker Host",
|
||||
"Connection Type": "ประเภทการเชื่อมต่อ",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
deleteDockerHostMsg: "คุณแน่ใจหรือไม่ที่จะลบ Docker host นี้สำหรับการมอนิเตอร์ทั้งหมด?",
|
||||
socket: "Socket",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker Container",
|
||||
"Container Name / ID": "Container Name / ID",
|
||||
"Docker Host": "Docker Host",
|
||||
"Docker Hosts": "Docker Hosts",
|
||||
"ntfy Topic": "ntfy Topic",
|
||||
Domain: "โดเมน",
|
||||
Workstation: "Workstation",
|
||||
disableCloudflaredNoAuthMsg: "คุณอยู่ในโหมดไม่มีการตรวจสอบสิทธิ์, ไม่จำเป็นต้องมีรหัสผ่าน",
|
||||
trustProxyDescription: "เชื่อ Header 'X-Forwarded-*' ถ้าคุณต้องการไอพีที่ถูกต้องและ Uptime Kuma อยู่ข้างหลัง Nginx หรือ Apache, คุณควรเปิดใช้งาน",
|
||||
Examples: "ตัวอย่าง",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "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. ": "Access Token แบบมีอายุนานสามารถสร้างได้โดยคลิกชื่อบนโปรไฟล์ (ล่างซ้าย) และเลื่อนไปข้างล่างจากนั้นคลิก \"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 ในเมนู \"Developer Tools > Services\" ค้นหา \"notification\" เพื่อหาชื่ออุปกรณ์หรือชื่อโทรศัพท์",
|
||||
"Automations can optionally be triggered in Home Assistant:": "สามารถเลือกสั่งงานระบบอัตโนมัติได้ใน Home Assistant:",
|
||||
"Trigger type:": "ชนิดสิ่งกระตุ้น:",
|
||||
"Event type:": "ชนิดกิจกรรม:",
|
||||
"Event data:": "ข้อมูลกิจกรรม:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "จากนั้นเลือกการกระทำ, ตัวอย่าง เช่น เปลี่ยนเป็นไฟสีแดง",
|
||||
"Frontend Version": "เวอร์ชั่น Frontend",
|
||||
"Frontend Version do not match backend version!": "เวอร์ชั่น Frontend ไม่ตรงกับ Backend !",
|
||||
};
|
||||
|
@ -2,6 +2,8 @@ export default {
|
||||
languageName: "Türkçe",
|
||||
checkEverySecond: "{0} Saniyede bir kontrol et.",
|
||||
retryCheckEverySecond: "{0} Saniyede bir dene.",
|
||||
resendEveryXTimes: "Her {0} bir yeniden gönder",
|
||||
resendDisabled: "Yeniden gönderme devre dışı",
|
||||
retriesDescription: "Servisin kapalı olarak işaretlenmeden ve bir bildirim gönderilmeden önce maksimum yeniden deneme sayısı",
|
||||
ignoreTLSError: "HTTPS web siteleri için TLS/SSL hatasını yoksay",
|
||||
upsideDownModeDescription: "Servisin durumunu tersine çevirir. Servis çalışıyorsa kapalı olarak işaretler.",
|
||||
@ -72,6 +74,7 @@ export default {
|
||||
"Heartbeat Interval": "Servis Test Aralığı",
|
||||
Retries: "Yeniden deneme",
|
||||
"Heartbeat Retry Interval": "Sağlık Durumları Tekrar Deneme Sıklığı",
|
||||
"Resend Notification if Down X times consequently": "Sonuç olarak X kez düşerse bildirimi yeniden gönder",
|
||||
Advanced: "Gelişmiş",
|
||||
"Upside Down Mode": "Ters/Düz Modu",
|
||||
"Max. Redirects": "Maksimum Yönlendirme",
|
||||
@ -333,6 +336,8 @@ export default {
|
||||
info: "info",
|
||||
warning: "warning",
|
||||
danger: "danger",
|
||||
error: "hata",
|
||||
critical: "kritik",
|
||||
primary: "primary",
|
||||
light: "light",
|
||||
dark: "dark",
|
||||
@ -373,6 +378,13 @@ export default {
|
||||
smtpDkimHashAlgo: "Hash Algoritması (Opsiyonel)",
|
||||
smtpDkimheaderFieldNames: "İmzalanacak Başlık Anahtarları (Opsiyonel)",
|
||||
smtpDkimskipFields: "İmzalamayacak Başlık Anahtarları (Opsiyonel)",
|
||||
wayToGetPagerDutyKey: "Bunu Hizmet -> Hizmet Dizini -> (Bir hizmet seçin) -> Entegrasyonlar -> Entegrasyon ekle'ye giderek alabilirsiniz. Burada \"Events API V2\" için arama yapabilirsiniz. Daha fazla bilgi {0}",
|
||||
"Integration Key": "Entegrasyon Anahtarı",
|
||||
"Integration URL": "Entegrasyon URL'si",
|
||||
"Auto resolve or acknowledged": "Otomatik çözümleme veya onaylandı",
|
||||
"do nothing": "hiçbir şey yapma",
|
||||
"auto acknowledged": "otomatik onaylandı",
|
||||
"auto resolve": "otomatik çözümleme",
|
||||
gorush: "Gorush",
|
||||
alerta: "Alerta",
|
||||
alertaApiEndpoint: "API Endpoint",
|
||||
@ -399,6 +411,8 @@ export default {
|
||||
SignName: "SignName",
|
||||
"Sms template must contain parameters: ": "Sms şablonu parametreleri içermelidir:",
|
||||
"Bark Endpoint": "Bark Endpoint",
|
||||
"Bark Group": "Bark Group",
|
||||
"Bark Sound": "Bark Sound",
|
||||
WebHookUrl: "WebHookUrl",
|
||||
SecretKey: "SecretKey",
|
||||
"For safety, must use secret key": "Güvenlik için gizli anahtar kullanılmalıdır",
|
||||
@ -432,6 +446,7 @@ export default {
|
||||
Next: "Sonraki",
|
||||
"The slug is already taken. Please choose another slug.": "Slug zaten alındı. Lütfen başka bir slug seçin.",
|
||||
"No Proxy": "Proxy Yok",
|
||||
Authentication: "Kimlik doğrulama",
|
||||
"HTTP Basic Auth": "HTTP Temel Yetkilendirme",
|
||||
"New Status Page": "Yeni Durum Sayfası",
|
||||
"Page Not Found": "Sayfa bulunamadı",
|
||||
@ -443,6 +458,8 @@ export default {
|
||||
"Message:": "Mesaj:",
|
||||
"Don't know how to get the token? Please read the guide:": "Tokeni nasıl alacağınızı bilmiyor musunuz? Lütfen kılavuzu okuyun:",
|
||||
"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.": "Halihazırda Cloudflare Tüneli üzerinden bağlanıyorsanız mevcut bağlantı kesilebilir. Durdurmak istediğinden emin misin? Onaylamak için mevcut şifrenizi yazın.",
|
||||
"HTTP Headers": "HTTP Headers",
|
||||
"Trust Proxy": "Trust Proxy",
|
||||
"Other Software": "Diğer Yazılımlar",
|
||||
"For example: nginx, Apache and Traefik.": "Örneğin: nginx, Apache ve Traefik.",
|
||||
"Please read": "Lütfen oku",
|
||||
@ -455,6 +472,7 @@ export default {
|
||||
"Domain Name Expiry Notification": "Alan Adı Sona Erme Bildirimi",
|
||||
Proxy: "Proxy",
|
||||
"Date Created": "Tarih Oluşturuldu",
|
||||
HomeAssistant: "Home Assistant",
|
||||
onebotHttpAddress: "OneBot HTTP Adresi",
|
||||
onebotMessageType: "OneBot Mesaj Türü",
|
||||
onebotGroupMessage: "Grup",
|
||||
@ -467,6 +485,12 @@ export default {
|
||||
"Domain Names": "Alan isimleri",
|
||||
signedInDisp: "{0} olarak oturum açıldı",
|
||||
signedInDispDisabled: "Yetkilendirme Devre Dışı.",
|
||||
RadiusSecret: "Radius Secret",
|
||||
RadiusSecretDescription: "İstemci ve sunucu arasında paylaşılan gizli anahtar",
|
||||
RadiusCalledStationId: "Aranan İstasyon Kimliği",
|
||||
RadiusCalledStationIdDescription: "Aranan cihazın tanımlayıcısı",
|
||||
RadiusCallingStationId: "Arayan İstasyon Kimliği",
|
||||
RadiusCallingStationIdDescription: "Arayan cihazın tanımlayıcısı",
|
||||
"Certificate Expiry Notification": "Sertifika Sona Erme Bildirimi",
|
||||
"API Username": "API Kullanıc Adı",
|
||||
"API Key": "API Anahtarı",
|
||||
@ -475,7 +499,7 @@ export default {
|
||||
"Leave blank to use a shared sender number.": "Paylaşılan bir gönderen numarası kullanmak için boş bırakın.",
|
||||
"Octopush API Version": "Octopush API Sürümü",
|
||||
"Legacy Octopush-DM": "Eski Octopush-DM",
|
||||
"endpoint": "endpoint",
|
||||
endpoint: "uç nokta",
|
||||
octopushAPIKey: "Kontrol panelindeki HTTP API kimlik bilgilerinden \"API Key\"",
|
||||
octopushLogin: "Kontrol panelindeki HTTP API kimlik bilgilerinden \"Login\"",
|
||||
promosmsLogin: "API Oturum Açma Adı",
|
||||
@ -518,13 +542,38 @@ export default {
|
||||
"Go back to the previous page.": "Bir önceki sayfaya geri git.",
|
||||
"Coming Soon": "Yakında gelecek",
|
||||
wayToGetClickSendSMSToken: "API Kullanıcı Adı ve API Anahtarını {0} adresinden alabilirsiniz.",
|
||||
error: "hata",
|
||||
critical: "kritik",
|
||||
wayToGetPagerDutyKey: "Bunu şuraya giderek alabilirsiniz: Servis -> Servis Dizini -> (Bir servis seçin) -> Entegrasyonlar -> Entegrasyon ekle. Burada \"Events API V2\" için arama yapabilirsiniz. Daha fazla bilgi {0}",
|
||||
"Integration Key": "Entegrasyon Anahtarı",
|
||||
"Integration URL": "Entegrasyon URL",
|
||||
"Auto resolve or acknowledged": "Otomatik çözümleme veya onaylama",
|
||||
"do nothing": "hiçbir şey yapma",
|
||||
"auto acknowledged": "otomatik onaylama",
|
||||
"auto resolve": "otomatik çözümleme",
|
||||
"Connection String": "Bağlantı dizisi",
|
||||
Query: "Sorgu",
|
||||
settingsCertificateExpiry: "TLS Sertifikasının Geçerlilik Süresi",
|
||||
certificationExpiryDescription: "HTTPS Monitörleri, TLS sertifikasının süresi dolduğunda bildirimi tetikler:",
|
||||
"Setup Docker Host": "Docker Ana Bilgisayarını Kur",
|
||||
"Connection Type": "Bağlantı türü",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
deleteDockerHostMsg: "Bu docker ana bilgisayarını tüm monitörler için silmek istediğinizden emin misiniz?",
|
||||
socket: "Soket",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker Konteyneri",
|
||||
"Container Name / ID": "Konteyner Adı / Kimliği",
|
||||
"Docker Host": "Docker Ana Bilgisayarı",
|
||||
"Docker Hosts": "Docker Ana Bilgisayarları",
|
||||
"ntfy Topic": "ntfy Konu",
|
||||
"Domain": "Domain",
|
||||
"Workstation": "İş İstasyonu",
|
||||
disableCloudflaredNoAuthMsg: "Yetki Yok modundasınız, şifre gerekli değil.",
|
||||
trustProxyDescription: "'X-Forwarded-*' başlıklarına güvenin. Doğru istemci IP'sini almak istiyorsanız ve Uptime Kuma'nız Nginx veya Apache'nin arkasındaysa, bunu etkinleştirmelisiniz.",
|
||||
wayToGetLineNotifyToken: "{0} adresinden bir erişim jetonu alabilirsiniz.",
|
||||
Examples: "Örnekler",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "Long-Lived Erişim Anahtarı",
|
||||
"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 Erişim Anahtarı, profil adınıza (sol altta) tıklayarak ve aşağıya kaydırarak ve ardından Anahtar Oluştur'a tıklayarak oluşturulabilir. ",
|
||||
"Notification Service": "Bildirim Hizmeti",
|
||||
"default: notify all devices": "varsayılan: tüm cihazları bilgilendir",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Cihazınızın/telefonunuzun adını bulmak için Home Assistant'ta \"Geliştirici Araçları > Hizmetler\" \"bildirim\" araması altında bir Bildirim Hizmetleri listesi bulunabilir.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Otomasyonlar isteğe bağlı olarak Home Assistant'ta tetiklenebilir:",
|
||||
"Trigger type:": "Trigger tipi:",
|
||||
"Event type:": "Etkinlik tipi:",
|
||||
"Event data:": "Etkinlik verileri:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Ardından bir eylem seçin, örneğin RGB ışığının kırmızı olduğu sahneyi değiştirin.",
|
||||
"Frontend Version": "Frontend Sürümü",
|
||||
"Frontend Version do not match backend version!": "Frontend Sürümü, backend sürümüyle eşleşmiyor!",
|
||||
};
|
||||
|
@ -404,6 +404,8 @@ export default {
|
||||
TemplateCode: "TemplateCode",
|
||||
SignName: "SignName",
|
||||
"Bark Endpoint": "Bark 接入点",
|
||||
"Bark Group": "Bark 群组",
|
||||
"Bark Sound": "Bark 铃声",
|
||||
"Device Token": "Apple Device Token",
|
||||
Platform: "平台",
|
||||
iOS: "iOS",
|
||||
@ -538,6 +540,45 @@ export default {
|
||||
settingsCertificateExpiry: "TLS 证书过期通知",
|
||||
certificationExpiryDescription: "HTTPS 监控项发现被监控目标的 TLS 证书剩余有效期少于以下天数时将发出通知:",
|
||||
"ntfy Topic": "ntfy 主题",
|
||||
"Domain": "域名",
|
||||
"Workstation": "工作站",
|
||||
Domain: "域名",
|
||||
Workstation: "工作站",
|
||||
resendEveryXTimes: "每 {0} 次失败则重复发送一次",
|
||||
resendDisabled: "为 0 时禁用重复发送",
|
||||
"Resend Notification if Down X times consequently": "连续失败时重复发送通知的间隔次数",
|
||||
"HTTP Headers": "HTTP 头",
|
||||
"Trust Proxy": "可信的代理类字段",
|
||||
HomeAssistant: "Home Assistant",
|
||||
RadiusSecret: "Radius 共享机密",
|
||||
RadiusSecretDescription: "客户端和服务器之间共享的密钥",
|
||||
RadiusCalledStationId: "NAS 网络访问服务器号码(Called Station Id)",
|
||||
RadiusCalledStationIdDescription: "所访问的服务器的标识",
|
||||
RadiusCallingStationId: "呼叫方号码(Calling Station Id)",
|
||||
RadiusCallingStationIdDescription: "发出请求的设备的标识",
|
||||
"Setup Docker Host": "配置 Docker 宿主信息",
|
||||
"Connection Type": "连接方式",
|
||||
"Docker Daemon": "Docker 守护进程",
|
||||
deleteDockerHostMsg: "您确定您要删除此 Docker 宿主设置吗?这会影响所有 Docker 监控项",
|
||||
socket: "Socket",
|
||||
tcp: "TCP / HTTP",
|
||||
"Docker Container": "Docker 容器",
|
||||
"Container Name / ID": "容器名称 / ID",
|
||||
"Docker Host": "Docker 宿主",
|
||||
"Docker Hosts": "Docker 宿主",
|
||||
disableCloudflaredNoAuthMsg: "您现在正处于 No Auth 模式,无需输入密码",
|
||||
trustProxyDescription: "信任 'X-Forwarded-*' 头。如果您的 Uptime Kuma 是通过 Nginx 或 Apache 等反代服务对外提供访问的话,则您应当启用本功能以获取正确的客户端 IP。",
|
||||
wayToGetLineNotifyToken: "您可以在 {0} 获取 Access token",
|
||||
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. ": "长期访问令牌可通过点击左下角您的用户名,滚动到页面底部并点击 Create Token 按钮获取。",
|
||||
"Notification Service": "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 中的 Developer Tools > Services 通过搜索您的设备或手机的名称来获得。",
|
||||
"Automations can optionally be triggered in Home Assistant:": "可以在 Home Assistant 使用下列模板设置自动化操作的触发条件:",
|
||||
"Trigger type:": "触发类型:",
|
||||
"Event type:": "事件类型:",
|
||||
"Event data:": "事件数据:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "然后您可以选择关联操作,例如切换到 RGB 灯发出红光的场景",
|
||||
"Frontend Version": "前端版本",
|
||||
"Frontend Version do not match backend version!": "前端版本与后端版本不符!",
|
||||
};
|
||||
|
@ -408,6 +408,8 @@ export default {
|
||||
SignName: "SignName",
|
||||
"Sms template must contain parameters: ": "Sms 範本必須包含參數:",
|
||||
"Bark Endpoint": "Bark 端點",
|
||||
"Bark Group": "Bark 群組",
|
||||
"Bark Sound": "Bark 鈴聲",
|
||||
WebHookUrl: "WebHookUrl",
|
||||
SecretKey: "SecretKey",
|
||||
"For safety, must use secret key": "為了安全起見,必須使用秘密金鑰",
|
||||
|
@ -77,7 +77,7 @@
|
||||
|
||||
<!-- Mobile Only -->
|
||||
<div v-if="$root.isMobile" style="width: 100%; height: 60px;" />
|
||||
<nav v-if="$root.isMobile" class="bottom-nav">
|
||||
<nav v-if="$root.isMobile && $root.loggedIn" class="bottom-nav">
|
||||
<router-link to="/dashboard" class="nav-link">
|
||||
<div><font-awesome-icon icon="tachometer-alt" /></div>
|
||||
{{ $t("Dashboard") }}
|
||||
|
@ -39,6 +39,7 @@ export default {
|
||||
uptimeList: { },
|
||||
tlsInfoList: {},
|
||||
notificationList: [],
|
||||
dockerHostList: [],
|
||||
statusPageListLoaded: false,
|
||||
statusPageList: [],
|
||||
proxyList: [],
|
||||
@ -147,6 +148,10 @@ export default {
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("dockerHostList", (data) => {
|
||||
this.dockerHostList = data;
|
||||
});
|
||||
|
||||
socket.on("heartbeat", (data) => {
|
||||
if (! (data.monitorID in this.heartbeatList)) {
|
||||
this.heartbeatList[data.monitorID] = [];
|
||||
|
@ -27,6 +27,9 @@
|
||||
<option value="dns">
|
||||
DNS
|
||||
</option>
|
||||
<option value="docker">
|
||||
{{ $t("Docker Container") }}
|
||||
</option>
|
||||
</optgroup>
|
||||
|
||||
<optgroup label="Passive Monitor Type">
|
||||
@ -45,6 +48,12 @@
|
||||
<option value="sqlserver">
|
||||
SQL Server
|
||||
</option>
|
||||
<option value="postgres">
|
||||
PostgreSQL
|
||||
</option>
|
||||
<option value="radius">
|
||||
Radius
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
@ -81,8 +90,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Hostname -->
|
||||
<!-- TCP Port / Ping / DNS / Steam / MQTT only -->
|
||||
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'mqtt'" class="my-3">
|
||||
<!-- 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 === 'mqtt' || monitor.type === 'radius'" 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="`${ipRegexPattern}|${hostnameRegexPattern}`" required>
|
||||
</div>
|
||||
@ -138,6 +147,34 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Docker Container Name / ID -->
|
||||
<!-- For Docker Type -->
|
||||
<div v-if="monitor.type === 'docker'" class="my-3">
|
||||
<label for="docker_container" class="form-label">{{ $t("Container Name / ID") }}</label>
|
||||
<input id="docker_container" v-model="monitor.docker_container" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<!-- Docker Host -->
|
||||
<!-- For Docker Type -->
|
||||
<div v-if="monitor.type === 'docker'" class="my-3">
|
||||
<h2 class="mb-2">{{ $t("Docker Host") }}</h2>
|
||||
<p v-if="$root.dockerHostList.length === 0">
|
||||
{{ $t("Not available, please setup.") }}
|
||||
</p>
|
||||
|
||||
<div v-else class="mb-3">
|
||||
<label for="docker-host" class="form-label">{{ $t("Docker Host") }}</label>
|
||||
<select id="docket-host" v-model="monitor.docker_host" class="form-select">
|
||||
<option v-for="host in $root.dockerHostList" :key="host.id" :value="host.id">{{ host.name }}</option>
|
||||
</select>
|
||||
<a href="#" @click="$refs.dockerHostDialog.show(monitor.docker_host)">{{ $t("Edit") }}</a>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary me-2" type="button" @click="$refs.dockerHostDialog.show()">
|
||||
{{ $t("Setup Docker Host") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- MQTT -->
|
||||
<!-- For MQTT Type -->
|
||||
<template v-if="monitor.type === 'mqtt'">
|
||||
@ -168,15 +205,51 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- SQL Server -->
|
||||
<template v-if="monitor.type === 'sqlserver'">
|
||||
<template v-if="monitor.type === 'radius'">
|
||||
<div class="my-3">
|
||||
<label for="sqlserverConnectionString" class="form-label">SQL Server {{ $t("Connection String") }}</label>
|
||||
<input id="sqlserverConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
<label for="radius_username" class="form-label">Radius {{ $t("Username") }}</label>
|
||||
<input id="radius_username" v-model="monitor.radiusUsername" type="text" class="form-control" required />
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="radius_password" class="form-label">Radius {{ $t("Password") }}</label>
|
||||
<input id="radius_password" v-model="monitor.radiusPassword" type="password" class="form-control" required />
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="radius_secret" class="form-label">{{ $t("RadiusSecret") }}</label>
|
||||
<input id="radius_secret" v-model="monitor.radiusSecret" type="password" class="form-control" required />
|
||||
<div class="form-text"> {{ $t( "RadiusSecretDescription") }} </div>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="radius_called_station_id" class="form-label">{{ $t("RadiusCalledStationId") }}</label>
|
||||
<input id="radius_called_station_id" v-model="monitor.radiusCalledStationId" type="text" class="form-control" required />
|
||||
<div class="form-text"> {{ $t( "RadiusCalledStationIdDescription") }} </div>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="radius_calling_station_id" class="form-label">{{ $t("RadiusCallingStationId") }}</label>
|
||||
<input id="radius_calling_station_id" v-model="monitor.radiusCallingStationId" type="text" class="form-control" required />
|
||||
<div class="form-text"> {{ $t( "RadiusCallingStationIdDescription") }} </div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- SQL Server and PostgreSQL -->
|
||||
<template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres'">
|
||||
<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" placeholder="Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>">
|
||||
</template>
|
||||
<template v-if="monitor.type === 'postgres'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="postgres://username:password@host:port/database">
|
||||
</template>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<label for="sqlserverQuery" class="form-label">SQL Server {{ $t("Query") }}</label>
|
||||
<textarea id="sqlserverQuery" v-model="monitor.databaseQuery" class="form-control" placeholder="Example: select getdate()"></textarea>
|
||||
<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>
|
||||
|
||||
@ -202,6 +275,15 @@
|
||||
<input id="retry-interval" v-model="monitor.retryInterval" type="number" class="form-control" required min="20" step="1">
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="resend-interval" class="form-label">
|
||||
{{ $t("Resend Notification if Down X times consequently") }}
|
||||
<span v-if="monitor.resendInterval > 0">({{ $t("resendEveryXTimes", [ monitor.resendInterval ]) }})</span>
|
||||
<span v-else>({{ $t("resendDisabled") }})</span>
|
||||
</label>
|
||||
<input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="0" step="1">
|
||||
</div>
|
||||
|
||||
<h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
|
||||
|
||||
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' " class="my-3 form-check">
|
||||
@ -415,6 +497,7 @@
|
||||
</form>
|
||||
|
||||
<NotificationDialog ref="notificationDialog" @added="addedNotification" />
|
||||
<DockerHostDialog ref="dockerHostDialog" @added="addedDockerHost" />
|
||||
<ProxyDialog ref="proxyDialog" @added="addedProxy" />
|
||||
</div>
|
||||
</transition>
|
||||
@ -425,6 +508,7 @@ import VueMultiselect from "vue-multiselect";
|
||||
import { useToast } from "vue-toastification";
|
||||
import CopyableInput from "../components/CopyableInput.vue";
|
||||
import NotificationDialog from "../components/NotificationDialog.vue";
|
||||
import DockerHostDialog from "../components/DockerHostDialog.vue";
|
||||
import ProxyDialog from "../components/ProxyDialog.vue";
|
||||
import TagsManager from "../components/TagsManager.vue";
|
||||
import { genSecret, isDev } from "../util.ts";
|
||||
@ -436,6 +520,7 @@ export default {
|
||||
ProxyDialog,
|
||||
CopyableInput,
|
||||
NotificationDialog,
|
||||
DockerHostDialog,
|
||||
TagsManager,
|
||||
VueMultiselect,
|
||||
},
|
||||
@ -584,7 +669,7 @@ export default {
|
||||
method: "GET",
|
||||
interval: 60,
|
||||
retryInterval: this.interval,
|
||||
databaseConnectionString: "Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>",
|
||||
resendInterval: 0,
|
||||
maxretries: 0,
|
||||
notificationIDList: {},
|
||||
ignoreTls: false,
|
||||
@ -594,6 +679,8 @@ export default {
|
||||
accepted_statuscodes: [ "200-299" ],
|
||||
dns_resolve_type: "A",
|
||||
dns_resolve_server: "1.1.1.1",
|
||||
docker_container: "",
|
||||
docker_host: null,
|
||||
proxyId: null,
|
||||
mqttUsername: "",
|
||||
mqttPassword: "",
|
||||
@ -721,6 +808,12 @@ export default {
|
||||
addedProxy(id) {
|
||||
this.monitor.proxyId = id;
|
||||
},
|
||||
|
||||
// Added a Docker Host Event
|
||||
// Enable it if the Docker Host is added in EditMonitor.vue
|
||||
addedDockerHost(id) {
|
||||
this.monitor.docker_host = id;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -89,6 +89,9 @@ export default {
|
||||
"monitor-history": {
|
||||
title: this.$t("Monitor History"),
|
||||
},
|
||||
"docker-hosts": {
|
||||
title: this.$t("Docker Hosts"),
|
||||
},
|
||||
security: {
|
||||
title: this.$t("Security"),
|
||||
},
|
||||
@ -153,6 +156,10 @@ export default {
|
||||
this.settings.tlsExpiryNotifyDays = [ 7, 14, 21 ];
|
||||
}
|
||||
|
||||
if (this.settings.trustProxy === undefined) {
|
||||
this.settings.trustProxy = false;
|
||||
}
|
||||
|
||||
this.settingsLoaded = true;
|
||||
});
|
||||
},
|
||||
|
@ -25,6 +25,7 @@ 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";
|
||||
import DockerHosts from "./components/settings/Docker.vue";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -95,6 +96,10 @@ const routes = [
|
||||
path: "monitor-history",
|
||||
component: MonitorHistory,
|
||||
},
|
||||
{
|
||||
path: "docker-hosts",
|
||||
component: DockerHosts,
|
||||
},
|
||||
{
|
||||
path: "security",
|
||||
component: Security,
|
||||
|
Loading…
Reference in New Issue
Block a user