mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-16 09:26:48 +02:00
Merge branch 'louislam:master' into master
This commit is contained in:
commit
6eb82400fe
76 changed files with 5331 additions and 3957 deletions
22
.github/workflows/stale-bot.yml
vendored
22
.github/workflows/stale-bot.yml
vendored
|
@ -1,22 +0,0 @@
|
||||||
name: 'Automatically close stale issues and PRs'
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * *'
|
|
||||||
#Run once a day at midnight
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v4
|
|
||||||
with:
|
|
||||||
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
|
||||||
stale-pr-message: 'We are clearing up our old Pull Requests and yours has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
|
||||||
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
|
|
||||||
close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
|
|
||||||
days-before-stale: 180
|
|
||||||
days-before-close: 7
|
|
||||||
exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,'
|
|
||||||
exempt-pr-labels: 'awaiting-approval,work-in-progress,enhancement,'
|
|
||||||
exempt-issue-assignees: 'louislam'
|
|
||||||
exempt-pr-assignees: 'louislam'
|
|
|
@ -27,9 +27,20 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
|
||||||
|
|
||||||
## Can I create a pull request for Uptime Kuma?
|
## Can I create a pull request for Uptime Kuma?
|
||||||
|
|
||||||
Generally, if the pull request is working fine, and it does not affect any existing logic, workflow and performance, I will merge into the master branch once it is tested.
|
⚠️ 2022-03-02 Update:
|
||||||
|
|
||||||
If you are not sure whether I will accept your pull request, feel free to create an empty pull request draft first.
|
Since I found that merging pull requests is a pretty heavy task for me, I try to rearrange it.
|
||||||
|
|
||||||
|
✅ Accept:
|
||||||
|
- Bug/Security fix
|
||||||
|
- Translations
|
||||||
|
- Adding notification providers
|
||||||
|
|
||||||
|
❌ Avoid:
|
||||||
|
- Large pull requests
|
||||||
|
- New big features
|
||||||
|
|
||||||
|
My long story here: https://www.reddit.com/r/UptimeKuma/comments/t1t6or/comment/hynyijx/
|
||||||
|
|
||||||
### Recommended Pull Request Guideline
|
### Recommended Pull Request Guideline
|
||||||
|
|
||||||
|
@ -43,42 +54,6 @@ If you are not sure whether I will accept your pull request, feel free to create
|
||||||
1. Write a proper description
|
1. Write a proper description
|
||||||
1. Click "Change to draft"
|
1. Click "Change to draft"
|
||||||
|
|
||||||
### Pull Request Examples
|
|
||||||
|
|
||||||
Here are some example situations in the past.
|
|
||||||
|
|
||||||
#### ✅ High - Medium Priority
|
|
||||||
|
|
||||||
Easy to review, no breaking change and not touching the existing code
|
|
||||||
|
|
||||||
- Add a new notification
|
|
||||||
- Add a chart
|
|
||||||
- Fix a bug
|
|
||||||
- Translations
|
|
||||||
- Add a independent new feature
|
|
||||||
|
|
||||||
#### *️⃣ Requires one more reviewer
|
|
||||||
|
|
||||||
I do not have such knowledge to test it.
|
|
||||||
|
|
||||||
- Add k8s supports
|
|
||||||
|
|
||||||
#### ⚠ Low Priority - Harsh Mode
|
|
||||||
|
|
||||||
Some pull requests are required to modify the core. To be honest, I do not want anyone to try to do that, because it would spend a lot of your time. I will review your pull request harshly. Also, you may need to write a lot of unit tests to ensure that there is no breaking change.
|
|
||||||
|
|
||||||
- Touch large parts of code of any very important features
|
|
||||||
- Touch monitoring logic
|
|
||||||
- Drop a table or drop a column for any reason
|
|
||||||
- Touch the entry point of Docker or Node.js
|
|
||||||
- Modify auth
|
|
||||||
|
|
||||||
#### *️⃣ Low Priority
|
|
||||||
|
|
||||||
It changed my current workflow and require further studies.
|
|
||||||
|
|
||||||
- Change my release approach
|
|
||||||
|
|
||||||
#### ❌ Won't Merge
|
#### ❌ Won't Merge
|
||||||
|
|
||||||
- Any breaking changes
|
- Any breaking changes
|
||||||
|
@ -227,7 +202,7 @@ https://github.com/louislam/uptime-kuma/issues?q=sort%3Aupdated-desc
|
||||||
1. `npm run build-docker`
|
1. `npm run build-docker`
|
||||||
1. `git push`
|
1. `git push`
|
||||||
1. Publish the release note as 1.X.X
|
1. Publish the release note as 1.X.X
|
||||||
1. `npm run upload-artifacts`
|
1. `npm run upload-artifacts` with env vars VERSION=1.X.X;GITHUB_TOKEN=XXXX
|
||||||
1. SSH to demo site server and update to 1.X.X
|
1. SSH to demo site server and update to 1.X.X
|
||||||
|
|
||||||
Checking:
|
Checking:
|
||||||
|
|
|
@ -115,7 +115,7 @@ Telegram Notification Sample:
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
* I was looking for a self-hosted monitoring tool like "Uptime Robot", but it is hard to find a suitable one. One of the close ones is statping. Unfortunately, it is not stable and unmaintained.
|
* I was looking for a self-hosted monitoring tool like "Uptime Robot", but it is hard to find a suitable one. One of the close ones is statping. Unfortunately, it is not stable and no longer maintained.
|
||||||
* Want to build a fancy UI.
|
* Want to build a fancy UI.
|
||||||
* Learn Vue 3 and vite.js.
|
* Learn Vue 3 and vite.js.
|
||||||
* Show the power of Bootstrap 5.
|
* Show the power of Bootstrap 5.
|
||||||
|
@ -144,4 +144,4 @@ If you want to translate Uptime Kuma into your language, please read: https://gi
|
||||||
|
|
||||||
If you want to modify Uptime Kuma, this guideline may be useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md
|
If you want to modify Uptime Kuma, this guideline may be useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md
|
||||||
|
|
||||||
English proofreading is needed too because my grammar is not that great, sadly. Feel free to correct my grammar in this README, source code, or wiki.
|
Unfortunately, English proofreading is needed too because my grammar is not that great. Feel free to correct my grammar in this README, source code, or wiki.
|
||||||
|
|
31
db/patch-status-page.sql
Normal file
31
db/patch-status-page.sql
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TABLE [status_page](
|
||||||
|
[id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
[slug] VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
[title] VARCHAR(255) NOT NULL,
|
||||||
|
[description] TEXT,
|
||||||
|
[icon] VARCHAR(255) NOT NULL,
|
||||||
|
[theme] VARCHAR(30) NOT NULL,
|
||||||
|
[published] BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
[search_engine_index] BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
[show_tags] BOOLEAN NOT NULL DEFAULT 0,
|
||||||
|
[password] VARCHAR,
|
||||||
|
[created_date] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
[modified_date] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX [slug] ON [status_page]([slug]);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE [status_page_cname](
|
||||||
|
[id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
[status_page_id] INTEGER NOT NULL REFERENCES [status_page]([id]) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
[domain] VARCHAR NOT NULL UNIQUE
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE incident ADD status_page_id INTEGER;
|
||||||
|
ALTER TABLE [group] ADD status_page_id INTEGER;
|
||||||
|
|
||||||
|
COMMIT;
|
|
@ -1,8 +1,8 @@
|
||||||
# DON'T UPDATE TO alpine3.13, 1.14, see #41.
|
# DON'T UPDATE TO alpine3.13, 1.14, see #41.
|
||||||
FROM node:14-alpine3.12
|
FROM node:16-alpine3.12
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install apprise, iputils for non-root ping, setpriv
|
# 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 && \
|
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.6 && \
|
pip3 --no-cache-dir install apprise==0.9.7 && \
|
||||||
rm -rf /root/.cache
|
rm -rf /root/.cache
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# DON'T UPDATE TO node:14-bullseye-slim, see #372.
|
# DON'T UPDATE TO node:14-bullseye-slim, see #372.
|
||||||
# If the image changed, the second stage image should be changed too
|
# If the image changed, the second stage image should be changed too
|
||||||
FROM node:14-buster-slim
|
FROM node:16-buster-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install Apprise, add sqlite3 cli for debugging in the future, iputils-ping for ping, util-linux for setpriv
|
# Install Apprise, add sqlite3 cli for debugging in the future, iputils-ping for ping, util-linux for setpriv
|
||||||
|
@ -8,5 +8,5 @@ WORKDIR /app
|
||||||
RUN apt update && \
|
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 \
|
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 && \
|
sqlite3 iputils-ping util-linux dumb-init && \
|
||||||
pip3 --no-cache-dir install apprise==0.9.6 && \
|
pip3 --no-cache-dir install apprise==0.9.7 && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
5938
package-lock.json
generated
5938
package-lock.json
generated
File diff suppressed because it is too large
Load diff
13
package.json
13
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.11.3",
|
"version": "1.12.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -30,13 +30,13 @@
|
||||||
"build-docker": "npm run build && npm run build-docker-debian && npm run build-docker-alpine",
|
"build-docker": "npm run build && npm run build-docker-debian && npm run build-docker-alpine",
|
||||||
"build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push",
|
"build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push",
|
||||||
"build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push",
|
"build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push",
|
||||||
"build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.11.3-alpine --target release . --push",
|
"build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.12.1-alpine --target release . --push",
|
||||||
"build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.11.3 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.11.3-debian --target release . --push",
|
"build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.12.1 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.12.1-debian --target release . --push",
|
||||||
"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": "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-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-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
|
||||||
"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",
|
"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.11.3 && npm ci --production && npm run download-dist",
|
"setup": "git checkout 1.12.1 && npm ci --production && npm run download-dist",
|
||||||
"download-dist": "node extra/download-dist.js",
|
"download-dist": "node extra/download-dist.js",
|
||||||
"update-version": "node extra/update-version.js",
|
"update-version": "node extra/update-version.js",
|
||||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||||
|
@ -61,19 +61,20 @@
|
||||||
"@louislam/sqlite3": "~6.0.1",
|
"@louislam/sqlite3": "~6.0.1",
|
||||||
"@popperjs/core": "~2.10.2",
|
"@popperjs/core": "~2.10.2",
|
||||||
"args-parser": "~1.3.0",
|
"args-parser": "~1.3.0",
|
||||||
"axios": "~0.21.4",
|
"axios": "~0.26.0",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
"bootstrap": "5.1.3",
|
"bootstrap": "5.1.3",
|
||||||
"bree": "~7.1.0",
|
"bree": "~7.1.0",
|
||||||
"chardet": "^1.3.0",
|
"chardet": "^1.3.0",
|
||||||
"chart.js": "~3.6.0",
|
"chart.js": "~3.6.0",
|
||||||
"chartjs-adapter-dayjs": "~1.0.0",
|
"chartjs-adapter-dayjs": "~1.0.0",
|
||||||
"check-password-strength": "^2.0.3",
|
"check-password-strength": "^2.0.5",
|
||||||
"command-exists": "~1.2.9",
|
"command-exists": "~1.2.9",
|
||||||
"compare-versions": "~3.6.0",
|
"compare-versions": "~3.6.0",
|
||||||
"dayjs": "~1.10.7",
|
"dayjs": "~1.10.7",
|
||||||
"express": "~4.17.1",
|
"express": "~4.17.1",
|
||||||
"express-basic-auth": "~1.2.0",
|
"express-basic-auth": "~1.2.0",
|
||||||
|
"favico.js": "^0.3.10",
|
||||||
"form-data": "~4.0.0",
|
"form-data": "~4.0.0",
|
||||||
"http-graceful-shutdown": "~3.1.5",
|
"http-graceful-shutdown": "~3.1.5",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const { setSetting } = require("./util-server");
|
const { setSetting, setting } = require("./util-server");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
|
const compareVersions = require("compare-versions");
|
||||||
|
|
||||||
exports.version = require("../package.json").version;
|
exports.version = require("../package.json").version;
|
||||||
exports.latestVersion = null;
|
exports.latestVersion = null;
|
||||||
|
@ -16,6 +17,19 @@ exports.startInterval = () => {
|
||||||
res.data.slow = "1000.0.0";
|
res.data.slow = "1000.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!await setting("checkUpdate")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let checkBeta = await setting("checkBeta");
|
||||||
|
|
||||||
|
if (checkBeta && res.data.beta) {
|
||||||
|
if (compareVersions.compare(res.data.beta, res.data.beta, ">")) {
|
||||||
|
exports.latestVersion = res.data.beta;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (res.data.slow) {
|
if (res.data.slow) {
|
||||||
exports.latestVersion = res.data.slow;
|
exports.latestVersion = res.data.slow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ class Database {
|
||||||
"patch-2fa-invalidate-used-token.sql": true,
|
"patch-2fa-invalidate-used-token.sql": true,
|
||||||
"patch-notification_sent_history.sql": true,
|
"patch-notification_sent_history.sql": true,
|
||||||
"patch-monitor-basic-auth.sql": true,
|
"patch-monitor-basic-auth.sql": true,
|
||||||
|
"patch-status-page.sql": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,6 +171,7 @@ class Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.patch2();
|
await this.patch2();
|
||||||
|
await this.migrateNewStatusPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -211,6 +213,70 @@ class Database {
|
||||||
await setSetting("databasePatchedFiles", databasePatchedFiles);
|
await setSetting("databasePatchedFiles", databasePatchedFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate status page value in setting to "status_page" table
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
static async migrateNewStatusPage() {
|
||||||
|
let title = await setting("title");
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
console.log("Migrating Status Page");
|
||||||
|
|
||||||
|
let statusPageCheck = await R.findOne("status_page", " slug = 'default' ");
|
||||||
|
|
||||||
|
if (statusPageCheck !== null) {
|
||||||
|
console.log("Migrating Status Page - Skip, default slug record is already existing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusPage = R.dispense("status_page");
|
||||||
|
statusPage.slug = "default";
|
||||||
|
statusPage.title = title;
|
||||||
|
statusPage.description = await setting("description");
|
||||||
|
statusPage.icon = await setting("icon");
|
||||||
|
statusPage.theme = await setting("statusPageTheme");
|
||||||
|
statusPage.published = !!await setting("statusPagePublished");
|
||||||
|
statusPage.search_engine_index = !!await setting("searchEngineIndex");
|
||||||
|
statusPage.show_tags = !!await setting("statusPageTags");
|
||||||
|
statusPage.password = null;
|
||||||
|
|
||||||
|
if (!statusPage.title) {
|
||||||
|
statusPage.title = "My Status Page";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!statusPage.icon) {
|
||||||
|
statusPage.icon = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!statusPage.theme) {
|
||||||
|
statusPage.theme = "light";
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = await R.store(statusPage);
|
||||||
|
|
||||||
|
await R.exec("UPDATE incident SET status_page_id = ? WHERE status_page_id IS NULL", [
|
||||||
|
id
|
||||||
|
]);
|
||||||
|
|
||||||
|
await R.exec("UPDATE [group] SET status_page_id = ? WHERE status_page_id IS NULL", [
|
||||||
|
id
|
||||||
|
]);
|
||||||
|
|
||||||
|
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
|
||||||
|
|
||||||
|
// Migrate Entry Page if it is status page
|
||||||
|
let entryPage = await setting("entryPage");
|
||||||
|
|
||||||
|
if (entryPage === "statusPage") {
|
||||||
|
await setSetting("entryPage", "statusPage-default", "general");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Migrating Status Page - Done");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used it patch2() only
|
* Used it patch2() only
|
||||||
* @param sqlFilename
|
* @param sqlFilename
|
||||||
|
|
|
@ -3,12 +3,12 @@ const { R } = require("redbean-node");
|
||||||
|
|
||||||
class Group extends BeanModel {
|
class Group extends BeanModel {
|
||||||
|
|
||||||
async toPublicJSON() {
|
async toPublicJSON(showTags = false) {
|
||||||
let monitorBeanList = await this.getMonitorList();
|
let monitorBeanList = await this.getMonitorList();
|
||||||
let monitorList = [];
|
let monitorList = [];
|
||||||
|
|
||||||
for (let bean of monitorBeanList) {
|
for (let bean of monitorBeanList) {
|
||||||
monitorList.push(await bean.toPublicJSON());
|
monitorList.push(await bean.toPublicJSON(showTags));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -24,18 +24,22 @@ const apicache = require("../modules/apicache");
|
||||||
class Monitor extends BeanModel {
|
class Monitor extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a object that ready to parse to JSON for public
|
* Return an object that ready to parse to JSON for public
|
||||||
* Only show necessary data to public
|
* Only show necessary data to public
|
||||||
*/
|
*/
|
||||||
async toPublicJSON() {
|
async toPublicJSON(showTags = false) {
|
||||||
return {
|
let obj = {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
};
|
};
|
||||||
|
if (showTags) {
|
||||||
|
obj.tags = await this.getTags();
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a object that ready to parse to JSON
|
* Return an object that ready to parse to JSON
|
||||||
*/
|
*/
|
||||||
async toJSON() {
|
async toJSON() {
|
||||||
|
|
||||||
|
@ -49,7 +53,7 @@ class Monitor extends BeanModel {
|
||||||
notificationIDList[bean.notification_id] = true;
|
notificationIDList[bean.notification_id] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags = await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]);
|
const tags = await this.getTags();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
|
@ -82,6 +86,10 @@ class Monitor extends BeanModel {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTags() {
|
||||||
|
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode user and password to Base64 encoding
|
* Encode user and password to Base64 encoding
|
||||||
* for HTTP "basic" auth, as per RFC-7617
|
* for HTTP "basic" auth, as per RFC-7617
|
||||||
|
@ -119,6 +127,19 @@ class Monitor extends BeanModel {
|
||||||
|
|
||||||
const beat = async () => {
|
const beat = async () => {
|
||||||
|
|
||||||
|
let beatInterval = this.interval;
|
||||||
|
|
||||||
|
if (! beatInterval) {
|
||||||
|
beatInterval = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (demoMode) {
|
||||||
|
if (beatInterval < 20) {
|
||||||
|
console.log("beat interval too low, reset to 20s");
|
||||||
|
beatInterval = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Expose here for prometheus update
|
// Expose here for prometheus update
|
||||||
// undefined if not https
|
// undefined if not https
|
||||||
let tlsInfo = undefined;
|
let tlsInfo = undefined;
|
||||||
|
@ -303,7 +324,7 @@ class Monitor extends BeanModel {
|
||||||
} else {
|
} else {
|
||||||
// No need to insert successful heartbeat for push type, so end here
|
// No need to insert successful heartbeat for push type, so end here
|
||||||
retries = 0;
|
retries = 0;
|
||||||
this.heartbeatInterval = setTimeout(beat, this.interval * 1000);
|
this.heartbeatInterval = setTimeout(beat, beatInterval * 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,8 +398,6 @@ class Monitor extends BeanModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let beatInterval = this.interval;
|
|
||||||
|
|
||||||
debug(`[${this.name}] Check isImportant`);
|
debug(`[${this.name}] Check isImportant`);
|
||||||
let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status);
|
let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status);
|
||||||
|
|
||||||
|
@ -422,14 +441,6 @@ class Monitor extends BeanModel {
|
||||||
previousBeat = bean;
|
previousBeat = bean;
|
||||||
|
|
||||||
if (! this.isStop) {
|
if (! this.isStop) {
|
||||||
|
|
||||||
if (demoMode) {
|
|
||||||
if (beatInterval < 20) {
|
|
||||||
console.log("beat interval too low, reset to 20s");
|
|
||||||
beatInterval = 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`[${this.name}] SetTimeout for next check.`);
|
debug(`[${this.name}] SetTimeout for next check.`);
|
||||||
this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000);
|
this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000);
|
||||||
} else {
|
} else {
|
||||||
|
|
60
server/model/status_page.js
Normal file
60
server/model/status_page.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
|
||||||
|
class StatusPage extends BeanModel {
|
||||||
|
|
||||||
|
static async sendStatusPageList(io, socket) {
|
||||||
|
let result = {};
|
||||||
|
|
||||||
|
let list = await R.findAll("status_page", " ORDER BY title ");
|
||||||
|
|
||||||
|
for (let item of list) {
|
||||||
|
result[item.id] = await item.toJSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
io.to(socket.userID).emit("statusPageList", result);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
async toJSON() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
slug: this.slug,
|
||||||
|
title: this.title,
|
||||||
|
description: this.description,
|
||||||
|
icon: this.getIcon(),
|
||||||
|
theme: this.theme,
|
||||||
|
published: !!this.published,
|
||||||
|
showTags: !!this.show_tags,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async toPublicJSON() {
|
||||||
|
return {
|
||||||
|
slug: this.slug,
|
||||||
|
title: this.title,
|
||||||
|
description: this.description,
|
||||||
|
icon: this.getIcon(),
|
||||||
|
theme: this.theme,
|
||||||
|
published: !!this.published,
|
||||||
|
showTags: !!this.show_tags,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static async slugToID(slug) {
|
||||||
|
return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [
|
||||||
|
slug
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getIcon() {
|
||||||
|
if (!this.icon) {
|
||||||
|
return "/icon.svg";
|
||||||
|
} else {
|
||||||
|
return this.icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = StatusPage;
|
67
server/notification-providers/alerta.js
Normal file
67
server/notification-providers/alerta.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Alerta extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "alerta";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let alertaUrl = `${notification.alertaApiEndpoint}`;
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json;charset=UTF-8",
|
||||||
|
"Authorization": "Key " + notification.alertaapiKey,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = {
|
||||||
|
environment: notification.alertaEnvironment,
|
||||||
|
severity: "critical",
|
||||||
|
correlate: [],
|
||||||
|
service: [ "UptimeKuma" ],
|
||||||
|
value: "Timeout",
|
||||||
|
tags: [ "uptimekuma" ],
|
||||||
|
attributes: {},
|
||||||
|
origin: "uptimekuma",
|
||||||
|
type: "exceptionAlert",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let postData = Object.assign({
|
||||||
|
event: "msg",
|
||||||
|
text: msg,
|
||||||
|
group: "uptimekuma-msg",
|
||||||
|
resource: "Message",
|
||||||
|
}, data);
|
||||||
|
|
||||||
|
await axios.post(alertaUrl, postData, config);
|
||||||
|
} else {
|
||||||
|
let datadup = Object.assign( {
|
||||||
|
correlate: ["service_up", "service_down"],
|
||||||
|
event: monitorJSON["type"],
|
||||||
|
group: "uptimekuma-" + monitorJSON["type"],
|
||||||
|
resource: monitorJSON["name"],
|
||||||
|
}, data );
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
datadup.severity = notification.alertaAlertState; // critical
|
||||||
|
datadup.text = "Service " + monitorJSON["type"] + " is down.";
|
||||||
|
await axios.post(alertaUrl, datadup, config);
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
datadup.severity = notification.alertaRecoverState; // cleaned
|
||||||
|
datadup.text = "Service " + monitorJSON["type"] + " is up.";
|
||||||
|
await axios.post(alertaUrl, datadup, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Alerta;
|
42
server/notification-providers/gorush.js
Normal file
42
server/notification-providers/gorush.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Gorush extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "gorush";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
let platformMapping = {
|
||||||
|
"ios": 1,
|
||||||
|
"android": 2,
|
||||||
|
"huawei": 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
"notifications": [
|
||||||
|
{
|
||||||
|
"tokens": [notification.gorushDeviceToken],
|
||||||
|
"platform": platformMapping[notification.gorushPlatform],
|
||||||
|
"message": msg,
|
||||||
|
// Optional
|
||||||
|
"title": notification.gorushTitle,
|
||||||
|
"priority": notification.gorushPriority,
|
||||||
|
"retry": parseInt(notification.gorushRetry) || 0,
|
||||||
|
"topic": notification.gorushTopic,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
await axios.post(`${notification.gorushServerURL}/api/push`, data, config);
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Gorush;
|
|
@ -20,7 +20,7 @@ class Mattermost extends NotificationProvider {
|
||||||
return okMsg;
|
return okMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mattermostChannel = notification.mattermostchannel;
|
const mattermostChannel = notification.mattermostchannel.toLowerCase();
|
||||||
const mattermostIconEmoji = notification.mattermosticonemo;
|
const mattermostIconEmoji = notification.mattermosticonemo;
|
||||||
const mattermostIconUrl = notification.mattermosticonurl;
|
const mattermostIconUrl = notification.mattermosticonurl;
|
||||||
|
|
||||||
|
|
23
server/notification-providers/techulus-push.js
Normal file
23
server/notification-providers/techulus-push.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class TechulusPush extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "PushByTechulus";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, {
|
||||||
|
"title": "Uptime-Kuma",
|
||||||
|
"body": msg,
|
||||||
|
})
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TechulusPush;
|
|
@ -12,6 +12,7 @@ const ClickSendSMS = require("./notification-providers/clicksendsms");
|
||||||
const Pushbullet = require("./notification-providers/pushbullet");
|
const Pushbullet = require("./notification-providers/pushbullet");
|
||||||
const Pushover = require("./notification-providers/pushover");
|
const Pushover = require("./notification-providers/pushover");
|
||||||
const Pushy = require("./notification-providers/pushy");
|
const Pushy = require("./notification-providers/pushy");
|
||||||
|
const TechulusPush = require("./notification-providers/techulus-push");
|
||||||
const RocketChat = require("./notification-providers/rocket-chat");
|
const RocketChat = require("./notification-providers/rocket-chat");
|
||||||
const Signal = require("./notification-providers/signal");
|
const Signal = require("./notification-providers/signal");
|
||||||
const Slack = require("./notification-providers/slack");
|
const Slack = require("./notification-providers/slack");
|
||||||
|
@ -27,6 +28,8 @@ const SerwerSMS = require("./notification-providers/serwersms");
|
||||||
const Stackfield = require("./notification-providers/stackfield");
|
const Stackfield = require("./notification-providers/stackfield");
|
||||||
const WeCom = require("./notification-providers/wecom");
|
const WeCom = require("./notification-providers/wecom");
|
||||||
const GoogleChat = require("./notification-providers/google-chat");
|
const GoogleChat = require("./notification-providers/google-chat");
|
||||||
|
const Gorush = require("./notification-providers/gorush");
|
||||||
|
const Alerta = require("./notification-providers/alerta");
|
||||||
|
|
||||||
class Notification {
|
class Notification {
|
||||||
|
|
||||||
|
@ -55,6 +58,7 @@ class Notification {
|
||||||
new Pushbullet(),
|
new Pushbullet(),
|
||||||
new Pushover(),
|
new Pushover(),
|
||||||
new Pushy(),
|
new Pushy(),
|
||||||
|
new TechulusPush(),
|
||||||
new RocketChat(),
|
new RocketChat(),
|
||||||
new Signal(),
|
new Signal(),
|
||||||
new Slack(),
|
new Slack(),
|
||||||
|
@ -65,7 +69,9 @@ class Notification {
|
||||||
new SerwerSMS(),
|
new SerwerSMS(),
|
||||||
new Stackfield(),
|
new Stackfield(),
|
||||||
new WeCom(),
|
new WeCom(),
|
||||||
new GoogleChat()
|
new GoogleChat(),
|
||||||
|
new Gorush(),
|
||||||
|
new Alerta(),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let item of list) {
|
for (let item of list) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ const apicache = require("../modules/apicache");
|
||||||
const Monitor = require("../model/monitor");
|
const Monitor = require("../model/monitor");
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { UP, flipStatus, debug } = require("../../src/util");
|
const { UP, flipStatus, debug } = require("../../src/util");
|
||||||
|
const StatusPage = require("../model/status_page");
|
||||||
let router = express.Router();
|
let router = express.Router();
|
||||||
|
|
||||||
let cache = apicache.middleware;
|
let cache = apicache.middleware;
|
||||||
|
@ -82,110 +83,80 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status Page Config
|
// Status page config, incident, monitor list
|
||||||
router.get("/api/status-page/config", async (_request, response) => {
|
router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
|
let slug = request.params.slug;
|
||||||
|
|
||||||
let config = await getSettings("statusPage");
|
// Get Status Page
|
||||||
|
let statusPage = await R.findOne("status_page", " slug = ? ", [
|
||||||
|
slug
|
||||||
|
]);
|
||||||
|
|
||||||
if (! config.statusPageTheme) {
|
if (!statusPage) {
|
||||||
config.statusPageTheme = "light";
|
response.statusCode = 404;
|
||||||
|
response.json({
|
||||||
|
msg: "Not Found"
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! config.statusPagePublished) {
|
|
||||||
config.statusPagePublished = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! config.statusPageTags) {
|
|
||||||
config.statusPageTags = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! config.title) {
|
|
||||||
config.title = "Uptime Kuma";
|
|
||||||
}
|
|
||||||
|
|
||||||
response.json(config);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Status Page - Get the current Incident
|
|
||||||
// Can fetch only if published
|
|
||||||
router.get("/api/status-page/incident", async (_, response) => {
|
|
||||||
allowDevAllOrigin(response);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await checkPublished();
|
// Incident
|
||||||
|
let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [
|
||||||
let incident = await R.findOne("incident", " pin = 1 AND active = 1");
|
statusPage.id,
|
||||||
|
]);
|
||||||
|
|
||||||
if (incident) {
|
if (incident) {
|
||||||
incident = incident.toPublicJSON();
|
incident = incident.toPublicJSON();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Public Group List
|
||||||
|
const publicGroupList = [];
|
||||||
|
const showTags = !!statusPage.show_tags;
|
||||||
|
debug("Show Tags???" + showTags);
|
||||||
|
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
|
||||||
|
statusPage.id
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (let groupBean of list) {
|
||||||
|
let monitorGroup = await groupBean.toPublicJSON(showTags);
|
||||||
|
publicGroupList.push(monitorGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response
|
||||||
response.json({
|
response.json({
|
||||||
ok: true,
|
config: await statusPage.toPublicJSON(),
|
||||||
incident,
|
incident,
|
||||||
|
publicGroupList
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
send403(response, error.message);
|
send403(response, error.message);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Status Page - Monitor List
|
|
||||||
// Can fetch only if published
|
|
||||||
router.get("/api/status-page/monitor-list", cache("5 minutes"), async (_request, response) => {
|
|
||||||
allowDevAllOrigin(response);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await checkPublished();
|
|
||||||
const publicGroupList = [];
|
|
||||||
const tagsVisible = (await getSettings("statusPage")).statusPageTags;
|
|
||||||
const list = await R.find("group", " public = 1 ORDER BY weight ");
|
|
||||||
for (let groupBean of list) {
|
|
||||||
let monitorGroup = await groupBean.toPublicJSON();
|
|
||||||
if (tagsVisible) {
|
|
||||||
monitorGroup.monitorList = await Promise.all(monitorGroup.monitorList.map(async (monitor) => {
|
|
||||||
// Includes tags as an array in response, allows for tags to be displayed on public status page
|
|
||||||
const tags = await R.getAll(
|
|
||||||
`SELECT monitor_tag.monitor_id, monitor_tag.value, tag.name, tag.color
|
|
||||||
FROM monitor_tag
|
|
||||||
JOIN tag
|
|
||||||
ON monitor_tag.tag_id = tag.id
|
|
||||||
WHERE monitor_tag.monitor_id = ?`, [monitor.id]
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
...monitor,
|
|
||||||
tags: tags
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
publicGroupList.push(monitorGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.json(publicGroupList);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
send403(response, error.message);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status Page Polling Data
|
// Status Page Polling Data
|
||||||
// Can fetch only if published
|
// Can fetch only if published
|
||||||
router.get("/api/status-page/heartbeat", cache("5 minutes"), async (_request, response) => {
|
router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await checkPublished();
|
|
||||||
|
|
||||||
let heartbeatList = {};
|
let heartbeatList = {};
|
||||||
let uptimeList = {};
|
let uptimeList = {};
|
||||||
|
|
||||||
|
let slug = request.params.slug;
|
||||||
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
let monitorIDList = await R.getCol(`
|
let monitorIDList = await R.getCol(`
|
||||||
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
||||||
WHERE monitor_group.group_id = \`group\`.id
|
WHERE monitor_group.group_id = \`group\`.id
|
||||||
AND public = 1
|
AND public = 1
|
||||||
`);
|
AND \`group\`.status_page_id = ?
|
||||||
|
`, [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
for (let monitorID of monitorIDList) {
|
for (let monitorID of monitorIDList) {
|
||||||
let list = await R.getAll(`
|
let list = await R.getAll(`
|
||||||
|
@ -214,22 +185,12 @@ router.get("/api/status-page/heartbeat", cache("5 minutes"), async (_request, re
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function checkPublished() {
|
|
||||||
if (! await isPublished()) {
|
|
||||||
throw new Error("The status page is not published");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default is published
|
* Default is published
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
async function isPublished() {
|
async function isPublished() {
|
||||||
const value = await setting("statusPagePublished");
|
|
||||||
if (value === null) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function send403(res, msg = "") {
|
function send403(res, msg = "") {
|
||||||
|
|
|
@ -132,6 +132,7 @@ const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sen
|
||||||
const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler");
|
const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler");
|
||||||
const databaseSocketHandler = require("./socket-handlers/database-socket-handler");
|
const databaseSocketHandler = require("./socket-handlers/database-socket-handler");
|
||||||
const TwoFA = require("./2fa");
|
const TwoFA = require("./2fa");
|
||||||
|
const StatusPage = require("./model/status_page");
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
@ -200,8 +201,8 @@ exports.entryPage = "dashboard";
|
||||||
|
|
||||||
// Entry Page
|
// Entry Page
|
||||||
app.get("/", async (_request, response) => {
|
app.get("/", async (_request, response) => {
|
||||||
if (exports.entryPage === "statusPage") {
|
if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) {
|
||||||
response.redirect("/status");
|
response.redirect("/status/" + exports.entryPage.replace("statusPage-", ""));
|
||||||
} else {
|
} else {
|
||||||
response.redirect("/dashboard");
|
response.redirect("/dashboard");
|
||||||
}
|
}
|
||||||
|
@ -1414,6 +1415,8 @@ async function afterLogin(socket, user) {
|
||||||
for (let monitorID in monitorList) {
|
for (let monitorID in monitorList) {
|
||||||
await Monitor.sendStats(io, monitorID, user.id);
|
await Monitor.sendStats(io, monitorID, user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await StatusPage.sendStatusPageList(io, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMonitorJSONList(userID) {
|
async function getMonitorJSONList(userID) {
|
||||||
|
|
|
@ -1,25 +1,36 @@
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { checkLogin, setSettings } = require("../util-server");
|
const { checkLogin, setSettings, setSetting } = require("../util-server");
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { debug } = require("../../src/util");
|
const { debug } = require("../../src/util");
|
||||||
const ImageDataURI = require("../image-data-uri");
|
const ImageDataURI = require("../image-data-uri");
|
||||||
const Database = require("../database");
|
const Database = require("../database");
|
||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
|
const StatusPage = require("../model/status_page");
|
||||||
|
const server = require("../server");
|
||||||
|
|
||||||
module.exports.statusPageSocketHandler = (socket) => {
|
module.exports.statusPageSocketHandler = (socket) => {
|
||||||
|
|
||||||
// Post or edit incident
|
// Post or edit incident
|
||||||
socket.on("postIncident", async (incident, callback) => {
|
socket.on("postIncident", async (slug, incident, callback) => {
|
||||||
try {
|
try {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
|
|
||||||
await R.exec("UPDATE incident SET pin = 0 ");
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
|
if (!statusPageID) {
|
||||||
|
throw new Error("slug is not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
await R.exec("UPDATE incident SET pin = 0 WHERE status_page_id = ? ", [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
let incidentBean;
|
let incidentBean;
|
||||||
|
|
||||||
if (incident.id) {
|
if (incident.id) {
|
||||||
incidentBean = await R.findOne("incident", " id = ?", [
|
incidentBean = await R.findOne("incident", " id = ? AND status_page_id = ? ", [
|
||||||
incident.id
|
incident.id,
|
||||||
|
statusPageID
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +42,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
incidentBean.content = incident.content;
|
incidentBean.content = incident.content;
|
||||||
incidentBean.style = incident.style;
|
incidentBean.style = incident.style;
|
||||||
incidentBean.pin = true;
|
incidentBean.pin = true;
|
||||||
|
incidentBean.status_page_id = statusPageID;
|
||||||
|
|
||||||
if (incident.id) {
|
if (incident.id) {
|
||||||
incidentBean.lastUpdatedDate = R.isoDateTime(dayjs.utc());
|
incidentBean.lastUpdatedDate = R.isoDateTime(dayjs.utc());
|
||||||
|
@ -52,11 +64,15 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("unpinIncident", async (callback) => {
|
socket.on("unpinIncident", async (slug, callback) => {
|
||||||
try {
|
try {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
|
|
||||||
await R.exec("UPDATE incident SET pin = 0 WHERE pin = 1");
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
|
await R.exec("UPDATE incident SET pin = 0 WHERE pin = 1 AND status_page_id = ? ", [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
@ -71,13 +87,21 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
|
|
||||||
// Save Status Page
|
// Save Status Page
|
||||||
// imgDataUrl Only Accept PNG!
|
// imgDataUrl Only Accept PNG!
|
||||||
socket.on("saveStatusPage", async (config, imgDataUrl, publicGroupList, callback) => {
|
socket.on("saveStatusPage", async (slug, config, imgDataUrl, publicGroupList, callback) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
|
|
||||||
apicache.clear();
|
apicache.clear();
|
||||||
|
|
||||||
|
// Save Config
|
||||||
|
let statusPage = await R.findOne("status_page", " slug = ? ", [
|
||||||
|
slug
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!statusPage) {
|
||||||
|
throw new Error("No slug?");
|
||||||
|
}
|
||||||
|
|
||||||
const header = "data:image/png;base64,";
|
const header = "data:image/png;base64,";
|
||||||
|
|
||||||
// Check logo format
|
// Check logo format
|
||||||
|
@ -88,16 +112,28 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
throw new Error("Only allowed PNG logo.");
|
throw new Error("Only allowed PNG logo.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filename = `logo${statusPage.id}.png`;
|
||||||
|
|
||||||
// Convert to file
|
// Convert to file
|
||||||
await ImageDataURI.outputFile(imgDataUrl, Database.uploadDir + "logo.png");
|
await ImageDataURI.outputFile(imgDataUrl, Database.uploadDir + filename);
|
||||||
config.logo = "/upload/logo.png?t=" + Date.now();
|
config.logo = `/upload/${filename}?t=` + Date.now();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
config.icon = imgDataUrl;
|
config.icon = imgDataUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save Config
|
statusPage.slug = config.slug;
|
||||||
await setSettings("statusPage", config);
|
statusPage.title = config.title;
|
||||||
|
statusPage.description = config.description;
|
||||||
|
statusPage.icon = config.logo;
|
||||||
|
statusPage.theme = config.theme;
|
||||||
|
//statusPage.published = ;
|
||||||
|
//statusPage.search_engine_index = ;
|
||||||
|
statusPage.show_tags = config.showTags;
|
||||||
|
//statusPage.password = null;
|
||||||
|
statusPage.modified_date = R.isoDateTime();
|
||||||
|
|
||||||
|
await R.store(statusPage);
|
||||||
|
|
||||||
// Save Public Group List
|
// Save Public Group List
|
||||||
const groupIDList = [];
|
const groupIDList = [];
|
||||||
|
@ -106,13 +142,15 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
for (let group of publicGroupList) {
|
for (let group of publicGroupList) {
|
||||||
let groupBean;
|
let groupBean;
|
||||||
if (group.id) {
|
if (group.id) {
|
||||||
groupBean = await R.findOne("group", " id = ? AND public = 1 ", [
|
groupBean = await R.findOne("group", " id = ? AND public = 1 AND status_page_id = ? ", [
|
||||||
group.id
|
group.id,
|
||||||
|
statusPage.id
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
groupBean = R.dispense("group");
|
groupBean = R.dispense("group");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupBean.status_page_id = statusPage.id;
|
||||||
groupBean.name = group.name;
|
groupBean.name = group.name;
|
||||||
groupBean.public = true;
|
groupBean.public = true;
|
||||||
groupBean.weight = groupOrder++;
|
groupBean.weight = groupOrder++;
|
||||||
|
@ -124,7 +162,6 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let monitorOrder = 1;
|
let monitorOrder = 1;
|
||||||
console.log(group.monitorList);
|
|
||||||
|
|
||||||
for (let monitor of group.monitorList) {
|
for (let monitor of group.monitorList) {
|
||||||
let relationBean = R.dispense("monitor_group");
|
let relationBean = R.dispense("monitor_group");
|
||||||
|
@ -143,13 +180,19 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
const slots = groupIDList.map(() => "?").join(",");
|
const slots = groupIDList.map(() => "?").join(",");
|
||||||
await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots})`, groupIDList);
|
await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots})`, groupIDList);
|
||||||
|
|
||||||
|
// Also change entry page to new slug if it is the default one, and slug is changed.
|
||||||
|
if (server.entryPage === "statusPage-" + slug && statusPage.slug !== slug) {
|
||||||
|
server.entryPage = "statusPage-" + statusPage.slug;
|
||||||
|
await setSetting("entryPage", server.entryPage, "general");
|
||||||
|
}
|
||||||
|
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
publicGroupList,
|
publicGroupList,
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.error(error);
|
||||||
|
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
|
@ -158,4 +201,99 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add a new status page
|
||||||
|
socket.on("addStatusPage", async (title, slug, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
title = title?.trim();
|
||||||
|
slug = slug?.trim();
|
||||||
|
|
||||||
|
// Check empty
|
||||||
|
if (!title || !slug) {
|
||||||
|
throw new Error("Please input all fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure slug is string
|
||||||
|
if (typeof slug !== "string") {
|
||||||
|
throw new Error("Slug -Accept string only");
|
||||||
|
}
|
||||||
|
|
||||||
|
// lower case only
|
||||||
|
slug = slug.toLowerCase();
|
||||||
|
|
||||||
|
// Check slug a-z, 0-9, - only
|
||||||
|
// Regex from: https://stackoverflow.com/questions/22454258/js-regex-string-validation-for-slug
|
||||||
|
if (!slug.match(/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/)) {
|
||||||
|
throw new Error("Invalid Slug");
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusPage = R.dispense("status_page");
|
||||||
|
statusPage.slug = slug;
|
||||||
|
statusPage.title = title;
|
||||||
|
statusPage.theme = "light";
|
||||||
|
statusPage.icon = "";
|
||||||
|
await R.store(statusPage);
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "OK!"
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete a status page
|
||||||
|
socket.on("deleteStatusPage", async (slug, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
|
if (statusPageID) {
|
||||||
|
|
||||||
|
// Reset entry page if it is the default one.
|
||||||
|
if (server.entryPage === "statusPage-" + slug) {
|
||||||
|
server.entryPage = "dashboard";
|
||||||
|
await setSetting("entryPage", server.entryPage, "general");
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to delete records from `status_page_cname`, because it has cascade foreign key.
|
||||||
|
// But for incident & group, it is hard to add cascade foreign key during migration, so they have to be deleted manually.
|
||||||
|
|
||||||
|
// Delete incident
|
||||||
|
await R.exec("DELETE FROM incident WHERE status_page_id = ? ", [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Delete group
|
||||||
|
await R.exec("DELETE FROM `group` WHERE status_page_id = ? ", [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Delete status_page
|
||||||
|
await R.exec("DELETE FROM status_page WHERE id = ? ", [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error("Status Page is not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,6 +92,10 @@ textarea.form-control {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-dark {
|
||||||
|
background-color: #161B22;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 550px) {
|
@media (max-width: 550px) {
|
||||||
.table-shadow-box {
|
.table-shadow-box {
|
||||||
padding: 10px !important;
|
padding: 10px !important;
|
||||||
|
@ -144,6 +148,10 @@ textarea.form-control {
|
||||||
background-color: #090c10;
|
background-color: #090c10;
|
||||||
color: $dark-font-color;
|
color: $dark-font-color;
|
||||||
|
|
||||||
|
mark, .mark {
|
||||||
|
background-color: #b6ad86;
|
||||||
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb {
|
||||||
background: $dark-border-color;
|
background: $dark-border-color;
|
||||||
}
|
}
|
||||||
|
@ -156,13 +164,24 @@ textarea.form-control {
|
||||||
|
|
||||||
.form-check-input {
|
.form-check-input {
|
||||||
background-color: $dark-bg2;
|
background-color: $dark-bg2;
|
||||||
|
border-color: $dark-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group-text {
|
||||||
|
background-color: #282f39;
|
||||||
|
border-color: $dark-border-color;
|
||||||
|
color: $dark-font-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input:checked {
|
||||||
|
border-color: $primary; // Re-apply bootstrap border
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-switch .form-check-input {
|
.form-switch .form-check-input {
|
||||||
background-color: #232f3b;
|
background-color: #232f3b;
|
||||||
}
|
}
|
||||||
|
|
||||||
a,
|
a:not(.btn),
|
||||||
.table,
|
.table,
|
||||||
.nav-link {
|
.nav-link {
|
||||||
color: $dark-font-color;
|
color: $dark-font-color;
|
||||||
|
@ -433,6 +452,10 @@ textarea.form-control {
|
||||||
border-radius: 10px !important;
|
border-radius: 10px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
color: $primary;
|
||||||
|
}
|
||||||
|
|
||||||
// Localization
|
// Localization
|
||||||
|
|
||||||
@import "localization.scss";
|
@import "localization.scss";
|
||||||
|
|
|
@ -85,7 +85,9 @@ export default {
|
||||||
model: null,
|
model: null,
|
||||||
processing: false,
|
processing: false,
|
||||||
id: null,
|
id: null,
|
||||||
notificationTypes: Object.keys(NotificationFormList),
|
notificationTypes: Object.keys(NotificationFormList).sort((a, b) => {
|
||||||
|
return a.toLowerCase().localeCompare(b.toLowerCase());
|
||||||
|
}),
|
||||||
notification: {
|
notification: {
|
||||||
name: "",
|
name: "",
|
||||||
/** @type { null | keyof NotificationFormList } */
|
/** @type { null | keyof NotificationFormList } */
|
||||||
|
@ -143,12 +145,9 @@ export default {
|
||||||
this.id = null;
|
this.id = null;
|
||||||
this.notification = {
|
this.notification = {
|
||||||
name: "",
|
name: "",
|
||||||
type: null,
|
type: "telegram",
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set Default value here
|
|
||||||
this.notification.type = this.notificationTypes[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modal.show();
|
this.modal.show();
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<Uptime :monitor="monitor.element" type="24" :pill="true" />
|
<Uptime :monitor="monitor.element" type="24" :pill="true" />
|
||||||
{{ monitor.element.name }}
|
{{ monitor.element.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="tags">
|
<div v-if="showTags" class="tags">
|
||||||
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
|
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -76,6 +76,9 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
showTags: {
|
||||||
|
type: Boolean,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
14
src/components/notifications/Alerta.vue
Normal file
14
src/components/notifications/Alerta.vue
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="alerta-api-endpoint" class="form-label">{{ $t("alertaApiEndpoint") }}</label>
|
||||||
|
<input id="alerta-api-endpoint" v-model="$parent.notification.alertaApiEndpoint" type="text" class="form-control" required>
|
||||||
|
<label for="alerta-environment" class="form-label">{{ $t("alertaEnvironment") }}</label>
|
||||||
|
<input id="alerta-environment" v-model="$parent.notification.alertaEnvironment" type="text" class="form-control" required>
|
||||||
|
<label for="alerta-api-key" class="form-label">{{ $t("alertaApiKey") }}</label>
|
||||||
|
<input id="alerta-api-key" v-model="$parent.notification.alertaApiKey" type="text" class="form-control" required>
|
||||||
|
<label for="alerta-alert-state" class="form-label">{{ $t("alertaAlertState") }}</label>
|
||||||
|
<input id="alerta-alert-state" v-model="$parent.notification.alertaAlertState" type="text" class="form-control" placeholder="critical" required>
|
||||||
|
<label for="alerta-recover-state" class="form-label">{{ $t("alertaRecoverState") }}</label>
|
||||||
|
<input id="alerta-recover-state" v-model="$parent.notification.alertaRecoverState" type="text" class="form-control" placeholder="cleared" required>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -6,7 +6,7 @@
|
||||||
<label for="secretAccessKey" class="form-label">{{ $t("SecretAccessKey") }}<span style="color: red;"><sup>*</sup></span></label>
|
<label for="secretAccessKey" class="form-label">{{ $t("SecretAccessKey") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
<input id="secretAccessKey" v-model="$parent.notification.secretAccessKey" type="text" class="form-control" required>
|
<input id="secretAccessKey" v-model="$parent.notification.secretAccessKey" type="text" class="form-control" required>
|
||||||
|
|
||||||
<label for="phonenumber" class="form-label">{{ $t("Phonenumber") }}<span style="color: red;"><sup>*</sup></span></label>
|
<label for="phonenumber" class="form-label">{{ $t("PhoneNumbers") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
<input id="phonenumber" v-model="$parent.notification.phonenumber" type="text" class="form-control" required>
|
<input id="phonenumber" v-model="$parent.notification.phonenumber" type="text" class="form-control" required>
|
||||||
|
|
||||||
<label for="templateCode" class="form-label">{{ $t("TemplateCode") }}<span style="color: red;"><sup>*</sup></span></label>
|
<label for="templateCode" class="form-label">{{ $t("TemplateCode") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<input id="signName" v-model="$parent.notification.signName" type="text" class="form-control" required>
|
<input id="signName" v-model="$parent.notification.signName" type="text" class="form-control" required>
|
||||||
|
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<p>Sms template must contain parameters: <br> <code>${name} ${time} ${status} ${msg}</code></p>
|
<p>{{ $t("Sms template must contain parameters: ") }}<br> <code>${name} ${time} ${status} ${msg}</code></p>
|
||||||
<i18n-t tag="p" keypath="Read more:">
|
<i18n-t tag="p" keypath="Read more:">
|
||||||
<a href="https://help.aliyun.com/document_detail/101414.html" target="_blank">https://help.aliyun.com/document_detail/101414.html</a>
|
<a href="https://help.aliyun.com/document_detail/101414.html" target="_blank">https://help.aliyun.com/document_detail/101414.html</a>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
<input id="secretKey" v-model="$parent.notification.secretKey" type="text" class="form-control" required>
|
<input id="secretKey" v-model="$parent.notification.secretKey" type="text" class="form-control" required>
|
||||||
|
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<p>For safety, must use secret key</p>
|
<p>{{ $t("For safety, must use secret key") }}</p>
|
||||||
<i18n-t tag="p" keypath="Read more:">
|
<i18n-t tag="p" keypath="Read more:">
|
||||||
<a href="https://developers.dingtalk.com/document/robots/custom-robot-access" target="_blank">https://developers.dingtalk.com/document/robots/custom-robot-access</a>
|
<a href="https://developers.dingtalk.com/document/robots/custom-robot-access" target="_blank">https://developers.dingtalk.com/document/robots/custom-robot-access</a> <a href="https://open.dingtalk.com/document/robots/customize-robot-security-settings#title-7fs-kgs-36x" target="_blank">https://open.dingtalk.com/document/robots/customize-robot-security-settings#title-7fs-kgs-36x</a>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
51
src/components/notifications/Gorush.vue
Normal file
51
src/components/notifications/Gorush.vue
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gorush-device-token" class="form-label">{{ $t("Device Token") }}</label><span style="color: red;"><sup>*</sup></span>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input id="gorush-device-token" v-model="$parent.notification.gorushDeviceToken" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gorush-server-url" class="form-label">{{ $t("Server URL") }}</label><span style="color: red;"><sup>*</sup></span>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input id="gorush-server-url" v-model="$parent.notification.gorushServerURL" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gorush-platform" class="form-label">{{ $t("Platform") }}</label><span style="color: red;"><sup>*</sup></span>
|
||||||
|
<select id="gorush-platform" v-model="$parent.notification.gorushPlatform" class="form-select">
|
||||||
|
<option value="ios">{{ $t("iOS") }}</option>
|
||||||
|
<option value="android">{{ $t("Android") }}</option>
|
||||||
|
<option value="huawei">{{ $t("Huawei") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gorush-title" class="form-label">{{ $t("Title") }}</label>
|
||||||
|
<input id="gorush-title" v-model="$parent.notification.gorushTitle" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gorush-priority" class="form-label">{{ $t("Priority") }}</label>
|
||||||
|
<select id="gorush-priority" v-model="$parent.notification.gorushPriority" class="form-select">
|
||||||
|
<option value="normal">{{ $t("Normal") }}</option>
|
||||||
|
<option value="high">{{ $t("High") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gorush-retry" class="form-label">{{ $t("Retry") }}</label>
|
||||||
|
<input id="gorush-retry" v-model="$parent.notification.gorushRetry" type="number" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gorush-topic" class="form-label">{{ $t("Topic") }}</label>
|
||||||
|
<input id="gorush-topic" v-model="$parent.notification.gorushTopic" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-text">
|
||||||
|
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
||||||
|
</div>
|
||||||
|
</template>
|
20
src/components/notifications/TechulusPush.vue
Normal file
20
src/components/notifications/TechulusPush.vue
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="push-api-key" class="form-label">API_KEY</label>
|
||||||
|
<HiddenInput id="push-api-key" v-model="$parent.notification.pushAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
|
||||||
|
<a href="https://docs.push.techulus.com" target="_blank">https://docs.push.techulus.com</a>
|
||||||
|
</i18n-t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HiddenInput from "../HiddenInput.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HiddenInput,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -63,9 +63,9 @@ export default {
|
||||||
let update = res.data.result[res.data.result.length - 1];
|
let update = res.data.result[res.data.result.length - 1];
|
||||||
|
|
||||||
if (update.channel_post) {
|
if (update.channel_post) {
|
||||||
this.notification.telegramChatID = update.channel_post.chat.id;
|
this.$parent.notification.telegramChatID = update.channel_post.chat.id;
|
||||||
} else if (update.message) {
|
} else if (update.message) {
|
||||||
this.notification.telegramChatID = update.message.chat.id;
|
this.$parent.notification.telegramChatID = update.message.chat.id;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(this.$t("chatIDNotFound"));
|
throw new Error(this.$t("chatIDNotFound"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import RocketChat from "./RocketChat.vue";
|
||||||
import Teams from "./Teams.vue";
|
import Teams from "./Teams.vue";
|
||||||
import Pushover from "./Pushover.vue";
|
import Pushover from "./Pushover.vue";
|
||||||
import Pushy from "./Pushy.vue";
|
import Pushy from "./Pushy.vue";
|
||||||
|
import TechulusPush from "./TechulusPush.vue";
|
||||||
import Octopush from "./Octopush.vue";
|
import Octopush from "./Octopush.vue";
|
||||||
import PromoSMS from "./PromoSMS.vue";
|
import PromoSMS from "./PromoSMS.vue";
|
||||||
import ClickSendSMS from "./ClickSendSMS.vue";
|
import ClickSendSMS from "./ClickSendSMS.vue";
|
||||||
|
@ -26,6 +27,8 @@ import SerwerSMS from "./SerwerSMS.vue";
|
||||||
import Stackfield from './Stackfield.vue';
|
import Stackfield from './Stackfield.vue';
|
||||||
import WeCom from "./WeCom.vue";
|
import WeCom from "./WeCom.vue";
|
||||||
import GoogleChat from "./GoogleChat.vue";
|
import GoogleChat from "./GoogleChat.vue";
|
||||||
|
import Gorush from "./Gorush.vue";
|
||||||
|
import Alerta from "./Alerta.vue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage all notification form.
|
* Manage all notification form.
|
||||||
|
@ -44,6 +47,7 @@ const NotificationFormList = {
|
||||||
"rocket.chat": RocketChat,
|
"rocket.chat": RocketChat,
|
||||||
"pushover": Pushover,
|
"pushover": Pushover,
|
||||||
"pushy": Pushy,
|
"pushy": Pushy,
|
||||||
|
"PushByTechulus": TechulusPush,
|
||||||
"octopush": Octopush,
|
"octopush": Octopush,
|
||||||
"promosms": PromoSMS,
|
"promosms": PromoSMS,
|
||||||
"clicksendsms": ClickSendSMS,
|
"clicksendsms": ClickSendSMS,
|
||||||
|
@ -60,7 +64,9 @@ const NotificationFormList = {
|
||||||
"serwersms": SerwerSMS,
|
"serwersms": SerwerSMS,
|
||||||
"stackfield": Stackfield,
|
"stackfield": Stackfield,
|
||||||
"WeCom": WeCom,
|
"WeCom": WeCom,
|
||||||
"GoogleChat": GoogleChat
|
"GoogleChat": GoogleChat,
|
||||||
|
"gorush": Gorush,
|
||||||
|
"alerta": Alerta,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NotificationFormList;
|
export default NotificationFormList;
|
||||||
|
|
|
@ -4,14 +4,39 @@
|
||||||
<object class="my-4" width="200" height="200" data="/icon.svg" />
|
<object class="my-4" width="200" height="200" data="/icon.svg" />
|
||||||
<div class="fs-4 fw-bold">Uptime Kuma</div>
|
<div class="fs-4 fw-bold">Uptime Kuma</div>
|
||||||
<div>{{ $t("Version") }}: {{ $root.info.version }}</div>
|
<div>{{ $t("Version") }}: {{ $root.info.version }}</div>
|
||||||
<div class="my-1 update-link"><a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">{{ $t("Check Update On GitHub") }}</a></div>
|
|
||||||
|
<div class="my-3 update-link"><a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">{{ $t("Check Update On GitHub") }}</a></div>
|
||||||
|
|
||||||
|
<div class="mt-1">
|
||||||
|
<div class="form-check">
|
||||||
|
<label><input v-model="settings.checkUpdate" type="checkbox" @change="saveSettings()" /> Show update if available</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check">
|
||||||
|
<label><input v-model="settings.checkBeta" type="checkbox" :disabled="!settings.checkUpdate" @change="saveSettings()" /> Also check beta release</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
|
computed: {
|
||||||
|
settings() {
|
||||||
|
return this.$parent.$parent.$parent.settings;
|
||||||
|
},
|
||||||
|
saveSettings() {
|
||||||
|
return this.$parent.$parent.$parent.saveSettings;
|
||||||
|
},
|
||||||
|
settingsLoaded() {
|
||||||
|
return this.$parent.$parent.$parent.settingsLoaded;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -62,31 +62,31 @@
|
||||||
|
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
id="entryPageYes"
|
id="entryPageDashboard"
|
||||||
v-model="settings.entryPage"
|
v-model="settings.entryPage"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
name="statusPage"
|
name="entryPage"
|
||||||
value="dashboard"
|
value="dashboard"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="entryPageYes">
|
<label class="form-check-label" for="entryPageDashboard">
|
||||||
{{ $t("Dashboard") }}
|
{{ $t("Dashboard") }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check">
|
<div v-for="statusPage in $root.statusPageList" :key="statusPage.id" class="form-check">
|
||||||
<input
|
<input
|
||||||
id="entryPageNo"
|
:id="'status-page-' + statusPage.id"
|
||||||
v-model="settings.entryPage"
|
v-model="settings.entryPage"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
name="statusPage"
|
name="entryPage"
|
||||||
value="statusPage"
|
:value="'statusPage-' + statusPage.slug"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="entryPageNo">
|
<label class="form-check-label" :for="'status-page-' + statusPage.id">
|
||||||
{{ $t("Status Page") }}
|
{{ $t("Status Page") }} - {{ statusPage.title }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -216,11 +216,23 @@
|
||||||
<p>Vennligst vær forsiktig.</p>
|
<p>Vennligst vær forsiktig.</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="$i18n.locale === 'cs-CZ' ">
|
||||||
|
<p>Opravdu chcete <strong>deaktivovat autentifikaci</strong>?</p>
|
||||||
|
<p>Tato možnost je určena pro případy, kdy <strong>máte autentifikaci zajištěnou třetí stranou</strong> ještě před přístupem do Uptime Kuma, například prostřednictvím Cloudflare Access.</p>
|
||||||
|
<p>Používejte ji prosím s rozmyslem.</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="$i18n.locale === 'vi-VN' ">
|
||||||
|
<p>Bạn có muốn <strong>TẮT XÁC THỰC</strong> không?</p>
|
||||||
|
<p>Điều này rất nguy hiểm<strong>BẤT KỲ AI</strong> cũng có thể truy cập và cướp quyền điều khiển.</p>
|
||||||
|
<p>Vui lòng <strong>cẩn thận</strong>.</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- English (en) -->
|
<!-- English (en) -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<p>Are you sure want to <strong>disable auth</strong>?</p>
|
<p>Are you sure want to <strong>disable authentication</strong>?</p>
|
||||||
<p>It is for <strong>someone who have 3rd-party auth</strong> in front of Uptime Kuma such as Cloudflare Access.</p>
|
<p>It is designed for scenarios <strong>where you intend to implement third-party authentication</strong> in front of Uptime Kuma such as Cloudflare Access, Authelia or other authentication mechanisms.</p>
|
||||||
<p>Please use it carefully.</p>
|
<p>Please use this option carefully!</p>
|
||||||
</template>
|
</template>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { createI18n } from "vue-i18n/index";
|
||||||
import en from "./languages/en";
|
import en from "./languages/en";
|
||||||
|
|
||||||
const languageList = {
|
const languageList = {
|
||||||
|
"cs-CZ": "Čeština",
|
||||||
"zh-HK": "繁體中文 (香港)",
|
"zh-HK": "繁體中文 (香港)",
|
||||||
"bg-BG": "Български",
|
"bg-BG": "Български",
|
||||||
"de-DE": "Deutsch (Deutschland)",
|
"de-DE": "Deutsch (Deutschland)",
|
||||||
|
@ -27,7 +28,7 @@ const languageList = {
|
||||||
"zh-CN": "简体中文",
|
"zh-CN": "简体中文",
|
||||||
"pl": "Polski",
|
"pl": "Polski",
|
||||||
"et-EE": "eesti",
|
"et-EE": "eesti",
|
||||||
"vi": "Vietnamese",
|
"vi-VN": "Tiếng Việt",
|
||||||
"zh-TW": "繁體中文 (台灣)"
|
"zh-TW": "繁體中文 (台灣)"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,9 @@ import {
|
||||||
faAward,
|
faAward,
|
||||||
faLink,
|
faLink,
|
||||||
faChevronDown,
|
faChevronDown,
|
||||||
|
faPen,
|
||||||
|
faExternalLinkSquareAlt,
|
||||||
|
faSpinner,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
|
@ -67,6 +70,9 @@ library.add(
|
||||||
faAward,
|
faAward,
|
||||||
faLink,
|
faLink,
|
||||||
faChevronDown,
|
faChevronDown,
|
||||||
|
faPen,
|
||||||
|
faExternalLinkSquareAlt,
|
||||||
|
faSpinner,
|
||||||
);
|
);
|
||||||
|
|
||||||
export { FontAwesomeIcon };
|
export { FontAwesomeIcon };
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Пауза",
|
pauseDashboardHome: "Пауза",
|
||||||
deleteMonitorMsg: "Наистина ли желаете да изтриете този монитор?",
|
deleteMonitorMsg: "Наистина ли желаете да изтриете този монитор?",
|
||||||
deleteNotificationMsg: "Наистина ли желаете да изтриете това известяване за всички монитори?",
|
deleteNotificationMsg: "Наистина ли желаете да изтриете това известяване за всички монитори?",
|
||||||
resoverserverDescription: "Cloudflare е сървърът по подразбиране, но можете да го промените по всяко време.",
|
resolverserverDescription: "Cloudflare е сървърът по подразбиране, но можете да го промените по всяко време.",
|
||||||
rrtypeDescription: "Изберете ресурсния запис, който желаете да наблюдавате",
|
rrtypeDescription: "Изберете ресурсния запис, който желаете да наблюдавате",
|
||||||
pauseMonitorMsg: "Наистина ли желаете да поставите в режим пауза?",
|
pauseMonitorMsg: "Наистина ли желаете да поставите в режим пауза?",
|
||||||
enableDefaultNotificationDescription: "За всеки нов монитор това известяване ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.",
|
enableDefaultNotificationDescription: "За всеки нов монитор това известяване ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.",
|
||||||
|
@ -197,6 +197,7 @@ export default {
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
"Status Page": "Статус страница",
|
"Status Page": "Статус страница",
|
||||||
|
"Status Pages": "Статус страница",
|
||||||
"Primary Base URL": "Основен базов URL адрес",
|
"Primary Base URL": "Основен базов URL адрес",
|
||||||
"Push URL": "Генериран Push URL адрес",
|
"Push URL": "Генериран Push URL адрес",
|
||||||
needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди",
|
needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди",
|
||||||
|
@ -360,4 +361,13 @@ export default {
|
||||||
smtpDkimHashAlgo: "Хеш алгоритъм (по желание)",
|
smtpDkimHashAlgo: "Хеш алгоритъм (по желание)",
|
||||||
smtpDkimheaderFieldNames: "Хедър ключове за подписване (по желание)",
|
smtpDkimheaderFieldNames: "Хедър ключове за подписване (по желание)",
|
||||||
smtpDkimskipFields: "Хедър ключове, които да не се подписват (по желание)",
|
smtpDkimskipFields: "Хедър ключове, които да не се подписват (по желание)",
|
||||||
|
PushByTechulus: "Push от Techulus",
|
||||||
|
GoogleChat: "Google Chat (Само за работното пространство на Google)",
|
||||||
|
gorush: "Gorush",
|
||||||
|
alerta: "Alerta",
|
||||||
|
alertaApiEndpoint: "Крайна точка на API",
|
||||||
|
alertaEnvironment: "Среда",
|
||||||
|
alertaApiKey: "API Ключ",
|
||||||
|
alertaAlertState: "Състояние на тревога",
|
||||||
|
alertaRecoverState: "Състояние на възстановяване",
|
||||||
};
|
};
|
||||||
|
|
365
src/languages/cs-CZ.js
Normal file
365
src/languages/cs-CZ.js
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
export default {
|
||||||
|
languageName: "Czech",
|
||||||
|
checkEverySecond: "Kontrolovat každých {0} sekund",
|
||||||
|
retryCheckEverySecond: "Opakovat každých {0} sekund",
|
||||||
|
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.",
|
||||||
|
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.",
|
||||||
|
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ů.",
|
||||||
|
clearEventsMsg: "Opravdu chcete odstranit všechny události pro tento dohled?",
|
||||||
|
clearHeartbeatsMsg: "Opravdu chcete odstranit všechny heartbeaty pro tento dohled?",
|
||||||
|
confirmClearStatisticsMsg: "Opravdu chcete smazat VŠECHNY statistiky?",
|
||||||
|
importHandleDescription: "Možnost 'Přeskočit existující' vyberte v případě, že chcete přeskočit všechny dohledy nebo oznámení se stejným názvem. Vybráním možnosti 'Přepsat' dojde k odstranění všech existujících dohledů a oznámení.",
|
||||||
|
confirmImportMsg: "Opravdu chcete importovat zálohu? Prosím ověřte, zda jste vybrali správnou možnost importu.",
|
||||||
|
twoFAVerifyLabel: "Prosím, zadejte svůj token pro ověření 2FA:",
|
||||||
|
tokenValidSettingsMsg: "Token je platný! Nyní můžete uložit nastavení 2FA.",
|
||||||
|
confirmEnableTwoFAMsg: "Opravdu chcete zapnout 2FA?",
|
||||||
|
confirmDisableTwoFAMsg: "Opravdu chcete deaktivovat 2FA?",
|
||||||
|
Settings: "Nastavení",
|
||||||
|
Dashboard: "Nástěnka",
|
||||||
|
"New Update": "Nová aktualizace",
|
||||||
|
Language: "Jazyk",
|
||||||
|
Appearance: "Vzhled",
|
||||||
|
Theme: "Motiv",
|
||||||
|
General: "Obecné",
|
||||||
|
"Primary Base URL": "Primární URL adresa",
|
||||||
|
Version: "Verze",
|
||||||
|
"Check Update On GitHub": "Zkontrolovat aktualizace na GitHubu",
|
||||||
|
List: "Seznam",
|
||||||
|
Add: "Přidat",
|
||||||
|
"Add New Monitor": "Přidat nový dohled",
|
||||||
|
"Quick Stats": "Rychlé statistiky",
|
||||||
|
Up: "Běží",
|
||||||
|
Down: "Nedostupný",
|
||||||
|
Pending: "Čekám",
|
||||||
|
Unknown: "Neznámý",
|
||||||
|
Pause: "Pozastavit",
|
||||||
|
Name: "Název",
|
||||||
|
Status: "Stav",
|
||||||
|
DateTime: "DateTime",
|
||||||
|
Message: "Zpráva",
|
||||||
|
"No important events": "Žádné důležité události",
|
||||||
|
Resume: "Pokračovat",
|
||||||
|
Edit: "Změnit",
|
||||||
|
Delete: "Vymazat",
|
||||||
|
Current: "Aktuální",
|
||||||
|
Uptime: "Doba provozu",
|
||||||
|
"Cert Exp.": "Platnost certifikátu",
|
||||||
|
days: "dny/í",
|
||||||
|
day: "den",
|
||||||
|
"-day": "-dní",
|
||||||
|
hour: "hodina",
|
||||||
|
"-hour": "-hodin",
|
||||||
|
Response: "Odpověď",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Typ dohledu",
|
||||||
|
Keyword: "Klíčové slovo",
|
||||||
|
"Friendly Name": "Obecný název",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Adresa serveru",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Heartbeat interval",
|
||||||
|
Retries: "Počet pokusů",
|
||||||
|
"Heartbeat Retry Interval": "Interval opakování prezenčního signálu",
|
||||||
|
Advanced: "Rozšířené",
|
||||||
|
"Upside Down Mode": "Inverzní režim",
|
||||||
|
"Max. Redirects": "Max. Přesměrování",
|
||||||
|
"Accepted Status Codes": "Akceptované stavové kódy",
|
||||||
|
"Push URL": "Push URL",
|
||||||
|
needPushEvery: "Tuto URL adresu byste měli volat každých {0} sekund.",
|
||||||
|
pushOptionalParams: "Volitelné parametry: {0}",
|
||||||
|
Save: "Uložit",
|
||||||
|
Notifications: "Oznámení",
|
||||||
|
"Not available, please setup.": "Není k dispozici, prosím nastavte.",
|
||||||
|
"Setup Notification": "Nastavení oznámení",
|
||||||
|
Light: "Světlý",
|
||||||
|
Dark: "Tmavý",
|
||||||
|
Auto: "Automaticky",
|
||||||
|
"Theme - Heartbeat Bar": "Motiv – Heartbeat panel",
|
||||||
|
Normal: "Normální",
|
||||||
|
Bottom: "Dole",
|
||||||
|
None: "Žádné",
|
||||||
|
Timezone: "Časové pásmo",
|
||||||
|
"Search Engine Visibility": "Viditelnost pro vyhledávače",
|
||||||
|
"Allow indexing": "Povolit indexování",
|
||||||
|
"Discourage search engines from indexing site": "Zabránit vyhledávačům v indexování stránky",
|
||||||
|
"Change Password": "Změnit heslo",
|
||||||
|
"Current Password": "Aktuální heslo",
|
||||||
|
"New Password": "Nové heslo",
|
||||||
|
"Repeat New Password": "Znovu zadat nové heslo",
|
||||||
|
"Update Password": "Aktualizovat heslo",
|
||||||
|
"Disable Auth": "Deaktivovat ověřování",
|
||||||
|
"Enable Auth": "Povolit ověřování",
|
||||||
|
Logout: "Odhlášení",
|
||||||
|
Leave: "Odejít",
|
||||||
|
"I understand, please disable": "Rozumím, chci ji deaktivovat",
|
||||||
|
Confirm: "Potvrzení",
|
||||||
|
Yes: "Ano",
|
||||||
|
No: "Ne",
|
||||||
|
Username: "Uživatelské jméno",
|
||||||
|
Password: "Heslo",
|
||||||
|
"Remember me": "Zapamatovat si mě",
|
||||||
|
Login: "Přihlášení",
|
||||||
|
"No Monitors, please": "Žádné dohledy, prosím",
|
||||||
|
"add one": "přidat jeden",
|
||||||
|
"Notification Type": "Typ oznámení",
|
||||||
|
Email: "E-mail",
|
||||||
|
Test: "Test",
|
||||||
|
"Certificate Info": "Informace o certifikátu",
|
||||||
|
"Resolver Server": "Resolver Server",
|
||||||
|
"Resource Record Type": "Typ záznamu o prostředku",
|
||||||
|
"Last Result": "Poslední výsledek",
|
||||||
|
"Create your admin account": "Vytvořit účet administrátora",
|
||||||
|
"Repeat Password": "Znovu zadat heslo",
|
||||||
|
"Import Backup": "Importovat zálohu",
|
||||||
|
"Export Backup": "Exportovat zálohu",
|
||||||
|
Export: "Exportovat",
|
||||||
|
Import: "Importovat",
|
||||||
|
respTime: "Odezva Čas (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "Standardně povoleno",
|
||||||
|
"Apply on all existing monitors": "Použít pro všechny existující dohledy",
|
||||||
|
Create: "Vytvořit",
|
||||||
|
"Clear Data": "Vymazat data",
|
||||||
|
Events: "Události",
|
||||||
|
Heartbeats: "Heartbeaty",
|
||||||
|
"Auto Get": "Získat automaticky",
|
||||||
|
backupDescription: "Všechny dohledy a oznámení můžete zálohovat do souboru ve formátu JSON.",
|
||||||
|
backupDescription2: "Poznámka: Nezahrnuje historii a data událostí.",
|
||||||
|
backupDescription3: "Součástí exportovaného souboru jsou citlivá data jako tokeny oznámení; export si prosím bezpečně uložte.",
|
||||||
|
alertNoFile: "Vyberte soubor, který chcete importovat.",
|
||||||
|
alertWrongFileType: "Vyberte soubor ve formátu JSON.",
|
||||||
|
"Clear all statistics": "Vymazat všechny statistiky",
|
||||||
|
"Skip existing": "Přeskočit existující",
|
||||||
|
Overwrite: "Přepsat",
|
||||||
|
Options: "Možnosti",
|
||||||
|
"Keep both": "Ponechat obojí",
|
||||||
|
"Verify Token": "Ověřit token",
|
||||||
|
"Setup 2FA": "Nastavení 2FA",
|
||||||
|
"Enable 2FA": "Povolit 2FA",
|
||||||
|
"Disable 2FA": "Deaktivovat 2FA",
|
||||||
|
"2FA Settings": "Nastavení 2FA",
|
||||||
|
"Two Factor Authentication": "Dvoufaktorová autentifikace",
|
||||||
|
Active: "Zapnuto",
|
||||||
|
Inactive: "Neaktivní",
|
||||||
|
Token: "Token",
|
||||||
|
"Show URI": "Zobrazit URI",
|
||||||
|
Tags: "Štítky",
|
||||||
|
"Add New below or Select...": "Níže přidejte nový nebo vyberte existující…",
|
||||||
|
"Tag with this name already exist.": "Štítek s tímto názvem již existuje.",
|
||||||
|
"Tag with this value already exist.": "Štítek touto hodnotou již existuje.",
|
||||||
|
color: "barva",
|
||||||
|
"value (optional)": "hodnota (volitelné)",
|
||||||
|
Gray: "Šedá",
|
||||||
|
Red: "Červená",
|
||||||
|
Orange: "Oranžová",
|
||||||
|
Green: "Zelená",
|
||||||
|
Blue: "Modrá",
|
||||||
|
Indigo: "Indigo",
|
||||||
|
Purple: "Purpurová",
|
||||||
|
Pink: "Růžová",
|
||||||
|
"Search...": "Hledat…",
|
||||||
|
"Avg. Ping": "Průměr Ping",
|
||||||
|
"Avg. Response": "Průměr Odpověď",
|
||||||
|
"Entry Page": "Vstupní stránka",
|
||||||
|
statusPageNothing: "Nic tady není, přidejte prosím skupinu nebo dohled.",
|
||||||
|
"No Services": "Žádné služby",
|
||||||
|
"All Systems Operational": "Všechny systémy běží",
|
||||||
|
"Partially Degraded Service": "Částečně zhoršená služba",
|
||||||
|
"Degraded Service": "Zhoršená služba",
|
||||||
|
"Add Group": "Přidat skupinu",
|
||||||
|
"Add a monitor": "Přidání dohledu",
|
||||||
|
"Edit Status Page": "Upravit stavovou stránku",
|
||||||
|
"Go to Dashboard": "Přejít na nástěnku",
|
||||||
|
"Status Page": "Stavová stránka",
|
||||||
|
"Status Pages": "Stavová stránka",
|
||||||
|
defaultNotificationName: "Moje {notification} upozornění ({číslo})",
|
||||||
|
here: "sem",
|
||||||
|
Required: "Vyžadováno",
|
||||||
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "Token robota",
|
||||||
|
wayToGetTelegramToken: "Token můžete získat od {0}.",
|
||||||
|
"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",
|
||||||
|
chatIDNotFound: "ID chatu nebylo nalezeno; nejprve tomuto robotovi zašlete zprávu",
|
||||||
|
webhook: "Webhook",
|
||||||
|
"Post URL": "URL adresa příspěvku",
|
||||||
|
"Content Type": "Typ obsahu",
|
||||||
|
webhookJsonDesc: "{0} je vhodný pro všechny moderní servery HTTP, jako je Express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} je vhodné pro PHP. JSON bude nutné analyzovat prostřednictvím {decodeFunction}",
|
||||||
|
smtp: "E-mail (SMTP)",
|
||||||
|
secureOptionNone: "Žádné / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "Ignorovat chybu TLS",
|
||||||
|
"From Email": "Odesílatel",
|
||||||
|
emailCustomSubject: "Vlastní předmět",
|
||||||
|
"To Email": "Příjemce",
|
||||||
|
smtpCC: "Kopie",
|
||||||
|
smtpBCC: "Skrytá kopie",
|
||||||
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "Získáte tak, že přejdete do Nastavení serveru - > Integrace - > Vytvořit Webhook",
|
||||||
|
"Bot Display Name": "Zobrazované jméno robota",
|
||||||
|
"Prefix Custom Message": "Předpona vlastní zprávy",
|
||||||
|
"Hello @everyone is...": "Dobrý den, {'@'}všichni jsou…",
|
||||||
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "URL adresa webhooku",
|
||||||
|
wayToGetTeamsURL: "Informace o tom, jak vytvořit URL adresu webhooku naleznete {0}.",
|
||||||
|
signal: "Signal",
|
||||||
|
Number: "Číslo",
|
||||||
|
Recipients: "Příjemci",
|
||||||
|
needSignalAPI: "Musíte mít Signal klienta s REST API.",
|
||||||
|
wayToCheckSignalURL: "Pro zobrazení instrukcí, jak službu nastavit, přejděte na následující adresu:",
|
||||||
|
signalImportant: "Důležité V seznamu příjemců není možné současně použít skupiny a čísla!",
|
||||||
|
gotify: "Gotify",
|
||||||
|
"Application Token": "Token aplikace",
|
||||||
|
"Server URL": "URL adresa serveru",
|
||||||
|
Priority: "Priorita",
|
||||||
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "Ikona smajlíka",
|
||||||
|
"Channel Name": "Název kanálu",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Více informací o Webhoocích naleznete na adrese: {0}",
|
||||||
|
aboutChannelName: "Pro vynechání Webhook kanálu zadejte jeho název do pole Název kanálu {0}. Příklad: #jiny-kanal",
|
||||||
|
aboutKumaURL: "Pokud ponecháte pole URL adresa Uptime Kuma prázdné, použije se domovská stránka GitHub projektu.",
|
||||||
|
emojiCheatSheet: "Tahák smajlíků: {0}",
|
||||||
|
"rocket.chat": "Rocket.Chat",
|
||||||
|
pushover: "Pushover",
|
||||||
|
pushy: "Pushy",
|
||||||
|
octopush: "Octopush",
|
||||||
|
promosms: "PromoSMS",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
|
lunasea: "LunaSea",
|
||||||
|
apprise: "Apprise (podpora více než 50 oznamovacích služeb)",
|
||||||
|
GoogleChat: "Google Chat (pouze Google Workspace)",
|
||||||
|
pushbullet: "Pushbullet",
|
||||||
|
line: "Line Messenger",
|
||||||
|
mattermost: "Mattermost",
|
||||||
|
"User Key": "Klíč uživatele",
|
||||||
|
Device: "Zařízení",
|
||||||
|
"Message Title": "Nadpis zprávy",
|
||||||
|
"Notification Sound": "Zvuk oznámení",
|
||||||
|
"More info on:": "Více informací naleznete na adrese: {0}",
|
||||||
|
pushoverDesc1: "Výchozí časový limit pro emergency prioritu (2) je 30 sekund mezi opakovanými pokusy a vyprší po 1 hodině.",
|
||||||
|
pushoverDesc2: "Pokud chcete odesílat oznámení do různých zařízení, vyplňte pole Zařízení.",
|
||||||
|
"SMS Type": "Typ SMS",
|
||||||
|
octopushTypePremium: "Premium (rychlé – doporučeno pro upozornění)",
|
||||||
|
octopushTypeLowCost: "Nízké náklady (pomalé – někdy blokované operátorem)",
|
||||||
|
checkPrice: "Ceny {0} zjistíte na adrese:",
|
||||||
|
apiCredentials: "API přihlašovací údaje",
|
||||||
|
octopushLegacyHint: "Používáte starší verzi Octopush (2011-2020) nebo novou verzi?",
|
||||||
|
"Check octopush prices": "Ceny octopush naleznete na adrese {0}.",
|
||||||
|
octopushPhoneNumber: "Telefonní číslo (v mezinárodním formátu, např: +42012345678) ",
|
||||||
|
octopushSMSSender: "Odesílatel SMS: 3-11 alfanumerických znaků a mezera (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "ID zařízení LunaSea",
|
||||||
|
"Apprise URL": "Apprise URL",
|
||||||
|
"Example:": "Příklad: {0}",
|
||||||
|
"Read more:": "Více informací: {0}",
|
||||||
|
"Status:": "Stav: {0}",
|
||||||
|
"Read more": "Více informací",
|
||||||
|
appriseInstalled: "Apprise je nainstalován.",
|
||||||
|
appriseNotInstalled: "Apprise není nainstalován. {0}",
|
||||||
|
"Access Token": "Přístupový token",
|
||||||
|
"Channel access token": "Přístupový token ke kanálu",
|
||||||
|
"Line Developers Console": "Konzole Line Developers",
|
||||||
|
lineDevConsoleTo: "Konzole Line Developers - {0}",
|
||||||
|
"Basic Settings": "Obecné nastavení",
|
||||||
|
"User ID": "ID uživatele",
|
||||||
|
"Messaging API": "Messaging API",
|
||||||
|
wayToGetLineChannelToken: "Nejprve otevřete {0}, vytvořte poskytovatele a kanál (Messaging API). Poté můžete získat přístupový token ke kanálu a ID uživatele, v sekci uvedené výše.",
|
||||||
|
"Icon URL": "URL adresa ikony",
|
||||||
|
aboutIconURL: "Pro přepsání výchozího profilového obrázku můžete do pole \"URL adresa ikony\" zadat odkaz na obrázek. Nebude použito, pokud je nastavena ikona smajlíka.",
|
||||||
|
aboutMattermostChannelName: "Výchozí kanál, do kterého jsou zasílány Webhook příspěvky, můžete přepsat zadáním názvu kanálu do pole \"Název kanálu\". Tato možnost musí být povolena v nastavení Mattermost Webhooku. Příklad: #jiny-kanal",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO – levné, ale pomalé a často přetížené. Omezeno pouze na polské příjemce.",
|
||||||
|
promosmsTypeFlash: "SMS FLASH –zpráva se automaticky zobrazí na zařízení příjemce. Omezeno pouze na polské příjemce.",
|
||||||
|
promosmsTypeFull: "SMS FULL – prémiová úroveň SMS. Můžete definovat odesílatele (vyžadována registrace jména). Spolehlivý pro výstrahy.",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED – nejvyšší priorita v systému. Velmi rychlé a spolehlivé, ale nákladné (přibližně dvojnásobek ceny SMS FULL).",
|
||||||
|
promosmsPhoneNumber: "Telefonní číslo (polští příjemci mohou vynechat telefonní předvolbu)",
|
||||||
|
promosmsSMSSender: "Odesílatel SMS: Předem zaregistrovaný název nebo jeden z výchozích: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
|
"Feishu WebHookUrl": "Feishu WebHookURL",
|
||||||
|
matrixHomeserverURL: "URL adresa domácího serveru (s http(s):// a volitelně portem)",
|
||||||
|
"Internal Room Id": "ID interní místnosti",
|
||||||
|
matrixDesc1: "ID interní místnosti naleznete v Matrix klientovi v rozšířeném nastavení místnosti. Mělo by být ve tvaru !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
|
matrixDesc2: "Důrazně doporučujeme vytvořit nového uživatele a nepoužívat váš vlastní přístupový token uživatele Matrix. Pomocí něj je možné získat přístup k vašemu účtu a všem místnostem, ke kterým jste se připojili. Místo toho vytvořte nového uživatele a pozvěte jej pouze do místnosti, do které chcete oznámení dostávat. Přístupový token můžete získat spuštěním {0}",
|
||||||
|
Method: "Metoda",
|
||||||
|
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: ",
|
||||||
|
"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: ",
|
||||||
|
"Current User": "Aktuálně přihlášený uživatel",
|
||||||
|
recent: "Poslední",
|
||||||
|
Done: "Hotovo",
|
||||||
|
Info: "Informace",
|
||||||
|
Security: "Bezpečnost",
|
||||||
|
"Steam API Key": "API klíč služby Steam",
|
||||||
|
"Shrink Database": "Zmenšit databázi",
|
||||||
|
"Pick a RR-Type...": "Vyberte typ záznamu o prostředku…",
|
||||||
|
"Pick Accepted Status Codes...": "Vyberte stavové kódy, které chcete akceptovat…",
|
||||||
|
Default: "Standardní",
|
||||||
|
"HTTP Options": "Možnosti protokolu HTTP",
|
||||||
|
"Create Incident": "Vytvořit incident",
|
||||||
|
Title: "Předmět",
|
||||||
|
Content: "Obsah",
|
||||||
|
Style: "Styl",
|
||||||
|
info: "informace",
|
||||||
|
warning: "upozornění",
|
||||||
|
danger: "riziko",
|
||||||
|
primary: "primární",
|
||||||
|
light: "světlý",
|
||||||
|
dark: "tmavý",
|
||||||
|
Post: "Publikovat",
|
||||||
|
"Please input title and content": "Zadejte prosím název a obsah",
|
||||||
|
Created: "Vytvořen",
|
||||||
|
"Last Updated": "Poslední aktualizace",
|
||||||
|
Unpin: "Odepnout",
|
||||||
|
"Switch to Light Theme": "Přepnout na světlý motiv",
|
||||||
|
"Switch to Dark Theme": "Přepnutí na tmavý motiv",
|
||||||
|
"Show Tags": "Zobrazit štítky",
|
||||||
|
"Hide Tags": "Skrýt štítky",
|
||||||
|
Description: "Popis",
|
||||||
|
"No monitors available.": "Není dostupný žádný dohled.",
|
||||||
|
"Add one": "Přidat jeden",
|
||||||
|
"No Monitors": "Žádný dohled",
|
||||||
|
"Untitled Group": "Skupina bez názvu",
|
||||||
|
Services: "Služby",
|
||||||
|
Discard: "Zahodit",
|
||||||
|
Cancel: "Zrušit",
|
||||||
|
"Powered by": "Poskytuje",
|
||||||
|
shrinkDatabaseDescription: "Pomocí této možnosti provedete příkaz VACUUM nad SQLite databází. Pokud byla databáze vytvořena po vydání verze 1.10.0, AUTO_VACUUM je již povolena a tato akce není vyžadována.",
|
||||||
|
serwersms: "SerwerSMS.pl",
|
||||||
|
serwersmsAPIUser: "API uživatelské jméno (včetně předpony webapi_)",
|
||||||
|
serwersmsAPIPassword: "API heslo",
|
||||||
|
serwersmsPhoneNumber: "Telefonní číslo",
|
||||||
|
serwersmsSenderName: "Odesílatel SMS (registrováno prostřednictvím zákaznického portálu)",
|
||||||
|
"stackfield": "Stackfield",
|
||||||
|
smtpDkimSettings: "Nastavení DKIM",
|
||||||
|
smtpDkimDesc: "Informace o použití naleznete v {0} Nodemailer DKIM.",
|
||||||
|
documentation: "dokumentaci",
|
||||||
|
smtpDkimDomain: "Název domény",
|
||||||
|
smtpDkimKeySelector: "Selector klíče",
|
||||||
|
smtpDkimPrivateKey: "Privátní klíč",
|
||||||
|
smtpDkimHashAlgo: "Hashovací algoritmus (volitelné)",
|
||||||
|
smtpDkimheaderFieldNames: "Podepisovat tyto hlavičky (volitelné)",
|
||||||
|
smtpDkimskipFields: "Nepodepisovat tyto hlavičky (volitelné)",
|
||||||
|
};
|
|
@ -98,7 +98,7 @@ export default {
|
||||||
keywordDescription: "Søg efter et søgeord i almindelig HTML- eller JSON -output. Bemærk, at der skelnes mellem store og små bogstaver.",
|
keywordDescription: "Søg efter et søgeord i almindelig HTML- eller JSON -output. Bemærk, at der skelnes mellem store og små bogstaver.",
|
||||||
deleteMonitorMsg: "Er du sikker på, at du vil slette overvågeren?",
|
deleteMonitorMsg: "Er du sikker på, at du vil slette overvågeren?",
|
||||||
deleteNotificationMsg: "Er du sikker på, at du vil slette denne underretning for alle overvågere? ",
|
deleteNotificationMsg: "Er du sikker på, at du vil slette denne underretning for alle overvågere? ",
|
||||||
resoverserverDescription: "Cloudflare er standardserveren, den kan til enhver tid ændres.",
|
resolverserverDescription: "Cloudflare er standardserveren, den kan til enhver tid ændres.",
|
||||||
"Resolver Server": "Navne-server",
|
"Resolver Server": "Navne-server",
|
||||||
rrtypeDescription: "Vælg den type RR, du vil overvåge.",
|
rrtypeDescription: "Vælg den type RR, du vil overvåge.",
|
||||||
"Last Result": "Seneste resultat",
|
"Last Result": "Seneste resultat",
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
"Edit Status Page": "Rediger Statusside",
|
"Edit Status Page": "Rediger Statusside",
|
||||||
"Go to Dashboard": "Gå til Betjeningspanel",
|
"Go to Dashboard": "Gå til Betjeningspanel",
|
||||||
"Status Page": "Statusside",
|
"Status Page": "Statusside",
|
||||||
|
"Status Pages": "Statusside",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
|
|
@ -4,14 +4,14 @@ export default {
|
||||||
Dashboard: "Dashboard",
|
Dashboard: "Dashboard",
|
||||||
"New Update": "Update verfügbar",
|
"New Update": "Update verfügbar",
|
||||||
Language: "Sprache",
|
Language: "Sprache",
|
||||||
Appearance: "Erscheinung",
|
Appearance: "Erscheinungsbild",
|
||||||
Theme: "Thema",
|
Theme: "Erscheinungsbild",
|
||||||
General: "Allgemein",
|
General: "Allgemein",
|
||||||
Version: "Version",
|
Version: "Version",
|
||||||
"Check Update On GitHub": "Auf GitHub nach Updates suchen",
|
"Check Update On GitHub": "Auf GitHub nach Updates suchen",
|
||||||
List: "Liste",
|
List: "Liste",
|
||||||
Add: "Hinzufügen",
|
Add: "Hinzufügen",
|
||||||
"Add New Monitor": "Neuer Monitor",
|
"Add New Monitor": "Neuen Monitor hinzufügen",
|
||||||
"Quick Stats": "Übersicht",
|
"Quick Stats": "Übersicht",
|
||||||
Up: "Aktiv",
|
Up: "Aktiv",
|
||||||
Down: "Inaktiv",
|
Down: "Inaktiv",
|
||||||
|
@ -49,20 +49,20 @@ export default {
|
||||||
retriesDescription: "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
|
retriesDescription: "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
|
||||||
Advanced: "Erweitert",
|
Advanced: "Erweitert",
|
||||||
ignoreTLSError: "Ignoriere TLS-/SSL-Fehler von Webseiten",
|
ignoreTLSError: "Ignoriere TLS-/SSL-Fehler von Webseiten",
|
||||||
"Upside Down Mode": "Invertierter Modus",
|
"Upside Down Mode": "Umgekehrter Modus",
|
||||||
upsideDownModeDescription: "Im invertierten Modus wird der Dienst als inaktiv angezeigt, wenn er erreichbar ist.",
|
upsideDownModeDescription: "Im umgekehrten Modus wird der Dienst als inaktiv angezeigt, wenn er erreichbar ist.",
|
||||||
"Max. Redirects": "Max. Weiterleitungen",
|
"Max. Redirects": "Max. Weiterleitungen",
|
||||||
maxRedirectDescription: "Maximale Anzahl von Weiterleitungen, denen gefolgt werden soll. Auf 0 setzen, um Weiterleitungen zu deaktivieren.",
|
maxRedirectDescription: "Maximale Anzahl von Weiterleitungen, denen gefolgt werden soll. Auf 0 setzen, um Weiterleitungen zu deaktivieren.",
|
||||||
"Accepted Status Codes": "Erlaubte HTTP-Statuscodes",
|
"Accepted Status Codes": "Erlaubte HTTP-Statuscodes",
|
||||||
acceptedStatusCodesDescription: "Wähle die Statuscodes aus, welche trotzdem als erfolgreich gewertet werden sollen.",
|
acceptedStatusCodesDescription: "Statuscodes auswählen, die als erfolgreiche Verbindung gelten sollen.",
|
||||||
Save: "Speichern",
|
Save: "Speichern",
|
||||||
Notifications: "Benachrichtigungen",
|
Notifications: "Benachrichtigungen",
|
||||||
"Not available, please setup.": "Keine verfügbar, bitte einrichten.",
|
"Not available, please setup.": "Nicht verfügbar, bitte einrichten.",
|
||||||
"Setup Notification": "Benachrichtigung einrichten",
|
"Setup Notification": "Benachrichtigung einrichten",
|
||||||
Light: "Hell",
|
Light: "Hell",
|
||||||
Dark: "Dunkel",
|
Dark: "Dunkel",
|
||||||
Auto: "Auto",
|
Auto: "Auto",
|
||||||
"Theme - Heartbeat Bar": "Thema - Zeitleiste",
|
"Theme - Heartbeat Bar": "Erscheinungsbild - Zeitleiste",
|
||||||
Normal: "Normal",
|
Normal: "Normal",
|
||||||
Bottom: "Unten",
|
Bottom: "Unten",
|
||||||
None: "Keine",
|
None: "Keine",
|
||||||
|
@ -71,15 +71,15 @@ export default {
|
||||||
"Allow indexing": "Indizierung zulassen",
|
"Allow indexing": "Indizierung zulassen",
|
||||||
"Discourage search engines from indexing site": "Halte Suchmaschinen von der Indexierung der Seite ab",
|
"Discourage search engines from indexing site": "Halte Suchmaschinen von der Indexierung der Seite ab",
|
||||||
"Change Password": "Passwort ändern",
|
"Change Password": "Passwort ändern",
|
||||||
"Current Password": "Derzeitiges Passwort",
|
"Current Password": "Aktuelles Passwort",
|
||||||
"New Password": "Neues Passwort",
|
"New Password": "Neues Passwort",
|
||||||
"Repeat New Password": "Neues Passwort wiederholen",
|
"Repeat New Password": "Neues Passwort wiederholen",
|
||||||
passwordNotMatchMsg: "Passwörter stimmen nicht überein. ",
|
passwordNotMatchMsg: "Passwörter stimmen nicht überein.",
|
||||||
"Update Password": "Passwort aktualisieren",
|
"Update Password": "Passwort aktualisieren",
|
||||||
"Disable Auth": "Authentifizierung deaktivieren",
|
"Disable Auth": "Authentifizierung deaktivieren",
|
||||||
"Enable Auth": "Authentifizierung aktivieren",
|
"Enable Auth": "Authentifizierung aktivieren",
|
||||||
Logout: "Ausloggen",
|
Logout: "Ausloggen",
|
||||||
notificationDescription: "Weise den Monitor(en) eine Benachrichtigung zu, damit diese Funktion greift.",
|
notificationDescription: "Benachrichtigungen müssen einem Monitor zugewiesen werden, damit diese funktionieren.",
|
||||||
Leave: "Verlassen",
|
Leave: "Verlassen",
|
||||||
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
|
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
|
||||||
Confirm: "Bestätigen",
|
Confirm: "Bestätigen",
|
||||||
|
@ -87,7 +87,7 @@ export default {
|
||||||
No: "Nein",
|
No: "Nein",
|
||||||
Username: "Benutzername",
|
Username: "Benutzername",
|
||||||
Password: "Passwort",
|
Password: "Passwort",
|
||||||
"Remember me": "Passwort merken",
|
"Remember me": "Angemeldet bleiben",
|
||||||
Login: "Einloggen",
|
Login: "Einloggen",
|
||||||
"No Monitors, please": "Keine Monitore, bitte",
|
"No Monitors, please": "Keine Monitore, bitte",
|
||||||
"add one": "hinzufügen",
|
"add one": "hinzufügen",
|
||||||
|
@ -98,7 +98,7 @@ export default {
|
||||||
keywordDescription: "Ein Suchwort in der HTML- oder JSON-Ausgabe finden. Bitte beachte: es wird zwischen Groß-/Kleinschreibung unterschieden.",
|
keywordDescription: "Ein Suchwort in der HTML- oder JSON-Ausgabe finden. Bitte beachte: es wird zwischen Groß-/Kleinschreibung unterschieden.",
|
||||||
deleteMonitorMsg: "Bist du sicher, dass du den Monitor löschen möchtest?",
|
deleteMonitorMsg: "Bist du sicher, dass du den Monitor löschen möchtest?",
|
||||||
deleteNotificationMsg: "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?",
|
deleteNotificationMsg: "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?",
|
||||||
resoverserverDescription: "Cloudflare ist als der Standardserver festgelegt, dieser kann jederzeit geändern werden.",
|
resolverserverDescription: "Cloudflare ist als der Standardserver festgelegt. Dieser kann jederzeit geändert werden.",
|
||||||
"Resolver Server": "Auflösungsserver",
|
"Resolver Server": "Auflösungsserver",
|
||||||
rrtypeDescription: "Wähle den RR-Typ aus, welchen du überwachen möchtest.",
|
rrtypeDescription: "Wähle den RR-Typ aus, welchen du überwachen möchtest.",
|
||||||
"Last Result": "Letztes Ergebnis",
|
"Last Result": "Letztes Ergebnis",
|
||||||
|
@ -110,8 +110,8 @@ export default {
|
||||||
Heartbeats: "Statistiken",
|
Heartbeats: "Statistiken",
|
||||||
confirmClearStatisticsMsg: "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
|
confirmClearStatisticsMsg: "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
|
||||||
"Create your admin account": "Erstelle dein Admin-Konto",
|
"Create your admin account": "Erstelle dein Admin-Konto",
|
||||||
"Repeat Password": "Wiederhole das Passwort",
|
"Repeat Password": "Passwort erneut eingeben",
|
||||||
"Resource Record Type": "Resource Record Type",
|
"Resource Record Type": "Ressourcen Record Typ",
|
||||||
Export: "Export",
|
Export: "Export",
|
||||||
Import: "Import",
|
Import: "Import",
|
||||||
respTime: "Antw.-Zeit (ms)",
|
respTime: "Antw.-Zeit (ms)",
|
||||||
|
@ -148,7 +148,7 @@ export default {
|
||||||
Token: "Token",
|
Token: "Token",
|
||||||
"Show URI": "URI anzeigen",
|
"Show URI": "URI anzeigen",
|
||||||
Tags: "Tags",
|
Tags: "Tags",
|
||||||
"Add New below or Select...": "Bestehenden Tag auswählen oder neuen hinzufügen...",
|
"Add New below or Select...": "Einen bestehenden Tag auswählen oder neuen hinzufügen...",
|
||||||
"Tag with this name already exist.": "Ein Tag mit diesem Namen existiert bereits.",
|
"Tag with this name already exist.": "Ein Tag mit diesem Namen existiert bereits.",
|
||||||
"Tag with this value already exist.": "Ein Tag mit diesem Wert existiert bereits.",
|
"Tag with this value already exist.": "Ein Tag mit diesem Wert existiert bereits.",
|
||||||
color: "Farbe",
|
color: "Farbe",
|
||||||
|
@ -162,8 +162,8 @@ export default {
|
||||||
Purple: "Lila",
|
Purple: "Lila",
|
||||||
Pink: "Pink",
|
Pink: "Pink",
|
||||||
"Search...": "Suchen...",
|
"Search...": "Suchen...",
|
||||||
"Heartbeat Retry Interval": "Heartbeat-Wiederholungsintervall",
|
"Heartbeat Retry Interval": "Überprüfungsintervall",
|
||||||
retryCheckEverySecond: "Versuche alle {0} Sekunden",
|
retryCheckEverySecond: "Alle {0} Sekunden neu versuchen",
|
||||||
"Import Backup": "Backup importieren",
|
"Import Backup": "Backup importieren",
|
||||||
"Export Backup": "Backup exportieren",
|
"Export Backup": "Backup exportieren",
|
||||||
"Avg. Ping": "Durchschn. Ping",
|
"Avg. Ping": "Durchschn. Ping",
|
||||||
|
@ -179,6 +179,7 @@ export default {
|
||||||
"Edit Status Page": "Bearbeite Status-Seite",
|
"Edit Status Page": "Bearbeite Status-Seite",
|
||||||
"Go to Dashboard": "Gehe zum Dashboard",
|
"Go to Dashboard": "Gehe zum Dashboard",
|
||||||
"Status Page": "Status-Seite",
|
"Status Page": "Status-Seite",
|
||||||
|
"Status Pages": "Status-Seite",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "E-Mail (SMTP)",
|
smtp: "E-Mail (SMTP)",
|
||||||
|
@ -202,7 +203,7 @@ export default {
|
||||||
"Push URL": "Push URL",
|
"Push URL": "Push URL",
|
||||||
needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen",
|
needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen",
|
||||||
pushOptionalParams: "Optionale Parameter: {0}",
|
pushOptionalParams: "Optionale Parameter: {0}",
|
||||||
defaultNotificationName: "Meine {notification} Alarm ({number})",
|
defaultNotificationName: "Mein {notification} Alarm ({number})",
|
||||||
here: "hier",
|
here: "hier",
|
||||||
Required: "Erforderlich",
|
Required: "Erforderlich",
|
||||||
"Bot Token": "Bot Token",
|
"Bot Token": "Bot Token",
|
||||||
|
@ -214,23 +215,23 @@ export default {
|
||||||
chatIDNotFound: "Chat-ID wurde nicht gefunden: bitte sende zuerst eine Nachricht an diesen Bot",
|
chatIDNotFound: "Chat-ID wurde nicht gefunden: bitte sende zuerst eine Nachricht an diesen Bot",
|
||||||
"Post URL": "Post URL",
|
"Post URL": "Post URL",
|
||||||
"Content Type": "Content Type",
|
"Content Type": "Content Type",
|
||||||
webhookJsonDesc: "{0} ist gut für alle modernen HTTP-Server sowie Express.js",
|
webhookJsonDesc: "{0} ist gut für alle modernen HTTP-Server, wie z.B. Express.js, geeignet",
|
||||||
webhookFormDataDesc: "{multipart} ist gut für PHP. Die JSON muss mit {decodeFunction} geparst werden",
|
webhookFormDataDesc: "{multipart} ist gut für PHP. Das JSON muss mit {decodeFunction} verarbeitet werden",
|
||||||
secureOptionNone: "Keine / STARTTLS (25, 587)",
|
secureOptionNone: "Keine / STARTTLS (25, 587)",
|
||||||
secureOptionTLS: "TLS (465)",
|
secureOptionTLS: "TLS (465)",
|
||||||
"Ignore TLS Error": "TLS-Fehler ignorieren",
|
"Ignore TLS Error": "TLS-Fehler ignorieren",
|
||||||
"From Email": "Von Email",
|
"From Email": "Absender E-Mail",
|
||||||
emailCustomSubject: "Benutzerdefinierter Betreff",
|
emailCustomSubject: "Benutzerdefinierter Betreff",
|
||||||
"To Email": "Zu Email",
|
"To Email": "Empfänger E-Mail",
|
||||||
smtpCC: "CC",
|
smtpCC: "CC",
|
||||||
smtpBCC: "BCC",
|
smtpBCC: "BCC",
|
||||||
"Discord Webhook URL": "Discord Webhook URL",
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
wayToGetDiscordURL: "Du kannst diesen erhalten, indem du zu den Servereinstellungen gehst -> Integrationen -> Neuer Webhook",
|
wayToGetDiscordURL: "Du kannst diese erhalten, indem du zu den Servereinstellungen gehst -> Integrationen -> Neuer Webhook",
|
||||||
"Bot Display Name": "Bot-Anzeigename",
|
"Bot Display Name": "Bot-Anzeigename",
|
||||||
"Prefix Custom Message": "Benutzerdefinierter Nachrichten Präfix",
|
"Prefix Custom Message": "Benutzerdefinierter Nachrichten Präfix",
|
||||||
"Hello @everyone is...": "Hallo {'@'}everyone ist...",
|
"Hello @everyone is...": "Hallo {'@'}everyone ist...",
|
||||||
"Webhook URL": "Webhook URL",
|
"Webhook URL": "Webhook URL",
|
||||||
wayToGetTeamsURL: "Hier erfährst du, wie eine Webhook-URL erstellt werden kann {0}.",
|
wayToGetTeamsURL: "Wie eine Webhook-URL erstellt werden kann, erfährst du {0}.",
|
||||||
Number: "Nummer",
|
Number: "Nummer",
|
||||||
Recipients: "Empfänger",
|
Recipients: "Empfänger",
|
||||||
needSignalAPI: "Es wird ein Signal Client mit REST-API benötigt.",
|
needSignalAPI: "Es wird ein Signal Client mit REST-API benötigt.",
|
||||||
|
@ -243,22 +244,22 @@ export default {
|
||||||
"Channel Name": "Kanalname",
|
"Channel Name": "Kanalname",
|
||||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
aboutWebhooks: "Weitere Informationen zu Webhooks auf: {0}",
|
aboutWebhooks: "Weitere Informationen zu Webhooks auf: {0}",
|
||||||
aboutChannelName: "Gebe den Kanalnamen ein auf {0} Feld Kanalname, wenn du den Webhook-Kanal umgehen möchtest. Ex: #other-channel",
|
aboutChannelName: "Gebe den Kanalnamen ein in {0} Feld Kanalname, falls du den Webhook-Kanal umgehen möchtest. Ex: #other-channel",
|
||||||
aboutKumaURL: "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird es standardmäßig die GitHub Projekt Seite verwenden.",
|
aboutKumaURL: "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird standardmäßig die GitHub Projekt Seite verwendet.",
|
||||||
emojiCheatSheet: "Emoji Cheat Sheet: {0}",
|
emojiCheatSheet: "Emoji Cheat Sheet: {0}",
|
||||||
"User Key": "Benutzerschlüssel",
|
"User Key": "Benutzerschlüssel",
|
||||||
Device: "Gerät",
|
Device: "Gerät",
|
||||||
"Message Title": "Nachrichtentitel",
|
"Message Title": "Nachrichtentitel",
|
||||||
"Notification Sound": "Benachrichtigungston",
|
"Notification Sound": "Benachrichtigungston",
|
||||||
"More info on:": "Mehr Infos auf: {0}",
|
"More info on:": "Mehr Infos auf: {0}",
|
||||||
pushoverDesc1: "Notfallpriorität (2) hat Standardmäßig 30 Sekunden Auszeit, zwischen den Versuchen und läuft nach 1 Stunde ab.",
|
pushoverDesc1: "Notfallpriorität (2) hat standardmäßig 30 Sekunden Auszeit zwischen den Versuchen und läuft nach 1 Stunde ab.",
|
||||||
pushoverDesc2: "Fülle das Geräte Feld aus, wenn du Benachrichtigungen an verschiedene Geräte senden möchtest.",
|
pushoverDesc2: "Fülle das Geräte Feld aus, wenn du Benachrichtigungen an verschiedene Geräte senden möchtest.",
|
||||||
"SMS Type": "SMS Typ",
|
"SMS Type": "SMS Typ",
|
||||||
octopushTypePremium: "Premium (Schnell - zur Benachrichtigung empfohlen)",
|
octopushTypePremium: "Premium (Schnell - zur Benachrichtigung empfohlen)",
|
||||||
octopushTypeLowCost: "Kostengünstig (Langsam - manchmal vom Betreiber gesperrt)",
|
octopushTypeLowCost: "Kostengünstig (Langsam - manchmal vom Betreiber gesperrt)",
|
||||||
checkPrice: "Prüfe {0} Preise:",
|
checkPrice: "Prüfe {0} Preise:",
|
||||||
octopushLegacyHint: "Verwendest du die Legacy-Version von Octopush (2011-2020) oder die neue Version?",
|
octopushLegacyHint: "Verwendest du die Legacy-Version von Octopush (2011-2020) oder die neue Version?",
|
||||||
"Check octopush prices": "Überprüfe die Oktopush Preise {0}.",
|
"Check octopush prices": "Vergleiche die Oktopush Preise {0}.",
|
||||||
octopushPhoneNumber: "Telefonnummer (Internationales Format, z.B : +49612345678) ",
|
octopushPhoneNumber: "Telefonnummer (Internationales Format, z.B : +49612345678) ",
|
||||||
octopushSMSSender: "Name des SMS-Absenders : 3-11 alphanumerische Zeichen und Leerzeichen (a-zA-Z0-9)",
|
octopushSMSSender: "Name des SMS-Absenders : 3-11 alphanumerische Zeichen und Leerzeichen (a-zA-Z0-9)",
|
||||||
"LunaSea Device ID": "LunaSea Geräte ID",
|
"LunaSea Device ID": "LunaSea Geräte ID",
|
||||||
|
@ -279,24 +280,24 @@ export default {
|
||||||
wayToGetLineChannelToken: "Rufe zuerst {0} auf, erstelle dann einen Provider und Channel (Messaging API). Als nächstes kannst du den Channel access token und die User ID aus den oben genannten Menüpunkten abrufen.",
|
wayToGetLineChannelToken: "Rufe zuerst {0} auf, erstelle dann einen Provider und Channel (Messaging API). Als nächstes kannst du den Channel access token und die User ID aus den oben genannten Menüpunkten abrufen.",
|
||||||
"Icon URL": "Icon URL",
|
"Icon URL": "Icon URL",
|
||||||
aboutIconURL: "Du kannst einen Link zu einem Bild in 'Icon URL' übergeben um das Standardprofilbild zu überschreiben. Wird nicht verwendet, wenn ein Icon Emoji gesetzt ist.",
|
aboutIconURL: "Du kannst einen Link zu einem Bild in 'Icon URL' übergeben um das Standardprofilbild zu überschreiben. Wird nicht verwendet, wenn ein Icon Emoji gesetzt ist.",
|
||||||
aboutMattermostChannelName: "Du kannst den Standardkanal, auf dem der Webhook postet überschreiben, indem der Kanalnamen in das Feld 'Channel Name' eingeben wird. Dies muss in den Mattermost Webhook-Einstellungen aktiviert werden. Ex: #other-channel",
|
aboutMattermostChannelName: "Du kannst den Standardkanal, auf dem der Webhook gesendet wird überschreiben, indem der Kanalnamen in das Feld 'Channel Name' eingeben wird. Dies muss in den Mattermost Webhook-Einstellungen aktiviert werden. Ex: #other-channel",
|
||||||
matrix: "Matrix",
|
matrix: "Matrix",
|
||||||
promosmsTypeEco: "SMS ECO - billig, aber langsam und oft überladen. Nur auf polnische Empfänger beschränkt.",
|
promosmsTypeEco: "SMS ECO - billig, aber langsam und oft überladen. Auf polnische Empfänger beschränkt.",
|
||||||
promosmsTypeFlash: "SMS FLASH - Die Nachricht wird automatisch auf dem Empfängergerät angezeigt. Nur auf polnische Empfänger beschränkt.",
|
promosmsTypeFlash: "SMS FLASH - Die Nachricht wird automatisch auf dem Empfängergerät angezeigt. Auf polnische Empfänger beschränkt.",
|
||||||
promosmsTypeFull: "SMS FULL - Premium Stufe von SMS, es kann der Absendernamen verwendet werden (Der Name musst zuerst registriert werden). Zuverlässig für Warnungen.",
|
promosmsTypeFull: "SMS FULL - Premium Stufe von SMS, es kann der Absendernamen verwendet werden (Der Name musst zuerst registriert werden). Zuverlässig für Warnungen.",
|
||||||
promosmsTypeSpeed: "SMS SPEED - Höchste Priorität im System. Sehr schnell und zuverlässig, aber teuer (Ungefähr das doppelte von SMS FULL).",
|
promosmsTypeSpeed: "SMS SPEED - Höchste Priorität im System. Sehr schnell und zuverlässig, aber teuer (Ungefähr das doppelte von SMS FULL).",
|
||||||
promosmsPhoneNumber: "Phone number (Für polnische Empfänger können die Vorwahlen übersprungen werden)",
|
promosmsPhoneNumber: "Telefonnummer (für polnische Empfänger können die Vorwahlen übersprungen werden)",
|
||||||
promosmsSMSSender: "Name des SMS-Absenders : vorregistrierter Name oder einer der Standardwerte: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
promosmsSMSSender: "Name des SMS-Absenders : vorregistrierter Name oder einer der Standardwerte: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
"Feishu WebHookUrl": "Feishu Webhook URL",
|
"Feishu WebHookUrl": "Feishu Webhook URL",
|
||||||
matrixHomeserverURL: "Heimserver URL (mit http(s):// und optionalen Ports)",
|
matrixHomeserverURL: "Heimserver URL (mit http(s):// und optionalen Ports)",
|
||||||
"Internal Room Id": "Interne Raum-ID",
|
"Internal Room Id": "Interne Raum-ID",
|
||||||
matrixDesc1: "Die interne Raum-ID findest du im erweiterten Bereich der Raumeinstellungen im Matrix-Client. Es sollte es aussehen wie z.B. !QMdRCpUIfLwsfjxye6:home.server.",
|
matrixDesc1: "Die interne Raum-ID findest du im erweiterten Bereich der Raumeinstellungen im Matrix-Client. Es sollte aussehen wie z.B. !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
matrixDesc2: "Es wird dringend empfohlen, dass ein neuen Benutzer erstellt wird und nicht den Zugriffstoken deines eigenen Matrix-Benutzers verwendest. Anderfalls ermöglicht es vollen Zugriff auf dein Konto und alle Räume, denen du beigetreten bist. Erstelle stattdessen einen neuen Benutzer und lade ihn nur in den Raum ein, in dem du die Benachrichtigung erhalten möchtest. Du kannst den Zugriffstoken erhalten, indem du folgendes ausführst {0}",
|
matrixDesc2: "Es wird dringend empfohlen einen neuen Benutzer anzulegen und nicht den Zugriffstoken deines eigenen Matrix-Benutzers zu verwenden. Anderenfalls ermöglicht es vollen Zugriff auf dein Konto und alle Räume, denen du beigetreten bist. Erstelle stattdessen einen neuen Benutzer und lade ihn nur in den Raum ein, in dem du die Benachrichtigung erhalten möchtest. Du kannst den Zugriffstoken erhalten, indem du Folgendes ausführst {0}",
|
||||||
Method: "Method",
|
Method: "Method",
|
||||||
Body: "Body",
|
Body: "Body",
|
||||||
Headers: "Headers",
|
Headers: "Headers",
|
||||||
PushUrl: "Push URL",
|
PushUrl: "Push URL",
|
||||||
HeadersInvalidFormat: "Die Header ist kein gültiges JSON: ",
|
HeadersInvalidFormat: "Der Header ist kein gültiges JSON: ",
|
||||||
BodyInvalidFormat: "Der Body ist kein gültiges JSON: ",
|
BodyInvalidFormat: "Der Body ist kein gültiges JSON: ",
|
||||||
"Monitor History": "Monitor Verlauf",
|
"Monitor History": "Monitor Verlauf",
|
||||||
clearDataOlderThan: "Bewahre die Monitor-Verlaufsdaten für {0} Tage auf.",
|
clearDataOlderThan: "Bewahre die Monitor-Verlaufsdaten für {0} Tage auf.",
|
||||||
|
@ -350,4 +351,15 @@ export default {
|
||||||
serwersmsPhoneNumber: "Telefonnummer",
|
serwersmsPhoneNumber: "Telefonnummer",
|
||||||
serwersmsSenderName: "Name des SMS-Absenders (über Kundenportal registriert)",
|
serwersmsSenderName: "Name des SMS-Absenders (über Kundenportal registriert)",
|
||||||
"stackfield": "Stackfield",
|
"stackfield": "Stackfield",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
|
apiCredentials: "API Zugangsdaten",
|
||||||
|
smtpDkimSettings: "DKIM Einstellungen",
|
||||||
|
smtpDkimDesc: "Details zur Konfiguration sind in der Nodemailer DKIM {0} zu finden.",
|
||||||
|
documentation: "Dokumentation",
|
||||||
|
smtpDkimDomain: "Domain Name",
|
||||||
|
smtpDkimKeySelector: "Schlüssel Auswahl",
|
||||||
|
smtpDkimPrivateKey: "Privater Schlüssel",
|
||||||
|
smtpDkimHashAlgo: "Hash-Algorithmus (Optional)",
|
||||||
|
smtpDkimheaderFieldNames: "Zu validierende Header-Schlüssel (optional)",
|
||||||
|
smtpDkimskipFields: "Zu ignorierende Header Schlüssel (optional)",
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Pause",
|
pauseDashboardHome: "Pause",
|
||||||
deleteMonitorMsg: "Are you sure want to delete this monitor?",
|
deleteMonitorMsg: "Are you sure want to delete this monitor?",
|
||||||
deleteNotificationMsg: "Are you sure want to delete this notification for all monitors?",
|
deleteNotificationMsg: "Are you sure want to delete this notification for all monitors?",
|
||||||
resoverserverDescription: "Cloudflare is the default server. You can change the resolver server anytime.",
|
resolverserverDescription: "Cloudflare is the default server. You can change the resolver server anytime.",
|
||||||
rrtypeDescription: "Select the RR type you want to monitor",
|
rrtypeDescription: "Select the RR type you want to monitor",
|
||||||
pauseMonitorMsg: "Are you sure want to pause?",
|
pauseMonitorMsg: "Are you sure want to pause?",
|
||||||
enableDefaultNotificationDescription: "This notification will be enabled by default for new monitors. You can still disable the notification separately for each monitor.",
|
enableDefaultNotificationDescription: "This notification will be enabled by default for new monitors. You can still disable the notification separately for each monitor.",
|
||||||
|
@ -183,6 +183,7 @@ export default {
|
||||||
"Edit Status Page": "Edit Status Page",
|
"Edit Status Page": "Edit Status Page",
|
||||||
"Go to Dashboard": "Go to Dashboard",
|
"Go to Dashboard": "Go to Dashboard",
|
||||||
"Status Page": "Status Page",
|
"Status Page": "Status Page",
|
||||||
|
"Status Pages": "Status Pages",
|
||||||
defaultNotificationName: "My {notification} Alert ({number})",
|
defaultNotificationName: "My {notification} Alert ({number})",
|
||||||
here: "here",
|
here: "here",
|
||||||
Required: "Required",
|
Required: "Required",
|
||||||
|
@ -238,6 +239,7 @@ export default {
|
||||||
"rocket.chat": "Rocket.Chat",
|
"rocket.chat": "Rocket.Chat",
|
||||||
pushover: "Pushover",
|
pushover: "Pushover",
|
||||||
pushy: "Pushy",
|
pushy: "Pushy",
|
||||||
|
PushByTechulus: "Push by Techulus",
|
||||||
octopush: "Octopush",
|
octopush: "Octopush",
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
clicksendsms: "ClickSend SMS",
|
clicksendsms: "ClickSend SMS",
|
||||||
|
@ -329,21 +331,21 @@ export default {
|
||||||
dark: "dark",
|
dark: "dark",
|
||||||
Post: "Post",
|
Post: "Post",
|
||||||
"Please input title and content": "Please input title and content",
|
"Please input title and content": "Please input title and content",
|
||||||
Created: "Created",
|
"Created": "Created",
|
||||||
"Last Updated": "Last Updated",
|
"Last Updated": "Last Updated",
|
||||||
Unpin: "Unpin",
|
"Unpin": "Unpin",
|
||||||
"Switch to Light Theme": "Switch to Light Theme",
|
"Switch to Light Theme": "Switch to Light Theme",
|
||||||
"Switch to Dark Theme": "Switch to Dark Theme",
|
"Switch to Dark Theme": "Switch to Dark Theme",
|
||||||
"Show Tags": "Show Tags",
|
"Show Tags": "Show Tags",
|
||||||
"Hide Tags": "Hide Tags",
|
"Hide Tags": "Hide Tags",
|
||||||
Description: "Description",
|
"Description": "Description",
|
||||||
"No monitors available.": "No monitors available.",
|
"No monitors available.": "No monitors available.",
|
||||||
"Add one": "Add one",
|
"Add one": "Add one",
|
||||||
"No Monitors": "No Monitors",
|
"No Monitors": "No Monitors",
|
||||||
"Untitled Group": "Untitled Group",
|
"Untitled Group": "Untitled Group",
|
||||||
Services: "Services",
|
"Services": "Services",
|
||||||
Discard: "Discard",
|
"Discard": "Discard",
|
||||||
Cancel: "Cancel",
|
"Cancel": "Cancel",
|
||||||
"Powered by": "Powered by",
|
"Powered by": "Powered by",
|
||||||
shrinkDatabaseDescription: "Trigger database VACUUM for SQLite. If your database is created after 1.10.0, AUTO_VACUUM is already enabled and this action is not needed.",
|
shrinkDatabaseDescription: "Trigger database VACUUM for SQLite. If your database is created after 1.10.0, AUTO_VACUUM is already enabled and this action is not needed.",
|
||||||
serwersms: "SerwerSMS.pl",
|
serwersms: "SerwerSMS.pl",
|
||||||
|
@ -351,7 +353,7 @@ export default {
|
||||||
serwersmsAPIPassword: "API Password",
|
serwersmsAPIPassword: "API Password",
|
||||||
serwersmsPhoneNumber: "Phone number",
|
serwersmsPhoneNumber: "Phone number",
|
||||||
serwersmsSenderName: "SMS Sender Name (registered via customer portal)",
|
serwersmsSenderName: "SMS Sender Name (registered via customer portal)",
|
||||||
"stackfield": "Stackfield",
|
stackfield: "Stackfield",
|
||||||
smtpDkimSettings: "DKIM Settings",
|
smtpDkimSettings: "DKIM Settings",
|
||||||
smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.",
|
smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.",
|
||||||
documentation: "documentation",
|
documentation: "documentation",
|
||||||
|
@ -361,4 +363,12 @@ export default {
|
||||||
smtpDkimHashAlgo: "Hash Algorithm (Optional)",
|
smtpDkimHashAlgo: "Hash Algorithm (Optional)",
|
||||||
smtpDkimheaderFieldNames: "Header Keys to sign (Optional)",
|
smtpDkimheaderFieldNames: "Header Keys to sign (Optional)",
|
||||||
smtpDkimskipFields: "Header Keys not to sign (Optional)",
|
smtpDkimskipFields: "Header Keys not to sign (Optional)",
|
||||||
|
gorush: "Gorush",
|
||||||
|
alerta: "Alerta",
|
||||||
|
alertaApiEndpoint: "API Endpoint",
|
||||||
|
alertaEnvironment: "Environment",
|
||||||
|
alertaApiKey: "API Key",
|
||||||
|
alertaAlertState: "Alert State",
|
||||||
|
alertaRecoverState: "Recover State",
|
||||||
|
deleteStatusPageMsg: "Are you sure want to delete this status page?",
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
pauseDashboardHome: "Pausado",
|
pauseDashboardHome: "Pausado",
|
||||||
deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?",
|
deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?",
|
||||||
deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?",
|
deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?",
|
||||||
resoverserverDescription: "Cloudflare es el servidor por defecto, puedes cambiar el servidor de resolución en cualquier momento.",
|
resolverserverDescription: "Cloudflare es el servidor por defecto, puedes cambiar el servidor de resolución en cualquier momento.",
|
||||||
rrtypeDescription: "Selecciona el tipo de registro que quieres monitorizar",
|
rrtypeDescription: "Selecciona el tipo de registro que quieres monitorizar",
|
||||||
pauseMonitorMsg: "¿Seguro que quieres pausar?",
|
pauseMonitorMsg: "¿Seguro que quieres pausar?",
|
||||||
Settings: "Ajustes",
|
Settings: "Ajustes",
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
"Edit Status Page": "Editar página de estado",
|
"Edit Status Page": "Editar página de estado",
|
||||||
"Go to Dashboard": "Ir al panel de control",
|
"Go to Dashboard": "Ir al panel de control",
|
||||||
"Status Page": "Página de estado",
|
"Status Page": "Página de estado",
|
||||||
|
"Status Pages": "Página de estado",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
|
|
@ -12,11 +12,12 @@ export default {
|
||||||
pauseDashboardHome: "Seisatud",
|
pauseDashboardHome: "Seisatud",
|
||||||
deleteMonitorMsg: "Kas soovid eemaldada seire?",
|
deleteMonitorMsg: "Kas soovid eemaldada seire?",
|
||||||
deleteNotificationMsg: "Kas soovid eemaldada selle teavitusteenuse kõikidelt seiretelt?",
|
deleteNotificationMsg: "Kas soovid eemaldada selle teavitusteenuse kõikidelt seiretelt?",
|
||||||
resoverserverDescription: "Cloudflare on vaikimisi pöördserver.",
|
resolverserverDescription: "Cloudflare on vaikimisi pöördserver.",
|
||||||
rrtypeDescription: "Vali kirje tüüp, mida soovid jälgida.",
|
rrtypeDescription: "Vali kirje tüüp, mida soovid jälgida.",
|
||||||
pauseMonitorMsg: "Kas soovid peatada seire?",
|
pauseMonitorMsg: "Kas soovid peatada seire?",
|
||||||
Settings: "Seaded",
|
Settings: "Seaded",
|
||||||
"Status Page": "Ülevaade",
|
"Status Page": "Ülevaade",
|
||||||
|
"Status Pages": "Ülevaated",
|
||||||
Dashboard: "Töölaud",
|
Dashboard: "Töölaud",
|
||||||
"New Update": "Uuem tarkvara versioon on saadaval.",
|
"New Update": "Uuem tarkvara versioon on saadaval.",
|
||||||
Language: "Keel",
|
Language: "Keel",
|
||||||
|
@ -197,4 +198,10 @@ export default {
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "LINE",
|
line: "LINE",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
alerta: "Alerta",
|
||||||
|
alertaApiEndpoint: "API otsik",
|
||||||
|
alertaEnvironment: "Keskkond",
|
||||||
|
alertaApiKey: "API võti",
|
||||||
|
alertaAlertState: "Häireseisund",
|
||||||
|
alertaRecoverState: "Taasta algolek",
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "متوقف شده",
|
pauseDashboardHome: "متوقف شده",
|
||||||
deleteMonitorMsg: "آیا از حذف این مانیتور مطمئن هستید؟",
|
deleteMonitorMsg: "آیا از حذف این مانیتور مطمئن هستید؟",
|
||||||
deleteNotificationMsg: "آیا مطمئن هستید که میخواهید این سرویس اطلاعرسانی را برای تمامی مانیتورها حذف کنید؟",
|
deleteNotificationMsg: "آیا مطمئن هستید که میخواهید این سرویس اطلاعرسانی را برای تمامی مانیتورها حذف کنید؟",
|
||||||
resoverserverDescription: "سرویس CloudFlare به عنوان سرور پیشفرض استفاده میشود، شما میتوانید آنرا به هر سرور دیگری بعدا تغییر دهید.",
|
resolverserverDescription: "سرویس CloudFlare به عنوان سرور پیشفرض استفاده میشود، شما میتوانید آنرا به هر سرور دیگری بعدا تغییر دهید.",
|
||||||
rrtypeDescription: "لطفا نوع Resource Record را انتخاب کنید.",
|
rrtypeDescription: "لطفا نوع Resource Record را انتخاب کنید.",
|
||||||
pauseMonitorMsg: "آیا مطمئن هستید که میخواهید این مانیتور را متوقف کنید ؟",
|
pauseMonitorMsg: "آیا مطمئن هستید که میخواهید این مانیتور را متوقف کنید ؟",
|
||||||
enableDefaultNotificationDescription: "برای هر مانیتور جدید، این سرویس اطلاعرسانی به صورت پیشفرض فعال خواهد شد. البته که شما میتوانید به صورت دستی آنرا برای هر مانیتور به صورت جداگانه غیر فعال کنید.",
|
enableDefaultNotificationDescription: "برای هر مانیتور جدید، این سرویس اطلاعرسانی به صورت پیشفرض فعال خواهد شد. البته که شما میتوانید به صورت دستی آنرا برای هر مانیتور به صورت جداگانه غیر فعال کنید.",
|
||||||
|
@ -178,6 +178,7 @@ export default {
|
||||||
"Add a monitor": "اضافه کردن مانیتور",
|
"Add a monitor": "اضافه کردن مانیتور",
|
||||||
"Edit Status Page": "ویرایش صفحه وضعیت",
|
"Edit Status Page": "ویرایش صفحه وضعیت",
|
||||||
"Status Page": "صفحه وضعیت",
|
"Status Page": "صفحه وضعیت",
|
||||||
|
"Status Pages": "صفحه وضعیت",
|
||||||
"Go to Dashboard": "رفتن به پیشخوان",
|
"Go to Dashboard": "رفتن به پیشخوان",
|
||||||
"Uptime Kuma": "آپتایم کوما",
|
"Uptime Kuma": "آپتایم کوما",
|
||||||
records: "مورد",
|
records: "مورد",
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "En pause",
|
pauseDashboardHome: "En pause",
|
||||||
deleteMonitorMsg: "Êtes-vous sûr de vouloir supprimer cette sonde ?",
|
deleteMonitorMsg: "Êtes-vous sûr de vouloir supprimer cette sonde ?",
|
||||||
deleteNotificationMsg: "Êtes-vous sûr de vouloir supprimer ce type de notifications ? Une fois désactivée, les services qui l'utilisent ne pourront plus envoyer de notifications.",
|
deleteNotificationMsg: "Êtes-vous sûr de vouloir supprimer ce type de notifications ? Une fois désactivée, les services qui l'utilisent ne pourront plus envoyer de notifications.",
|
||||||
resoverserverDescription: "Le DNS de Cloudflare est utilisé par défaut, mais vous pouvez le changer si vous le souhaitez.",
|
resolverserverDescription: "Le DNS de Cloudflare est utilisé par défaut, mais vous pouvez le changer si vous le souhaitez.",
|
||||||
rrtypeDescription: "Veuillez sélectionner un type d'enregistrement DNS",
|
rrtypeDescription: "Veuillez sélectionner un type d'enregistrement DNS",
|
||||||
pauseMonitorMsg: "Êtes-vous sûr de vouloir mettre en pause cette sonde ?",
|
pauseMonitorMsg: "Êtes-vous sûr de vouloir mettre en pause cette sonde ?",
|
||||||
enableDefaultNotificationDescription: "Pour chaque nouvelle sonde, cette notification sera activée par défaut. Vous pouvez toujours désactiver la notification séparément pour chaque sonde.",
|
enableDefaultNotificationDescription: "Pour chaque nouvelle sonde, cette notification sera activée par défaut. Vous pouvez toujours désactiver la notification séparément pour chaque sonde.",
|
||||||
|
@ -179,6 +179,7 @@ export default {
|
||||||
"Edit Status Page": "Modifier la page de statut",
|
"Edit Status Page": "Modifier la page de statut",
|
||||||
"Go to Dashboard": "Accéder au tableau de bord",
|
"Go to Dashboard": "Accéder au tableau de bord",
|
||||||
"Status Page": "Status Page",
|
"Status Page": "Status Page",
|
||||||
|
"Status Pages": "Status Pages",
|
||||||
defaultNotificationName: "Ma notification {notification} numéro ({number})",
|
defaultNotificationName: "Ma notification {notification} numéro ({number})",
|
||||||
here: "ici",
|
here: "ici",
|
||||||
Required: "Requis",
|
Required: "Requis",
|
||||||
|
@ -304,4 +305,9 @@ export default {
|
||||||
steamApiKeyDescription: "Pour surveiller un serveur Steam, vous avez besoin d'une clé Steam Web-API. Vous pouvez enregistrer votre clé ici : ",
|
steamApiKeyDescription: "Pour surveiller un serveur Steam, vous avez besoin d'une clé Steam Web-API. Vous pouvez enregistrer votre clé ici : ",
|
||||||
"Current User": "Utilisateur actuel",
|
"Current User": "Utilisateur actuel",
|
||||||
recent: "Récent",
|
recent: "Récent",
|
||||||
|
alertaApiEndpoint: "API Endpoint",
|
||||||
|
alertaEnvironment: "Environement",
|
||||||
|
alertaApiKey: "Clé de l'API",
|
||||||
|
alertaAlertState: "État de l'Alerte",
|
||||||
|
alertaRecoverState: "État de récupération",
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
keywordDescription: "Ključna riječ za pretragu, u obliku običnog HTML-a ili u JSON formatu. Pretraga je osjetljiva na velika i mala slova.",
|
keywordDescription: "Ključna riječ za pretragu, u obliku običnog HTML-a ili u JSON formatu. Pretraga je osjetljiva na velika i mala slova.",
|
||||||
deleteMonitorMsg: "Jeste li sigurni da želite izbrisati monitor?",
|
deleteMonitorMsg: "Jeste li sigurni da želite izbrisati monitor?",
|
||||||
deleteNotificationMsg: "Jeste li sigurni da želite izbrisati ovu obavijest za sve monitore?",
|
deleteNotificationMsg: "Jeste li sigurni da želite izbrisati ovu obavijest za sve monitore?",
|
||||||
resoverserverDescription: "Cloudflare je zadani DNS poslužitelj. Možete to promijeniti u bilo kojem trenutku.",
|
resolverserverDescription: "Cloudflare je zadani DNS poslužitelj. Možete to promijeniti u bilo kojem trenutku.",
|
||||||
rrtypeDescription: "Odaberite vrstu DNS zapisa o resursu kojeg želite pratiti",
|
rrtypeDescription: "Odaberite vrstu DNS zapisa o resursu kojeg želite pratiti",
|
||||||
pauseMonitorMsg: "Jeste li sigurni da želite pauzirati?",
|
pauseMonitorMsg: "Jeste li sigurni da želite pauzirati?",
|
||||||
enableDefaultNotificationDescription: "Ova će obavijesti biti omogućena za sve nove monitore. Možete ju ručno onemogućiti za pojedini monitor.",
|
enableDefaultNotificationDescription: "Ova će obavijesti biti omogućena za sve nove monitore. Možete ju ručno onemogućiti za pojedini monitor.",
|
||||||
|
@ -183,6 +183,7 @@ export default {
|
||||||
"Edit Status Page": "Uredi Statusnu stranicu",
|
"Edit Status Page": "Uredi Statusnu stranicu",
|
||||||
"Go to Dashboard": "Na Kontrolnu ploču",
|
"Go to Dashboard": "Na Kontrolnu ploču",
|
||||||
"Status Page": "Statusna stranica",
|
"Status Page": "Statusna stranica",
|
||||||
|
"Status Pages": "Statusna stranica",
|
||||||
defaultNotificationName: "Moja {number}. {notification} obavijest",
|
defaultNotificationName: "Moja {number}. {notification} obavijest",
|
||||||
here: "ovdje",
|
here: "ovdje",
|
||||||
Required: "Potrebno",
|
Required: "Potrebno",
|
||||||
|
@ -338,9 +339,8 @@ export default {
|
||||||
"Hide Tags": "Sakrij oznake",
|
"Hide Tags": "Sakrij oznake",
|
||||||
Description: "Opis",
|
Description: "Opis",
|
||||||
"No monitors available.": "Nema dostupnih monitora.",
|
"No monitors available.": "Nema dostupnih monitora.",
|
||||||
"Add one": "Add one",
|
|
||||||
"No Monitors": "Bez monitora",
|
|
||||||
"Add one": "Stvori jednog",
|
"Add one": "Stvori jednog",
|
||||||
|
"No Monitors": "Bez monitora",
|
||||||
"Untitled Group": "Bezimena grupa",
|
"Untitled Group": "Bezimena grupa",
|
||||||
Services: "Usluge",
|
Services: "Usluge",
|
||||||
Discard: "Odbaci",
|
Discard: "Odbaci",
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Szünetel",
|
pauseDashboardHome: "Szünetel",
|
||||||
deleteMonitorMsg: "Biztos, hogy törölni akarja ezt a figyelőt?",
|
deleteMonitorMsg: "Biztos, hogy törölni akarja ezt a figyelőt?",
|
||||||
deleteNotificationMsg: "Biztos, hogy törölni akarja ezt az értesítést az összes figyelőnél?",
|
deleteNotificationMsg: "Biztos, hogy törölni akarja ezt az értesítést az összes figyelőnél?",
|
||||||
resoverserverDescription: "A Cloudflare az alapértelmezett szerver, bármikor meg tudja változtatni a resolver server-t.",
|
resolverserverDescription: "A Cloudflare az alapértelmezett szerver, bármikor meg tudja változtatni a resolver server-t.",
|
||||||
rrtypeDescription: "Válassza ki az RR-típust a figyelőhöz",
|
rrtypeDescription: "Válassza ki az RR-típust a figyelőhöz",
|
||||||
pauseMonitorMsg: "Biztos, hogy szüneteltetni akarja?",
|
pauseMonitorMsg: "Biztos, hogy szüneteltetni akarja?",
|
||||||
enableDefaultNotificationDescription: "Minden új figyelőhöz ez az értesítés engedélyezett lesz alapértelmezetten. Kikapcsolhatja az értesítést külön minden figyelőnél.",
|
enableDefaultNotificationDescription: "Minden új figyelőhöz ez az értesítés engedélyezett lesz alapértelmezetten. Kikapcsolhatja az értesítést külön minden figyelőnél.",
|
||||||
|
@ -197,6 +197,7 @@ export default {
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
"Status Page": "Státusz oldal",
|
"Status Page": "Státusz oldal",
|
||||||
|
"Status Pages": "Státusz oldal",
|
||||||
"Primary Base URL": "Elsődleges URL",
|
"Primary Base URL": "Elsődleges URL",
|
||||||
"Push URL": "Meghívandó URL",
|
"Push URL": "Meghívandó URL",
|
||||||
needPushEvery: "Ezt az URL-t kell meghívni minden {0} másodpercben.",
|
needPushEvery: "Ezt az URL-t kell meghívni minden {0} másodpercben.",
|
||||||
|
@ -350,4 +351,23 @@ export default {
|
||||||
serwersmsAPIPassword: "API jelszó",
|
serwersmsAPIPassword: "API jelszó",
|
||||||
serwersmsPhoneNumber: "Telefonszám",
|
serwersmsPhoneNumber: "Telefonszám",
|
||||||
serwersmsSenderName: "SMS feladó neve (regisztrált név az oldalon)",
|
serwersmsSenderName: "SMS feladó neve (regisztrált név az oldalon)",
|
||||||
|
GoogleChat: "Google Chat (csak Google Workspace)",
|
||||||
|
stackfield: "Stackfield",
|
||||||
|
smtpDkimSettings: "DKIM beállítások",
|
||||||
|
smtpDkimDesc: "Nézze meg a Nodemailer DKIM {0} használati szabályokat.",
|
||||||
|
documentation: "dokumentáció",
|
||||||
|
smtpDkimDomain: "Domain név",
|
||||||
|
smtpDkimKeySelector: "Kulcs választó",
|
||||||
|
smtpDkimPrivateKey: "Privát kulcs",
|
||||||
|
smtpDkimHashAlgo: "Hash algoritmus (nem kötelező)",
|
||||||
|
smtpDkimheaderFieldNames: "Fejléc kulcsok a bejelentkezéshez (nem kötelező)",
|
||||||
|
smtpDkimskipFields: "Fejléc kulcsok egyéb esetben (nem kötelező)",
|
||||||
|
PushByTechulus: "Techulus push",
|
||||||
|
gorush: "Gorush",
|
||||||
|
alerta: "Alerta",
|
||||||
|
alertaApiEndpoint: "API végpont",
|
||||||
|
alertaEnvironment: "Környezet",
|
||||||
|
alertaApiKey: "API kulcs",
|
||||||
|
alertaAlertState: "Figyelmeztetési állapot",
|
||||||
|
alertaRecoverState: "Visszaállási állapot",
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Jeda",
|
pauseDashboardHome: "Jeda",
|
||||||
deleteMonitorMsg: "Apakah Anda mau menghapus monitor ini?",
|
deleteMonitorMsg: "Apakah Anda mau menghapus monitor ini?",
|
||||||
deleteNotificationMsg: "Apakah Anda mau menghapus notifikasi untuk semua monitor?",
|
deleteNotificationMsg: "Apakah Anda mau menghapus notifikasi untuk semua monitor?",
|
||||||
resoverserverDescription: "Cloudflare adalah server bawaan, Anda dapat mengubah server resolver kapan saja.",
|
resolverserverDescription: "Cloudflare adalah server bawaan, Anda dapat mengubah server resolver kapan saja.",
|
||||||
rrtypeDescription: "Pilih RR-Type yang mau Anda monitor",
|
rrtypeDescription: "Pilih RR-Type yang mau Anda monitor",
|
||||||
pauseMonitorMsg: "Apakah Anda yakin mau menjeda?",
|
pauseMonitorMsg: "Apakah Anda yakin mau menjeda?",
|
||||||
enableDefaultNotificationDescription: "Untuk setiap monitor baru, notifikasi ini akan diaktifkan secara bawaan. Anda masih dapat menonaktifkan notifikasi secara terpisah untuk setiap monitor.",
|
enableDefaultNotificationDescription: "Untuk setiap monitor baru, notifikasi ini akan diaktifkan secara bawaan. Anda masih dapat menonaktifkan notifikasi secara terpisah untuk setiap monitor.",
|
||||||
|
@ -179,6 +179,7 @@ export default {
|
||||||
"Edit Status Page": "Edit Halaman Status",
|
"Edit Status Page": "Edit Halaman Status",
|
||||||
"Go to Dashboard": "Pergi ke Dasbor",
|
"Go to Dashboard": "Pergi ke Dasbor",
|
||||||
"Status Page": "Halaman Status",
|
"Status Page": "Halaman Status",
|
||||||
|
"Status Pages": "Halaman Status",
|
||||||
defaultNotificationName: "{notification} saya Peringatan ({number})",
|
defaultNotificationName: "{notification} saya Peringatan ({number})",
|
||||||
here: "di sini",
|
here: "di sini",
|
||||||
Required: "Dibutuhkan",
|
Required: "Dibutuhkan",
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "In Pausa",
|
pauseDashboardHome: "In Pausa",
|
||||||
deleteMonitorMsg: "Si è certi di voler eliminare questo oggetto monitorato?",
|
deleteMonitorMsg: "Si è certi di voler eliminare questo oggetto monitorato?",
|
||||||
deleteNotificationMsg: "Si è certi di voler eliminare questa notifica per tutti gli oggetti monitorati?",
|
deleteNotificationMsg: "Si è certi di voler eliminare questa notifica per tutti gli oggetti monitorati?",
|
||||||
resoverserverDescription: "Cloudflare è il server predefinito, è possibile cambiare il server DNS.",
|
resolverserverDescription: "Cloudflare è il server predefinito, è possibile cambiare il server DNS.",
|
||||||
rrtypeDescription: "Scegliere il tipo di RR che si vuole monitorare",
|
rrtypeDescription: "Scegliere il tipo di RR che si vuole monitorare",
|
||||||
pauseMonitorMsg: "Si è certi di voler mettere in pausa?",
|
pauseMonitorMsg: "Si è certi di voler mettere in pausa?",
|
||||||
enableDefaultNotificationDescription: "Per ogni nuovo monitor questa notifica sarà abilitata di default. È comunque possibile disabilitare la notifica singolarmente.",
|
enableDefaultNotificationDescription: "Per ogni nuovo monitor questa notifica sarà abilitata di default. È comunque possibile disabilitare la notifica singolarmente.",
|
||||||
|
@ -183,6 +183,7 @@ export default {
|
||||||
"Edit Status Page": "Modifica pagina di stato",
|
"Edit Status Page": "Modifica pagina di stato",
|
||||||
"Go to Dashboard": "Vai alla dashboard",
|
"Go to Dashboard": "Vai alla dashboard",
|
||||||
"Status Page": "Pagina di stato",
|
"Status Page": "Pagina di stato",
|
||||||
|
"Status Pages": "Pagina di stato",
|
||||||
defaultNotificationName: "Notifica {notification} ({number})",
|
defaultNotificationName: "Notifica {notification} ({number})",
|
||||||
here: "qui",
|
here: "qui",
|
||||||
Required: "Obbligatorio",
|
Required: "Obbligatorio",
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
pauseDashboardHome: "一時停止",
|
pauseDashboardHome: "一時停止",
|
||||||
deleteMonitorMsg: "この監視を削除してよろしいですか?",
|
deleteMonitorMsg: "この監視を削除してよろしいですか?",
|
||||||
deleteNotificationMsg: "全ての監視のこの通知を削除してよろしいですか?",
|
deleteNotificationMsg: "全ての監視のこの通知を削除してよろしいですか?",
|
||||||
resoverserverDescription: "Cloudflareがデフォルトのサーバーですが、いつでもリゾルバサーバーを変更できます。",
|
resolverserverDescription: "Cloudflareがデフォルトのサーバーですが、いつでもリゾルバサーバーを変更できます。",
|
||||||
rrtypeDescription: "監視するRRタイプを選択します",
|
rrtypeDescription: "監視するRRタイプを選択します",
|
||||||
pauseMonitorMsg: "一時停止しますか?",
|
pauseMonitorMsg: "一時停止しますか?",
|
||||||
Settings: "設定",
|
Settings: "設定",
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
"Edit Status Page": "ステータスページ編集",
|
"Edit Status Page": "ステータスページ編集",
|
||||||
"Go to Dashboard": "ダッシュボード",
|
"Go to Dashboard": "ダッシュボード",
|
||||||
"Status Page": "ステータスページ",
|
"Status Page": "ステータスページ",
|
||||||
|
"Status Pages": "ステータスページ",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "일시 정지",
|
pauseDashboardHome: "일시 정지",
|
||||||
deleteMonitorMsg: "정말 이 모니터링을 삭제할까요?",
|
deleteMonitorMsg: "정말 이 모니터링을 삭제할까요?",
|
||||||
deleteNotificationMsg: "정말 이 알림을 모든 모니터링에서 삭제할까요?",
|
deleteNotificationMsg: "정말 이 알림을 모든 모니터링에서 삭제할까요?",
|
||||||
resoverserverDescription: "Cloudflare가 기본 서버예요, 원한다면 언제나 다른 Resolver 서버로 변경할 수 있어요.",
|
resolverserverDescription: "Cloudflare가 기본 서버예요, 원한다면 언제나 다른 Resolver 서버로 변경할 수 있어요.",
|
||||||
rrtypeDescription: "모니터링할 RR-Type을 선택해요.",
|
rrtypeDescription: "모니터링할 RR-Type을 선택해요.",
|
||||||
pauseMonitorMsg: "정말 이 모니터링을 일시 정지할까요?",
|
pauseMonitorMsg: "정말 이 모니터링을 일시 정지할까요?",
|
||||||
enableDefaultNotificationDescription: "새로 추가하는 모든 모니터링에 이 알림을 기본적으로 활성화해요. 각 모니터에 대해 별도로 알림을 비활성화할 수 있어요.",
|
enableDefaultNotificationDescription: "새로 추가하는 모든 모니터링에 이 알림을 기본적으로 활성화해요. 각 모니터에 대해 별도로 알림을 비활성화할 수 있어요.",
|
||||||
|
@ -179,6 +179,7 @@ export default {
|
||||||
"Edit Status Page": "상태 페이지 수정",
|
"Edit Status Page": "상태 페이지 수정",
|
||||||
"Go to Dashboard": "대시보드로 가기",
|
"Go to Dashboard": "대시보드로 가기",
|
||||||
"Status Page": "상태 페이지",
|
"Status Page": "상태 페이지",
|
||||||
|
"Status Pages": "상태 페이지",
|
||||||
defaultNotificationName: "내 {notification} 알림 ({number})",
|
defaultNotificationName: "내 {notification} 알림 ({number})",
|
||||||
here: "여기",
|
here: "여기",
|
||||||
Required: "필수",
|
Required: "필수",
|
||||||
|
@ -188,7 +189,7 @@ export default {
|
||||||
"Chat ID": "채팅 ID",
|
"Chat ID": "채팅 ID",
|
||||||
supportTelegramChatID: "Direct Chat / Group / Channel's Chat ID를 지원해요.",
|
supportTelegramChatID: "Direct Chat / Group / Channel's Chat ID를 지원해요.",
|
||||||
wayToGetTelegramChatID: "봇에 메시지를 보내 채팅 ID를 얻고 밑에 URL로 이동해 chat_id를 볼 수 있어요.",
|
wayToGetTelegramChatID: "봇에 메시지를 보내 채팅 ID를 얻고 밑에 URL로 이동해 chat_id를 볼 수 있어요.",
|
||||||
"YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE",
|
"YOUR BOT TOKEN HERE": "여기에 BOT 토큰을 적어주세요.",
|
||||||
chatIDNotFound: "채팅 ID를 찾을 수 없어요. 먼저 봇에게 메시지를 보내주세요.",
|
chatIDNotFound: "채팅 ID를 찾을 수 없어요. 먼저 봇에게 메시지를 보내주세요.",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
"Post URL": "Post URL",
|
"Post URL": "Post URL",
|
||||||
|
@ -281,15 +282,15 @@ export default {
|
||||||
promosmsSMSSender: "SMS 보내는 사람 이름 : 미리 등록된 이름 혹은 기본값 중 하나예요: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
promosmsSMSSender: "SMS 보내는 사람 이름 : 미리 등록된 이름 혹은 기본값 중 하나예요: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
"Primary Base URL": "기본 URL",
|
"Primary Base URL": "기본 URL",
|
||||||
"Push URL": "Push URL",
|
"Push URL": "Push URL",
|
||||||
needPushEvery: "You should call this URL every {0} seconds.",
|
needPushEvery: "이 URL을 {0} 초 마다 호출할 수 있어요.",
|
||||||
pushOptionalParams: "Optional parameters: {0}",
|
pushOptionalParams: "선택적 파라미터: {0}",
|
||||||
emailCustomSubject: "Custom Subject",
|
emailCustomSubject: "커스텀 주제",
|
||||||
clicksendsms: "ClickSend SMS",
|
clicksendsms: "ClickSend SMS",
|
||||||
checkPrice: "{0} 가격 확인:",
|
checkPrice: "{0} 가격 확인:",
|
||||||
apiCredentials: "API credentials",
|
apiCredentials: "API 인증정보",
|
||||||
octopushLegacyHint: "Octopush 레거시 버전 (2011-2020) 을 사용하시나요? 아니면 새 버전을 사용하시나요?",
|
octopushLegacyHint: "Octopush 레거시 버전 (2011-2020) 을 사용하시나요? 아니면 새 버전을 사용하시나요?",
|
||||||
"Feishu WebHookUrl": "Feishu WebHookURL",
|
"Feishu WebHookUrl": "Feishu WebHookURL",
|
||||||
matrixHomeserverURL: "Homeserver URL (with http(s):// and optionally port)",
|
matrixHomeserverURL: "Homeserver URL (http(s):// 와 함께 적어주세요. 그리고 포트 번호는 선택적 입니다.)",
|
||||||
"Internal Room Id": "내부 방 ID",
|
"Internal Room Id": "내부 방 ID",
|
||||||
matrixDesc1: "Matrix 클라이언트 방 설정의 고급 섹션에서 내부 방 ID를 찾을 수 있어요. 내부 방 ID는 이렇게 생겼답니다: !QMdRCpUIfLwsfjxye6:home.server.",
|
matrixDesc1: "Matrix 클라이언트 방 설정의 고급 섹션에서 내부 방 ID를 찾을 수 있어요. 내부 방 ID는 이렇게 생겼답니다: !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
matrixDesc2: "사용자의 모든 방에 대한 엑세스가 허용될 수 있어서 새로운 사용자를 만들고 원하는 방에만 초대한 후 엑세스 토큰을 사용하는 것이 좋아요. {0} 이 명령어를 통해 엑세스 토큰을 얻을 수 있어요.",
|
matrixDesc2: "사용자의 모든 방에 대한 엑세스가 허용될 수 있어서 새로운 사용자를 만들고 원하는 방에만 초대한 후 엑세스 토큰을 사용하는 것이 좋아요. {0} 이 명령어를 통해 엑세스 토큰을 얻을 수 있어요.",
|
||||||
|
@ -349,6 +350,6 @@ export default {
|
||||||
serwersmsAPIUser: "API Usename (webapi_ 접두사 포함)",
|
serwersmsAPIUser: "API Usename (webapi_ 접두사 포함)",
|
||||||
serwersmsAPIPassword: "API 비밀번호",
|
serwersmsAPIPassword: "API 비밀번호",
|
||||||
serwersmsPhoneNumber: "휴대전화 번호",
|
serwersmsPhoneNumber: "휴대전화 번호",
|
||||||
serwersmsSenderName: "보내는 사람 이름 (registered via customer portal)",
|
serwersmsSenderName: "보내는 사람 이름 (customer portal를 통해 가입된 정보)",
|
||||||
stackfield: "Stackfield",
|
stackfield: "Stackfield",
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Pause",
|
pauseDashboardHome: "Pause",
|
||||||
deleteMonitorMsg: "Er du sikker på at du vil slette denne overvåkningen?",
|
deleteMonitorMsg: "Er du sikker på at du vil slette denne overvåkningen?",
|
||||||
deleteNotificationMsg: "Er du sikker på at du vil slette dette varselet for alle overvåkningene?",
|
deleteNotificationMsg: "Er du sikker på at du vil slette dette varselet for alle overvåkningene?",
|
||||||
resoverserverDescription: "Cloudflare er standardserveren. Du kan endre DNS-serveren når som helst.",
|
resolverserverDescription: "Cloudflare er standardserveren. Du kan endre DNS-serveren når som helst.",
|
||||||
rrtypeDescription: "Velg RR-typen du vil overvåke",
|
rrtypeDescription: "Velg RR-typen du vil overvåke",
|
||||||
pauseMonitorMsg: "Er du sikker på at du vil sette på pause?",
|
pauseMonitorMsg: "Er du sikker på at du vil sette på pause?",
|
||||||
enableDefaultNotificationDescription: "For hver ny overvåkning vil denne varslingen være aktivert som standard. Du kan fortsatt deaktivere varselet separat for hver overvåkning.",
|
enableDefaultNotificationDescription: "For hver ny overvåkning vil denne varslingen være aktivert som standard. Du kan fortsatt deaktivere varselet separat for hver overvåkning.",
|
||||||
|
@ -179,6 +179,7 @@ export default {
|
||||||
"Edit Status Page": "Rediger statusside",
|
"Edit Status Page": "Rediger statusside",
|
||||||
"Go to Dashboard": "Gå til Dashboard",
|
"Go to Dashboard": "Gå til Dashboard",
|
||||||
"Status Page": "Statusside",
|
"Status Page": "Statusside",
|
||||||
|
"Status Pages": "Statusside",
|
||||||
defaultNotificationName: "Min {notification} varsling ({number})",
|
defaultNotificationName: "Min {notification} varsling ({number})",
|
||||||
here: "her",
|
here: "her",
|
||||||
Required: "Obligatorisk",
|
Required: "Obligatorisk",
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
pauseDashboardHome: "Gepauzeerd",
|
pauseDashboardHome: "Gepauzeerd",
|
||||||
deleteMonitorMsg: "Weet u zeker dat u deze monitor wilt verwijderen?",
|
deleteMonitorMsg: "Weet u zeker dat u deze monitor wilt verwijderen?",
|
||||||
deleteNotificationMsg: "Weet u zeker dat u deze melding voor alle monitoren wilt verwijderen?",
|
deleteNotificationMsg: "Weet u zeker dat u deze melding voor alle monitoren wilt verwijderen?",
|
||||||
resoverserverDescription: "Cloudflare is de standaardserver, u kunt de resolver server op elk moment wijzigen.",
|
resolverserverDescription: "Cloudflare is de standaardserver, u kunt de resolver server op elk moment wijzigen.",
|
||||||
rrtypeDescription: "Selecteer het RR-type dat u wilt monitoren",
|
rrtypeDescription: "Selecteer het RR-type dat u wilt monitoren",
|
||||||
pauseMonitorMsg: "Weet je zeker dat je wilt pauzeren?",
|
pauseMonitorMsg: "Weet je zeker dat je wilt pauzeren?",
|
||||||
enableDefaultNotificationDescription: "Voor elke nieuwe monitor wordt deze melding standaard ingeschakeld. U kunt de melding nog steeds afzonderlijk uitschakelen voor elke monitor.",
|
enableDefaultNotificationDescription: "Voor elke nieuwe monitor wordt deze melding standaard ingeschakeld. U kunt de melding nog steeds afzonderlijk uitschakelen voor elke monitor.",
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
"Edit Status Page": "Wijzig status pagina",
|
"Edit Status Page": "Wijzig status pagina",
|
||||||
"Go to Dashboard": "Ga naar Dashboard",
|
"Go to Dashboard": "Ga naar Dashboard",
|
||||||
"Status Page": "Status Pagina",
|
"Status Page": "Status Pagina",
|
||||||
|
"Status Pages": "Status Pagina",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Wstrzymane",
|
pauseDashboardHome: "Wstrzymane",
|
||||||
deleteMonitorMsg: "Czy na pewno chcesz usunąć ten monitor?",
|
deleteMonitorMsg: "Czy na pewno chcesz usunąć ten monitor?",
|
||||||
deleteNotificationMsg: "Czy na pewno chcesz usunąć to powiadomienie dla wszystkich monitorów?",
|
deleteNotificationMsg: "Czy na pewno chcesz usunąć to powiadomienie dla wszystkich monitorów?",
|
||||||
resoverserverDescription: "Cloudflare jest domyślnym serwerem, możesz zmienić serwer resolver w każdej chwili.",
|
resolverserverDescription: "Cloudflare jest domyślnym serwerem, możesz zmienić serwer resolver w każdej chwili.",
|
||||||
rrtypeDescription: "Wybierz rodzaj rekordu, który chcesz monitorować.",
|
rrtypeDescription: "Wybierz rodzaj rekordu, który chcesz monitorować.",
|
||||||
pauseMonitorMsg: "Czy na pewno chcesz wstrzymać monitorowanie?",
|
pauseMonitorMsg: "Czy na pewno chcesz wstrzymać monitorowanie?",
|
||||||
enableDefaultNotificationDescription: "Dla każdego nowego monitora to powiadomienie będzie domyślnie włączone. Nadal możesz wyłączyć powiadomienia osobno dla każdego monitora.",
|
enableDefaultNotificationDescription: "Dla każdego nowego monitora to powiadomienie będzie domyślnie włączone. Nadal możesz wyłączyć powiadomienia osobno dla każdego monitora.",
|
||||||
|
@ -179,6 +179,7 @@ export default {
|
||||||
"Edit Status Page": "Edytuj stronę statusu",
|
"Edit Status Page": "Edytuj stronę statusu",
|
||||||
"Go to Dashboard": "Idź do panelu",
|
"Go to Dashboard": "Idź do panelu",
|
||||||
"Status Page": "Strona statusu",
|
"Status Page": "Strona statusu",
|
||||||
|
"Status Pages": "Strona statusu",
|
||||||
defaultNotificationName: "Moje powiadomienie {notification} ({number})",
|
defaultNotificationName: "Moje powiadomienie {notification} ({number})",
|
||||||
here: "tutaj",
|
here: "tutaj",
|
||||||
Required: "Wymagane",
|
Required: "Wymagane",
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Pausar",
|
pauseDashboardHome: "Pausar",
|
||||||
deleteMonitorMsg: "Tem certeza de que deseja excluir este monitor?",
|
deleteMonitorMsg: "Tem certeza de que deseja excluir este monitor?",
|
||||||
deleteNotificationMsg: "Tem certeza de que deseja excluir esta notificação para todos os monitores?",
|
deleteNotificationMsg: "Tem certeza de que deseja excluir esta notificação para todos os monitores?",
|
||||||
resoverserverDescription: "Cloudflare é o servidor padrão, você pode alterar o servidor resolvedor a qualquer momento.",
|
resolverserverDescription: "Cloudflare é o servidor padrão, você pode alterar o servidor resolvedor a qualquer momento.",
|
||||||
rrtypeDescription: "Selecione o RR-Type que você deseja monitorar",
|
rrtypeDescription: "Selecione o RR-Type que você deseja monitorar",
|
||||||
pauseMonitorMsg: "Tem certeza que deseja fazer uma pausa?",
|
pauseMonitorMsg: "Tem certeza que deseja fazer uma pausa?",
|
||||||
enableDefaultNotificationDescription: "Para cada novo monitor, esta notificação será habilitada por padrão. Você ainda pode desativar a notificação separadamente para cada monitor.",
|
enableDefaultNotificationDescription: "Para cada novo monitor, esta notificação será habilitada por padrão. Você ainda pode desativar a notificação separadamente para cada monitor.",
|
||||||
|
@ -169,6 +169,7 @@ export default {
|
||||||
"Avg. Ping": "Ping Médio.",
|
"Avg. Ping": "Ping Médio.",
|
||||||
"Avg. Response": "Resposta Média. ",
|
"Avg. Response": "Resposta Média. ",
|
||||||
"Status Page": "Página de Status",
|
"Status Page": "Página de Status",
|
||||||
|
"Status Pages": "Página de Status",
|
||||||
"Entry Page": "Página de entrada",
|
"Entry Page": "Página de entrada",
|
||||||
statusPageNothing: "Nada aqui, por favor, adicione um grupo ou monitor.",
|
statusPageNothing: "Nada aqui, por favor, adicione um grupo ou monitor.",
|
||||||
"No Services": "Nenhum Serviço",
|
"No Services": "Nenhum Serviço",
|
||||||
|
|
|
@ -12,11 +12,11 @@ export default {
|
||||||
pauseDashboardHome: "Пауза",
|
pauseDashboardHome: "Пауза",
|
||||||
deleteMonitorMsg: "Вы действительно хотите удалить данный монитор?",
|
deleteMonitorMsg: "Вы действительно хотите удалить данный монитор?",
|
||||||
deleteNotificationMsg: "Вы действительно хотите удалить это уведомление для всех мониторов?",
|
deleteNotificationMsg: "Вы действительно хотите удалить это уведомление для всех мониторов?",
|
||||||
resoverserverDescription: "Cloudflare является сервером по умолчанию. Вы всегда можете сменить данный сервер.",
|
resolverserverDescription: "Cloudflare является сервером по умолчанию. Вы всегда можете сменить данный сервер.",
|
||||||
rrtypeDescription: "Выберите тип ресурсной записи, который вы хотите отслеживать",
|
rrtypeDescription: "Выберите тип ресурсной записи, который вы хотите отслеживать",
|
||||||
pauseMonitorMsg: "Вы действительно хотите поставить на паузу?",
|
pauseMonitorMsg: "Вы действительно хотите поставить на паузу?",
|
||||||
Settings: "Настройки",
|
Settings: "Настройки",
|
||||||
Dashboard: "Панель мониторов",
|
Dashboard: "Панель управления",
|
||||||
"New Update": "Обновление",
|
"New Update": "Обновление",
|
||||||
Language: "Язык",
|
Language: "Язык",
|
||||||
Appearance: "Внешний вид",
|
Appearance: "Внешний вид",
|
||||||
|
@ -60,7 +60,7 @@ export default {
|
||||||
"Heartbeat Interval": "Частота опроса",
|
"Heartbeat Interval": "Частота опроса",
|
||||||
Retries: "Попыток",
|
Retries: "Попыток",
|
||||||
Advanced: "Дополнительно",
|
Advanced: "Дополнительно",
|
||||||
"Upside Down Mode": "Режим реверса статуса",
|
"Upside Down Mode": "Реверс статуса",
|
||||||
"Max. Redirects": "Макс. количество перенаправлений",
|
"Max. Redirects": "Макс. количество перенаправлений",
|
||||||
"Accepted Status Codes": "Допустимые коды статуса",
|
"Accepted Status Codes": "Допустимые коды статуса",
|
||||||
Save: "Сохранить",
|
Save: "Сохранить",
|
||||||
|
@ -75,9 +75,9 @@ export default {
|
||||||
Bottom: "Снизу",
|
Bottom: "Снизу",
|
||||||
None: "Отсутствует",
|
None: "Отсутствует",
|
||||||
Timezone: "Часовой пояс",
|
Timezone: "Часовой пояс",
|
||||||
"Search Engine Visibility": "Видимость поисковым движком",
|
"Search Engine Visibility": "Индексация поисковыми системами:",
|
||||||
"Allow indexing": "Разрешить индексирование",
|
"Allow indexing": "Разрешить индексирование",
|
||||||
"Discourage search engines from indexing site": "Не позволять индексировать сайт",
|
"Discourage search engines from indexing site": "Запретить индексирование",
|
||||||
"Change Password": "Сменить пароль",
|
"Change Password": "Сменить пароль",
|
||||||
"Current Password": "Текущий пароль",
|
"Current Password": "Текущий пароль",
|
||||||
"New Password": "Новый пароль",
|
"New Password": "Новый пароль",
|
||||||
|
@ -96,6 +96,7 @@ export default {
|
||||||
"Remember me": "Запомнить меня",
|
"Remember me": "Запомнить меня",
|
||||||
Login: "Вход в систему",
|
Login: "Вход в систему",
|
||||||
"No Monitors, please": "Мониторов нет, пожалуйста",
|
"No Monitors, please": "Мониторов нет, пожалуйста",
|
||||||
|
"No Monitors": "Мониторы отсутствуют",
|
||||||
"add one": "создайте новый",
|
"add one": "создайте новый",
|
||||||
"Notification Type": "Тип уведомления",
|
"Notification Type": "Тип уведомления",
|
||||||
Email: "Почта",
|
Email: "Почта",
|
||||||
|
@ -107,7 +108,7 @@ export default {
|
||||||
"Create your admin account": "Создайте аккаунт администратора",
|
"Create your admin account": "Создайте аккаунт администратора",
|
||||||
"Repeat Password": "Повторите пароль",
|
"Repeat Password": "Повторите пароль",
|
||||||
respTime: "Время ответа (мс)",
|
respTime: "Время ответа (мс)",
|
||||||
notAvailableShort: "Н/Д",
|
notAvailableShort: "N/A",
|
||||||
Create: "Создать",
|
Create: "Создать",
|
||||||
clearEventsMsg: "Вы действительно хотите удалить всю статистику событий данного монитора?",
|
clearEventsMsg: "Вы действительно хотите удалить всю статистику событий данного монитора?",
|
||||||
clearHeartbeatsMsg: "Вы действительно хотите удалить всю статистику опросов данного монитора?",
|
clearHeartbeatsMsg: "Вы действительно хотите удалить всю статистику опросов данного монитора?",
|
||||||
|
@ -119,8 +120,8 @@ export default {
|
||||||
enableDefaultNotificationDescription: "Для каждого нового монитора это уведомление будет включено по умолчанию. Вы всё ещё можете отключить уведомления в каждом мониторе отдельно.",
|
enableDefaultNotificationDescription: "Для каждого нового монитора это уведомление будет включено по умолчанию. Вы всё ещё можете отключить уведомления в каждом мониторе отдельно.",
|
||||||
"Default enabled": "Использовать по умолчанию",
|
"Default enabled": "Использовать по умолчанию",
|
||||||
"Also apply to existing monitors": "Применить к существующим мониторам",
|
"Also apply to existing monitors": "Применить к существующим мониторам",
|
||||||
Export: "Резервная копия",
|
Export: "Экспорт",
|
||||||
Import: "Восстановление",
|
Import: "Импорт",
|
||||||
backupDescription: "Вы можете сохранить резервную копию всех мониторов и уведомлений в виде JSON-файла",
|
backupDescription: "Вы можете сохранить резервную копию всех мониторов и уведомлений в виде JSON-файла",
|
||||||
backupDescription2: "P.S. История и события сохранены не будут",
|
backupDescription2: "P.S. История и события сохранены не будут",
|
||||||
backupDescription3: "Важные данные, такие как токены уведомлений, добавляются при экспорте, поэтому храните файлы в безопасном месте",
|
backupDescription3: "Важные данные, такие как токены уведомлений, добавляются при экспорте, поэтому храните файлы в безопасном месте",
|
||||||
|
@ -141,13 +142,13 @@ export default {
|
||||||
Inactive: "Неактивно",
|
Inactive: "Неактивно",
|
||||||
Token: "Токен",
|
Token: "Токен",
|
||||||
"Show URI": "Показать URI",
|
"Show URI": "Показать URI",
|
||||||
"Clear all statistics": "Удалить всю статистику",
|
"Clear all statistics": "Очистить статистику",
|
||||||
retryCheckEverySecond: "Повтор каждые {0} секунд",
|
retryCheckEverySecond: "Повтор каждые {0} секунд",
|
||||||
importHandleDescription: "Выберите \"Пропустить существующие\", если вы хотите пропустить каждый монитор или уведомление с таким же именем. \"Перезаписать\" удалит каждый существующий монитор или уведомление и добавит заново. Вариант \"Не проверять\" принудительно восстанавливает все мониторы и уведомления, даже если они уже существуют.",
|
importHandleDescription: "Выберите \"Пропустить существующие\", если вы хотите пропустить каждый монитор или уведомление с таким же именем. \"Перезаписать\" удалит каждый существующий монитор или уведомление и добавит заново. Вариант \"Не проверять\" принудительно восстанавливает все мониторы и уведомления, даже если они уже существуют.",
|
||||||
confirmImportMsg: "Вы действительно хотите восстановить резервную копию? Убедитесь, что вы выбрали подходящий вариант импорта.",
|
confirmImportMsg: "Вы действительно хотите восстановить резервную копию? Убедитесь, что вы выбрали подходящий вариант импорта.",
|
||||||
"Heartbeat Retry Interval": "Интервал повтора опроса",
|
"Heartbeat Retry Interval": "Интервал повтора опроса",
|
||||||
"Import Backup": "Восстановление резервной копии",
|
"Import Backup": "Импорт",
|
||||||
"Export Backup": "Резервная копия",
|
"Export Backup": "Скачать",
|
||||||
"Skip existing": "Пропустить существующие",
|
"Skip existing": "Пропустить существующие",
|
||||||
Overwrite: "Перезаписать",
|
Overwrite: "Перезаписать",
|
||||||
Options: "Опции",
|
Options: "Опции",
|
||||||
|
@ -172,14 +173,15 @@ export default {
|
||||||
"Entry Page": "Главная страница",
|
"Entry Page": "Главная страница",
|
||||||
statusPageNothing: "Здесь пусто. Добавьте группу или монитор.",
|
statusPageNothing: "Здесь пусто. Добавьте группу или монитор.",
|
||||||
"No Services": "Нет сервисов",
|
"No Services": "Нет сервисов",
|
||||||
"All Systems Operational": "Все сервисы работают",
|
"All Systems Operational": "Все системы работают в штатном режиме",
|
||||||
"Partially Degraded Service": "Сервисы частично не работают",
|
"Partially Degraded Service": "Сервисы работают частично",
|
||||||
"Degraded Service": "Все сервисы не работают",
|
"Degraded Service": "Все сервисы не работают",
|
||||||
"Add Group": "Добавить группу",
|
"Add Group": "Добавить группу",
|
||||||
"Add a monitor": "Добавить монитор",
|
"Add a monitor": "Добавить монитор",
|
||||||
"Edit Status Page": "Редактировать",
|
"Edit Status Page": "Редактировать",
|
||||||
"Go to Dashboard": "Панель мониторов",
|
"Go to Dashboard": "Панель управления",
|
||||||
"Status Page": "Статус сервисов",
|
"Status Page": "Мониторинг",
|
||||||
|
"Status Pages": "Página de Status",
|
||||||
Discard: "Отмена",
|
Discard: "Отмена",
|
||||||
"Create Incident": "Создать инцидент",
|
"Create Incident": "Создать инцидент",
|
||||||
"Switch to Dark Theme": "Тёмная тема",
|
"Switch to Dark Theme": "Тёмная тема",
|
||||||
|
@ -302,22 +304,23 @@ export default {
|
||||||
PushUrl: "URL пуша",
|
PushUrl: "URL пуша",
|
||||||
HeadersInvalidFormat: "Заголовки запроса некорректны JSON: ",
|
HeadersInvalidFormat: "Заголовки запроса некорректны JSON: ",
|
||||||
BodyInvalidFormat: "Тело запроса некорректно JSON: ",
|
BodyInvalidFormat: "Тело запроса некорректно JSON: ",
|
||||||
"Monitor History": "История мониторов",
|
"Monitor History": "Статистика",
|
||||||
clearDataOlderThan: "Сохранять историю мониторов в течение {0} дней.",
|
clearDataOlderThan: "Сохранять статистику за {0} дней.",
|
||||||
PasswordsDoNotMatch: "Пароли не совпадают.",
|
PasswordsDoNotMatch: "Пароли не совпадают.",
|
||||||
records: "записей",
|
records: "записей",
|
||||||
"One record": "Одна запись",
|
"One record": "Одна запись",
|
||||||
steamApiKeyDescription: "Для мониторинга игрового сервера Steam вам необходим Web-API ключ Steam. Зарегистрировать его можно здесь: ",
|
steamApiKeyDescription: "Для мониторинга игрового сервера Steam вам необходим Web-API ключ Steam. Зарегистрировать его можно здесь: ",
|
||||||
"Certificate Chain:": "Цепочка сертификатов:",
|
"Certificate Chain": "Цепочка сертификатов",
|
||||||
"Valid": "Действительный",
|
"Valid": "Действительный",
|
||||||
"Hide Tags": "Скрыть тэги",
|
"Hide Tags": "Скрыть тэги",
|
||||||
"Title:": "Название инцидента:",
|
"Title": "Название инцидента:",
|
||||||
"Content:": "Содержание инцидента:",
|
"Content": "Содержание инцидента:",
|
||||||
"Post": "Опубликовать",
|
"Post": "Опубликовать",
|
||||||
"Cancel": "Отмена",
|
"Cancel": "Отмена",
|
||||||
"Created:": "Создано:",
|
"Created": "Создано",
|
||||||
|
"Unpin": "Открепить",
|
||||||
"Show Tags": "Показать тэги",
|
"Show Tags": "Показать тэги",
|
||||||
"Recent": "Текущее",
|
"recent": "Сейчас",
|
||||||
"3h": "3 часа",
|
"3h": "3 часа",
|
||||||
"6h": "6 часов",
|
"6h": "6 часов",
|
||||||
"24h": "24 часа",
|
"24h": "24 часа",
|
||||||
|
@ -326,6 +329,10 @@ export default {
|
||||||
"Add one": "Добавить новый",
|
"Add one": "Добавить новый",
|
||||||
"Backup": "Резервная копия",
|
"Backup": "Резервная копия",
|
||||||
"Security": "Безопасность",
|
"Security": "Безопасность",
|
||||||
"Current User:": "Текущий пользователь:",
|
"Shrink Database": "Сжать Базу Данных",
|
||||||
"All Systems Operational": "Все системы работают",
|
"Current User": "Текущий пользователь",
|
||||||
|
"About": "О программе",
|
||||||
|
"Description": "Описание",
|
||||||
|
"Powered by": "Работает на основе скрипта от",
|
||||||
|
shrinkDatabaseDescription: "Включает VACUUM для базы данных SQLite. Если ваша база данных была создана на версии 1.10.0 и более, AUTO_VACUUM уже включен и это действие не требуется.",
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "Pavza",
|
pauseDashboardHome: "Pavza",
|
||||||
deleteMonitorMsg: "Ste prepričani, da želite izbrisati ta monitor?",
|
deleteMonitorMsg: "Ste prepričani, da želite izbrisati ta monitor?",
|
||||||
deleteNotificationMsg: "Ste prepričani, da želite izbrisati to obvestilo za vse monitorje?",
|
deleteNotificationMsg: "Ste prepričani, da želite izbrisati to obvestilo za vse monitorje?",
|
||||||
resoverserverDescription: "Cloudflare je privzeti strežnik. DNS strežnik lahko spremenite kadarkoli.",
|
resolverserverDescription: "Cloudflare je privzeti strežnik. DNS strežnik lahko spremenite kadarkoli.",
|
||||||
rrtypeDescription: "Izberite RR tip, ki ga želite spremljati",
|
rrtypeDescription: "Izberite RR tip, ki ga želite spremljati",
|
||||||
pauseMonitorMsg: "Ste prepričani, da želite pavzirati?",
|
pauseMonitorMsg: "Ste prepričani, da želite pavzirati?",
|
||||||
enableDefaultNotificationDescription: "To obvestilo bo kot privzeto omogočeno za vse nove monitorje. Še vedno ga lahko izključite posebej za vsak monitor.",
|
enableDefaultNotificationDescription: "To obvestilo bo kot privzeto omogočeno za vse nove monitorje. Še vedno ga lahko izključite posebej za vsak monitor.",
|
||||||
|
@ -182,7 +182,8 @@ export default {
|
||||||
"Add a monitor": "Dodaj monitor",
|
"Add a monitor": "Dodaj monitor",
|
||||||
"Edit Status Page": "Uredi statusno stran",
|
"Edit Status Page": "Uredi statusno stran",
|
||||||
"Go to Dashboard": "Pojdi na nadzorno ploščo",
|
"Go to Dashboard": "Pojdi na nadzorno ploščo",
|
||||||
"Status Page": "Status",
|
"Status Page": "Página de Status",
|
||||||
|
"Status Pages": "Página de Status",
|
||||||
defaultNotificationName: "Moje {notification} Obvestilo ({number})",
|
defaultNotificationName: "Moje {notification} Obvestilo ({number})",
|
||||||
here: "tukaj",
|
here: "tukaj",
|
||||||
Required: "Obvezno",
|
Required: "Obvezno",
|
||||||
|
@ -339,7 +340,6 @@ export default {
|
||||||
"No monitors available.": "Nobenega monitorja ni na voljo.",
|
"No monitors available.": "Nobenega monitorja ni na voljo.",
|
||||||
"Add one": "Dodaj enega",
|
"Add one": "Dodaj enega",
|
||||||
"No Monitors": "Ni monitorjev",
|
"No Monitors": "Ni monitorjev",
|
||||||
"Add one": "Dodaj enega",
|
|
||||||
"Untitled Group": "Skupina brez imena",
|
"Untitled Group": "Skupina brez imena",
|
||||||
Services: "Storitve",
|
Services: "Storitve",
|
||||||
Discard: "zavrzi",
|
Discard: "zavrzi",
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
pauseDashboardHome: "Pauziraj",
|
pauseDashboardHome: "Pauziraj",
|
||||||
deleteMonitorMsg: "Da li ste sigurni da želite da obrišete ovog posmatrača?",
|
deleteMonitorMsg: "Da li ste sigurni da želite da obrišete ovog posmatrača?",
|
||||||
deleteNotificationMsg: "Da li ste sigurni d aželite da uklonite ovo obaveštenje za sve posmatrače?",
|
deleteNotificationMsg: "Da li ste sigurni d aželite da uklonite ovo obaveštenje za sve posmatrače?",
|
||||||
resoverserverDescription: "Cloudflare je podrazumevani server. Možete promeniti server za raszrešavanje u bilo kom trenutku.",
|
resolverserverDescription: "Cloudflare je podrazumevani server. Možete promeniti server za raszrešavanje u bilo kom trenutku.",
|
||||||
rrtypeDescription: "Odaberite RR-Type koji želite da posmatrate",
|
rrtypeDescription: "Odaberite RR-Type koji želite da posmatrate",
|
||||||
pauseMonitorMsg: "Da li ste sigurni da želite da pauzirate?",
|
pauseMonitorMsg: "Da li ste sigurni da želite da pauzirate?",
|
||||||
Settings: "Podešavanja",
|
Settings: "Podešavanja",
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
"Edit Status Page": "Edit Status Page",
|
"Edit Status Page": "Edit Status Page",
|
||||||
"Go to Dashboard": "Go to Dashboard",
|
"Go to Dashboard": "Go to Dashboard",
|
||||||
"Status Page": "Status Page",
|
"Status Page": "Status Page",
|
||||||
|
"Status Pages": "Status Pages",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
pauseDashboardHome: "Паузирај",
|
pauseDashboardHome: "Паузирај",
|
||||||
deleteMonitorMsg: "Да ли сте сигурни да желите да обришете овог посматрача?",
|
deleteMonitorMsg: "Да ли сте сигурни да желите да обришете овог посматрача?",
|
||||||
deleteNotificationMsg: "Да ли сте сигурни д ажелите да уклоните ово обавештење за све посматраче?",
|
deleteNotificationMsg: "Да ли сте сигурни д ажелите да уклоните ово обавештење за све посматраче?",
|
||||||
resoverserverDescription: "Cloudflare је подразумевани сервер. Можете променити сервер за расзрешавање у било ком тренутку.",
|
resolverserverDescription: "Cloudflare је подразумевани сервер. Можете променити сервер за расзрешавање у било ком тренутку.",
|
||||||
rrtypeDescription: "Одаберите RR-Type који желите да посматрате",
|
rrtypeDescription: "Одаберите RR-Type који желите да посматрате",
|
||||||
pauseMonitorMsg: "Да ли сте сигурни да желите да паузирате?",
|
pauseMonitorMsg: "Да ли сте сигурни да желите да паузирате?",
|
||||||
Settings: "Подешавања",
|
Settings: "Подешавања",
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
"Edit Status Page": "Edit Status Page",
|
"Edit Status Page": "Edit Status Page",
|
||||||
"Go to Dashboard": "Go to Dashboard",
|
"Go to Dashboard": "Go to Dashboard",
|
||||||
"Status Page": "Status Page",
|
"Status Page": "Status Page",
|
||||||
|
"Status Pages": "Status Pages",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
pauseDashboardHome: "Pausa",
|
pauseDashboardHome: "Pausa",
|
||||||
deleteMonitorMsg: "Är du säker på att du vill ta bort den här övervakningen?",
|
deleteMonitorMsg: "Är du säker på att du vill ta bort den här övervakningen?",
|
||||||
deleteNotificationMsg: "Är du säker på att du vill ta bort den här notisen för alla övervakare?",
|
deleteNotificationMsg: "Är du säker på att du vill ta bort den här notisen för alla övervakare?",
|
||||||
resoverserverDescription: "Cloudflare är den förvalda servern. Du kan byta resolver när som helst.",
|
resolverserverDescription: "Cloudflare är den förvalda servern. Du kan byta resolver när som helst.",
|
||||||
rrtypeDescription: "Välj den RR-typ du vill övervaka",
|
rrtypeDescription: "Välj den RR-typ du vill övervaka",
|
||||||
pauseMonitorMsg: "Är du säker på att du vill pausa?",
|
pauseMonitorMsg: "Är du säker på att du vill pausa?",
|
||||||
Settings: "Inställningar",
|
Settings: "Inställningar",
|
||||||
|
@ -108,94 +108,4 @@ export default {
|
||||||
"Repeat Password": "Upprepa Lösenord",
|
"Repeat Password": "Upprepa Lösenord",
|
||||||
respTime: "Svarstid (ms)",
|
respTime: "Svarstid (ms)",
|
||||||
notAvailableShort: "Ej Tillg.",
|
notAvailableShort: "Ej Tillg.",
|
||||||
Create: "Create",
|
|
||||||
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
|
||||||
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
|
||||||
"Clear Data": "Clear Data",
|
|
||||||
Events: "Events",
|
|
||||||
Heartbeats: "Heartbeats",
|
|
||||||
"Auto Get": "Auto Get",
|
|
||||||
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
|
||||||
"Default enabled": "Default enabled",
|
|
||||||
"Also apply to existing monitors": "Also apply to existing monitors",
|
|
||||||
Export: "Export",
|
|
||||||
Import: "Import",
|
|
||||||
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
|
||||||
backupDescription2: "PS: History and event data is not included.",
|
|
||||||
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
|
||||||
alertNoFile: "Please select a file to import.",
|
|
||||||
alertWrongFileType: "Please select a JSON file.",
|
|
||||||
twoFAVerifyLabel: "Please type in your token to verify that 2FA is working",
|
|
||||||
tokenValidSettingsMsg: "Token is valid! You can now save the 2FA settings.",
|
|
||||||
confirmEnableTwoFAMsg: "Are you sure you want to enable 2FA?",
|
|
||||||
confirmDisableTwoFAMsg: "Are you sure you want to disable 2FA?",
|
|
||||||
"Apply on all existing monitors": "Apply on all existing monitors",
|
|
||||||
"Verify Token": "Verify Token",
|
|
||||||
"Setup 2FA": "Setup 2FA",
|
|
||||||
"Enable 2FA": "Enable 2FA",
|
|
||||||
"Disable 2FA": "Disable 2FA",
|
|
||||||
"2FA Settings": "2FA Settings",
|
|
||||||
"Two Factor Authentication": "Two Factor Authentication",
|
|
||||||
Active: "Active",
|
|
||||||
Inactive: "Inactive",
|
|
||||||
Token: "Token",
|
|
||||||
"Show URI": "Show URI",
|
|
||||||
"Clear all statistics": "Clear all Statistics",
|
|
||||||
retryCheckEverySecond: "Retry every {0} seconds.",
|
|
||||||
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
|
|
||||||
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
|
|
||||||
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
|
|
||||||
"Import Backup": "Import Backup",
|
|
||||||
"Export Backup": "Export Backup",
|
|
||||||
"Skip existing": "Skip existing",
|
|
||||||
Overwrite: "Overwrite",
|
|
||||||
Options: "Options",
|
|
||||||
"Keep both": "Keep both",
|
|
||||||
Tags: "Tags",
|
|
||||||
"Add New below or Select...": "Add New below or Select...",
|
|
||||||
"Tag with this name already exist.": "Tag with this name already exist.",
|
|
||||||
"Tag with this value already exist.": "Tag with this value already exist.",
|
|
||||||
color: "color",
|
|
||||||
"value (optional)": "value (optional)",
|
|
||||||
Gray: "Gray",
|
|
||||||
Red: "Red",
|
|
||||||
Orange: "Orange",
|
|
||||||
Green: "Green",
|
|
||||||
Blue: "Blue",
|
|
||||||
Indigo: "Indigo",
|
|
||||||
Purple: "Purple",
|
|
||||||
Pink: "Pink",
|
|
||||||
"Search...": "Search...",
|
|
||||||
"Avg. Ping": "Avg. Ping",
|
|
||||||
"Avg. Response": "Avg. Response",
|
|
||||||
"Entry Page": "Entry Page",
|
|
||||||
statusPageNothing: "Nothing here, please add a group or a monitor.",
|
|
||||||
"No Services": "No Services",
|
|
||||||
"All Systems Operational": "All Systems Operational",
|
|
||||||
"Partially Degraded Service": "Partially Degraded Service",
|
|
||||||
"Degraded Service": "Degraded Service",
|
|
||||||
"Add Group": "Add Group",
|
|
||||||
"Add a monitor": "Add a monitor",
|
|
||||||
"Edit Status Page": "Edit Status Page",
|
|
||||||
"Go to Dashboard": "Go to Dashboard",
|
|
||||||
"Status Page": "Status Page",
|
|
||||||
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",
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
||||||
pauseDashboardHome: "Durdur",
|
pauseDashboardHome: "Durdur",
|
||||||
deleteMonitorMsg: "Servisi silmek istediğinden emin misin?",
|
deleteMonitorMsg: "Servisi silmek istediğinden emin misin?",
|
||||||
deleteNotificationMsg: "Bu bildirimi tüm servisler için silmek istediğinden emin misin?",
|
deleteNotificationMsg: "Bu bildirimi tüm servisler için silmek istediğinden emin misin?",
|
||||||
resoverserverDescription: "Cloudflare varsayılan sunucudur, çözümleyici sunucusunu istediğiniz zaman değiştirebilirsiniz.",
|
resolverserverDescription: "Cloudflare varsayılan sunucudur, çözümleyici sunucusunu istediğiniz zaman değiştirebilirsiniz.",
|
||||||
rrtypeDescription: "İzlemek istediğiniz servisin RR-Tipini seçin",
|
rrtypeDescription: "İzlemek istediğiniz servisin RR-Tipini seçin",
|
||||||
pauseMonitorMsg: "Durdurmak istediğinden emin misin?",
|
pauseMonitorMsg: "Durdurmak istediğinden emin misin?",
|
||||||
clearEventsMsg: "Bu servisin bütün kayıtlarını silmek istediğinden emin misin?",
|
clearEventsMsg: "Bu servisin bütün kayıtlarını silmek istediğinden emin misin?",
|
||||||
|
@ -124,7 +124,7 @@ export default {
|
||||||
tokenValidSettingsMsg: "Token geçerli! Şimdi 2FA ayarlarını kaydedebilirsiniz. ",
|
tokenValidSettingsMsg: "Token geçerli! Şimdi 2FA ayarlarını kaydedebilirsiniz. ",
|
||||||
confirmEnableTwoFAMsg: "2FA'ı etkinleştirmek istediğinizden emin misiniz?",
|
confirmEnableTwoFAMsg: "2FA'ı etkinleştirmek istediğinizden emin misiniz?",
|
||||||
confirmDisableTwoFAMsg: "2FA'ı devre dışı bırakmak istediğinize emin misiniz?",
|
confirmDisableTwoFAMsg: "2FA'ı devre dışı bırakmak istediğinize emin misiniz?",
|
||||||
"Heartbeat Retry Interval": "Sağlık Dırımları Tekrar Deneme Sıklığı",
|
"Heartbeat Retry Interval": "Sağlık Durumları Tekrar Deneme Sıklığı",
|
||||||
"Import Backup": "Yedeği içe aktar",
|
"Import Backup": "Yedeği içe aktar",
|
||||||
"Export Backup": "Yedeği dışa aktar",
|
"Export Backup": "Yedeği dışa aktar",
|
||||||
Export: "Dışa aktar",
|
Export: "Dışa aktar",
|
||||||
|
@ -149,52 +149,4 @@ export default {
|
||||||
"Two Factor Authentication": "İki Faktörlü Kimlik Doğrulama (2FA)",
|
"Two Factor Authentication": "İki Faktörlü Kimlik Doğrulama (2FA)",
|
||||||
Active: "Aktif",
|
Active: "Aktif",
|
||||||
Inactive: "İnaktif",
|
Inactive: "İnaktif",
|
||||||
Token: "Token",
|
|
||||||
"Show URI": "Show URI",
|
|
||||||
Tags: "Tags",
|
|
||||||
"Add New below or Select...": "Add New below or Select...",
|
|
||||||
"Tag with this name already exist.": "Tag with this name already exist.",
|
|
||||||
"Tag with this value already exist.": "Tag with this value already exist.",
|
|
||||||
color: "color",
|
|
||||||
"value (optional)": "value (optional)",
|
|
||||||
Gray: "Gray",
|
|
||||||
Red: "Red",
|
|
||||||
Orange: "Orange",
|
|
||||||
Green: "Green",
|
|
||||||
Blue: "Blue",
|
|
||||||
Indigo: "Indigo",
|
|
||||||
Purple: "Purple",
|
|
||||||
Pink: "Pink",
|
|
||||||
"Search...": "Search...",
|
|
||||||
"Avg. Ping": "Avg. Ping",
|
|
||||||
"Avg. Response": "Avg. Response",
|
|
||||||
"Entry Page": "Entry Page",
|
|
||||||
statusPageNothing: "Nothing here, please add a group or a monitor.",
|
|
||||||
"No Services": "No Services",
|
|
||||||
"All Systems Operational": "All Systems Operational",
|
|
||||||
"Partially Degraded Service": "Partially Degraded Service",
|
|
||||||
"Degraded Service": "Degraded Service",
|
|
||||||
"Add Group": "Add Group",
|
|
||||||
"Add a monitor": "Add a monitor",
|
|
||||||
"Edit Status Page": "Edit Status Page",
|
|
||||||
"Go to Dashboard": "Go to Dashboard",
|
|
||||||
"Status Page": "Status Page",
|
|
||||||
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",
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
export default {
|
export default {
|
||||||
languageName: "Vietnamese",
|
languageName: "Tiếng Việt",
|
||||||
checkEverySecond: "Kiểm tra mỗi {0} giây.",
|
checkEverySecond: "Kiểm tra mỗi {0} giây.",
|
||||||
retryCheckEverySecond: "Thử lại mỗi {0} giây.",
|
retryCheckEverySecond: "Thử lại mỗi {0} giây.",
|
||||||
retriesDescription: "Số lần thử lại tối đa trước khi dịch vụ được đánh dấu là down và gửi thông báo.",
|
retriesDescription: "Số lần thử lại tối đa trước khi dịch vụ được đánh dấu là down và gửi thông báo.",
|
||||||
ignoreTLSError: "Bỏ qua lỗi TLS/SSL với các web HTTPS.",
|
ignoreTLSError: "Bỏ qua lỗi TLS/SSL với các web HTTPS.",
|
||||||
upsideDownModeDescription: "Trạng thái đảo ngược, nếu dịch vụ có thể truy cập được nghĩa là DOWN.",
|
upsideDownModeDescription: "Trạng thái đảo ngược, nếu dịch vụ có thể truy cập được nghĩa là DOWN.",
|
||||||
maxRedirectDescription: "Số lần chuyển hướng (redirect) tối đa. Đặt thành 0 để tắt chuyển hướng",
|
maxRedirectDescription: "Số lần chuyển hướng (redirect) tối đa. Đặt thành 0 để tắt chuyển hướng",
|
||||||
acceptedStatusCodesDescription: "Chọn mã code trạng thái được coi là phản hồi thành công.",
|
acceptedStatusCodesDescription: "Chọn mã trạng thái được coi là phản hồi thành công.",
|
||||||
passwordNotMatchMsg: "Mật khẩu nhập lại không khớp.",
|
passwordNotMatchMsg: "Mật khẩu nhập lại không khớp.",
|
||||||
notificationDescription: "Vui lòng chỉ định một kênh thông báo.",
|
notificationDescription: "Vui lòng chỉ định một kênh thông báo.",
|
||||||
keywordDescription: "Từ khoá tìm kiếm phản hồi ở dạng html hoặc JSON, có phân biệt chữ HOA - thường",
|
keywordDescription: "Từ khoá tìm kiếm phản hồi ở dạng html hoặc JSON, có phân biệt chữ HOA - thường",
|
||||||
pauseDashboardHome: "Tạm dừng",
|
pauseDashboardHome: "Tạm dừng",
|
||||||
deleteMonitorMsg: "Bạn chắc chắn muốn xóa monitor này chứ?",
|
deleteMonitorMsg: "Bạn chắc chắn muốn xóa kênh theo dõi này chứ?",
|
||||||
deleteNotificationMsg: "Bạn có chắc chắn muốn xóa kênh thông báo này cho tất cả monitor?",
|
deleteNotificationMsg: "Bạn có chắc chắn muốn xóa kênh thông báo này cho tất cả kênh theo dõi?",
|
||||||
resoverserverDescription: "Cloudflare là máy chủ mặc định, bạn có thể thay đổi bất cứ lúc nào.",
|
resolverserverDescription: "Cloudflare là máy chủ mặc định, bạn có thể thay đổi bất cứ lúc nào.",
|
||||||
rrtypeDescription: "Hãy chọn RR-Type mà bạn muốn giám sát",
|
rrtypeDescription: "Hãy chọn RR-Type mà bạn muốn giám sát",
|
||||||
pauseMonitorMsg: "Bạn chắc chắn muốn tạm dừng chứ?",
|
pauseMonitorMsg: "Bạn chắc chắn muốn tạm dừng chứ?",
|
||||||
enableDefaultNotificationDescription: "Bật làm mặc định cho mọi monitor mới về sau. Bạn vẫn có thể tắt thông báo riêng cho từng monitor.",
|
enableDefaultNotificationDescription: "Bật làm mặc định cho mọi kênh theo dõi mới về sau. Bạn vẫn có thể tắt thông báo riêng cho từng kênh theo dõi.",
|
||||||
clearEventsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ sự kiện cho monitor này chứ?",
|
clearEventsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ sự kiện cho kênh theo dõi này chứ?",
|
||||||
clearHeartbeatsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ heartbeats cho monitor này chứ?",
|
clearHeartbeatsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ heartbeats cho kênh theo dõi này chứ?",
|
||||||
confirmClearStatisticsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ số liệu thống kê?",
|
confirmClearStatisticsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ số liệu thống kê?",
|
||||||
importHandleDescription: "Chọn 'Skip existing' nếu bạn muốn bỏ qua mọi monitor và kênh thông báo trùng tên. 'Overwrite' sẽ ghi đè lên tất cả các monitor và kênh thông báo.",
|
importHandleDescription: "Chọn 'Giữ lại' nếu bạn muốn bỏ qua mọi kênh theo dõi và kênh thông báo trùng tên. 'Ghi đè' sẽ ghi đè lên tất cả các kênh theo dõi và kênh thông báo.",
|
||||||
confirmImportMsg: "Bạn có chắc chắn muốn khôi phục bản bản sao lưu này không?.",
|
confirmImportMsg: "Bạn có chắc chắn muốn khôi phục bản bản sao lưu này không?.",
|
||||||
twoFAVerifyLabel: "Vui lòng nhập mã token của bạn để xác minh rằng 2FA đang hoạt động",
|
twoFAVerifyLabel: "Vui lòng nhập mã token của bạn để xác minh rằng xác thực 2 lớp (2FA) đang hoạt động",
|
||||||
tokenValidSettingsMsg: "Mã token hợp lệ! Bạn có thể lưu cài đặt 2FA bây giờ.",
|
tokenValidSettingsMsg: "Mã token hợp lệ! Bạn có thể lưu cài đặt xác thực 2 lớp (2FA) bây giờ.",
|
||||||
confirmEnableTwoFAMsg: "Bạn chắc chắn muốn bật 2FA chứ?",
|
confirmEnableTwoFAMsg: "Bạn chắc chắn muốn bật xác thực 2 lớp (2FA) chứ?",
|
||||||
confirmDisableTwoFAMsg: "Bạn chắc chắn muốn tắt 2FA chứ?",
|
confirmDisableTwoFAMsg: "Bạn chắc chắn muốn tắt xác thực 2 lớp (2FA) chứ?",
|
||||||
Settings: "Cài đặt",
|
Settings: "Cài đặt",
|
||||||
Dashboard: "Dashboard",
|
Dashboard: "Dashboard",
|
||||||
"New Update": "Bản cập nhật mới",
|
"New Update": "Bản cập nhật mới",
|
||||||
|
@ -38,7 +38,7 @@ export default {
|
||||||
"Check Update On GitHub": "Kiểm tra bản cập nhật mới trên GitHub",
|
"Check Update On GitHub": "Kiểm tra bản cập nhật mới trên GitHub",
|
||||||
List: "List",
|
List: "List",
|
||||||
Add: "Thêm",
|
Add: "Thêm",
|
||||||
"Add New Monitor": "Thêm mới Monitor",
|
"Add New Monitor": "Thêm mới kênh theo dõi",
|
||||||
"Quick Stats": "Thống kê nhanh",
|
"Quick Stats": "Thống kê nhanh",
|
||||||
Up: "Up",
|
Up: "Up",
|
||||||
Down: "Down",
|
Down: "Down",
|
||||||
|
@ -63,9 +63,9 @@ export default {
|
||||||
"-hour": "-giờ",
|
"-hour": "-giờ",
|
||||||
Response: "Phản hồi",
|
Response: "Phản hồi",
|
||||||
Ping: "Ping",
|
Ping: "Ping",
|
||||||
"Monitor Type": "Kiểu monitor",
|
"Monitor Type": "Kiểu kênh theo dõi",
|
||||||
Keyword: "Từ khoá",
|
Keyword: "Từ khoá",
|
||||||
"Friendly Name": "Tên monitor",
|
"Friendly Name": "Tên rút gọn",
|
||||||
URL: "URL",
|
URL: "URL",
|
||||||
Hostname: "Hostname",
|
Hostname: "Hostname",
|
||||||
Port: "Port",
|
Port: "Port",
|
||||||
|
@ -111,7 +111,7 @@ export default {
|
||||||
Password: "Mật khẩu",
|
Password: "Mật khẩu",
|
||||||
"Remember me": "Lưu phiên đăng nhập",
|
"Remember me": "Lưu phiên đăng nhập",
|
||||||
Login: "Đăng nhập",
|
Login: "Đăng nhập",
|
||||||
"No Monitors, please": "Không có monitor nào",
|
"No Monitors, please": "Không có kênh theo dõi nào",
|
||||||
"add one": "Thêm mới",
|
"add one": "Thêm mới",
|
||||||
"Notification Type": "Kiểu thông báo",
|
"Notification Type": "Kiểu thông báo",
|
||||||
Email: "Email",
|
Email: "Email",
|
||||||
|
@ -125,31 +125,31 @@ export default {
|
||||||
"Import Backup": "Khôi phục bản sao lưu",
|
"Import Backup": "Khôi phục bản sao lưu",
|
||||||
"Export Backup": "Xuất bản sao lưu",
|
"Export Backup": "Xuất bản sao lưu",
|
||||||
Export: "Xuất",
|
Export: "Xuất",
|
||||||
Import: "Khôi phục",
|
Import: "Nhập",
|
||||||
respTime: "Thời gian phản hồi (ms)",
|
respTime: "Thời gian phản hồi (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
"Default enabled": "Mặc định bật",
|
"Default enabled": "Mặc định bật",
|
||||||
"Apply on all existing monitors": "Áp dụng cho tất cả monitor đang có",
|
"Apply on all existing monitors": "Áp dụng cho tất cả kênh theo dõi đang có",
|
||||||
Create: "Tạo",
|
Create: "Tạo",
|
||||||
"Clear Data": "Xoá dữ liệu",
|
"Clear Data": "Xoá dữ liệu",
|
||||||
Events: "Sự kiện",
|
Events: "Sự kiện",
|
||||||
Heartbeats: "Heartbeats",
|
Heartbeats: "Heartbeats",
|
||||||
"Auto Get": "Tự động lấy",
|
"Auto Get": "Tự động lấy",
|
||||||
backupDescription: "Bạn có thể sao lưu tất cả các monitor và tất cả các thông báo vào một file JSON.",
|
backupDescription: "Sao lưu tất cả các kênh theo dõi và tất cả các thông báo vào một file định dạng JSON.",
|
||||||
backupDescription2: "PS: Không bao gồm dữ liệu lịch sử các sự kiện.",
|
backupDescription2: "Lưu ý: Không bao gồm dữ liệu lịch sử các sự kiện.",
|
||||||
backupDescription3: "Hãy lưu giữ file này cẩn thận vì trong file đó chứa cả các mã token thông báo.",
|
backupDescription3: "Hãy lưu giữ file này cẩn thận, trong file đó chứa cả các token thông báo.",
|
||||||
alertNoFile: "Hãy chọn file để khôi phục.",
|
alertNoFile: "Hãy chọn file để khôi phục.",
|
||||||
alertWrongFileType: "Hãy chọn file JSON.",
|
alertWrongFileType: "Hãy chọn file định dạng JSON.",
|
||||||
"Clear all statistics": "Xoá tất cả thống kê",
|
"Clear all statistics": "Xoá tất cả thống kê",
|
||||||
"Skip existing": "Skip existing",
|
"Skip existing": "Giữ lại",
|
||||||
Overwrite: "Ghi đè",
|
Overwrite: "Ghi đè",
|
||||||
Options: "Tuỳ chọn",
|
Options: "Tuỳ chọn",
|
||||||
"Keep both": "Giữ lại cả hai",
|
"Keep both": "Giữ lại cả hai",
|
||||||
"Verify Token": "Xác minh Token",
|
"Verify Token": "Xác minh Token",
|
||||||
"Setup 2FA": "Cài đặt 2FA",
|
"Setup 2FA": "Cài đặt xác thực 2 lớp (2FA)",
|
||||||
"Enable 2FA": "Bật 2FA",
|
"Enable 2FA": "Bật xác thực 2 lớp (2FA)",
|
||||||
"Disable 2FA": "Tắt 2FA",
|
"Disable 2FA": "Tắt xác thực 2 lớp (2FA)",
|
||||||
"2FA Settings": "Cài đặt 2FA",
|
"2FA Settings": "Cài đặt xác thực 2 lớp (2FA)",
|
||||||
"Two Factor Authentication": "Xác thực hai yếu tố",
|
"Two Factor Authentication": "Xác thực hai yếu tố",
|
||||||
Active: "Hoạt động",
|
Active: "Hoạt động",
|
||||||
Inactive: "Ngừng hoạt động",
|
Inactive: "Ngừng hoạt động",
|
||||||
|
@ -170,19 +170,20 @@ export default {
|
||||||
Purple: "Tím",
|
Purple: "Tím",
|
||||||
Pink: "Hồng",
|
Pink: "Hồng",
|
||||||
"Search...": "Tìm kiếm...",
|
"Search...": "Tìm kiếm...",
|
||||||
"Avg. Ping": "Ping Trung bình",
|
"Avg. Ping": "Ping trung bình",
|
||||||
"Avg. Response": "Phản hồi trung bình",
|
"Avg. Response": "Phản hồi trung bình",
|
||||||
"Entry Page": "Entry Page",
|
"Entry Page": "Entry Page",
|
||||||
statusPageNothing: "Không có gì, hãy thêm nhóm monitor hoặc monitor.",
|
statusPageNothing: "Chưa có thông tin gì, hãy thêm nhóm kênh theo dõi hoặc kênh theo dõi.",
|
||||||
"No Services": "Không có dịch vụ",
|
"No Services": "Không có dịch vụ",
|
||||||
"All Systems Operational": "Tất cả các hệ thống hoạt động bình thường",
|
"All Systems Operational": "Tất cả các hệ thống hoạt động bình thường",
|
||||||
"Partially Degraded Service": "Có hệ thống down",
|
"Partially Degraded Service": "Có hệ thống bị ngưng",
|
||||||
"Degraded Service": "Toàn bộ hệ thống down",
|
"Degraded Service": "Toàn bộ hệ thống bị ngưng",
|
||||||
"Add Group": "Thêm nhóm",
|
"Add Group": "Thêm nhóm",
|
||||||
"Add a monitor": "Thêm monitor",
|
"Add a monitor": "Thêm kênh theo dõi",
|
||||||
"Edit Status Page": "Sửa trang trạng thái",
|
"Edit Status Page": "Sửa trang trạng thái",
|
||||||
"Go to Dashboard": "Đi tới Dashboard",
|
"Go to Dashboard": "Đi tới Dashboard",
|
||||||
"Status Page": "Trang trạng thái",
|
"Status Page": "Trang trạng thái",
|
||||||
|
"Status Pages": "Trang trạng thái",
|
||||||
defaultNotificationName: "My {notification} Alerts ({number})",
|
defaultNotificationName: "My {notification} Alerts ({number})",
|
||||||
here: "tại đây",
|
here: "tại đây",
|
||||||
Required: "Bắt buộc",
|
Required: "Bắt buộc",
|
||||||
|
@ -195,23 +196,23 @@ export default {
|
||||||
"YOUR BOT TOKEN HERE": "MÃ BOT TOKEN CỦA BẠN",
|
"YOUR BOT TOKEN HERE": "MÃ BOT TOKEN CỦA BẠN",
|
||||||
chatIDNotFound: "Không tìm thấy Chat ID, vui lòng gửi tin nhắn cho bot này trước",
|
chatIDNotFound: "Không tìm thấy Chat ID, vui lòng gửi tin nhắn cho bot này trước",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
"Post URL": "URL đăng",
|
"Post URL": "URL webhook",
|
||||||
"Content Type": "Loại nội dung",
|
"Content Type": "Loại nội dung",
|
||||||
webhookJsonDesc: "{0} phù hợp với bất kỳ máy chủ http hiện đại nào như express.js",
|
webhookJsonDesc: "{0} tương thích với máy chủ HTTP ví dụ như Express.js",
|
||||||
webhookFormDataDesc: "{multipart} phù hợp với PHP, bạn chỉ cần phân tích cú pháp json bằng {decodeFunction}",
|
webhookFormDataDesc: "{multipart} tương thích với máy chủ PHP, bạn chỉ cần phân tích cú pháp json bằng {decodeFunction}",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
secureOptionNone: "None / STARTTLS (25, 587)",
|
secureOptionNone: "None/STARTTLS(25, 587)",
|
||||||
secureOptionTLS: "TLS (465)",
|
secureOptionTLS: "TLS (465)",
|
||||||
"Ignore TLS Error": "Bỏ qua lỗi TLS",
|
"Ignore TLS Error": "Bỏ qua lỗi TLS",
|
||||||
"From Email": "Từ Email",
|
"From Email": "Email gửi",
|
||||||
emailCustomSubject: "Tuỳ chỉnh tiêu đề",
|
emailCustomSubject: "Tuỳ chỉnh tiêu đề",
|
||||||
"To Email": "Tới Email",
|
"To Email": "Email nhận",
|
||||||
smtpCC: "CC",
|
smtpCC: "CC",
|
||||||
smtpBCC: "BCC",
|
smtpBCC: "BCC",
|
||||||
discord: "Discord",
|
discord: "Discord",
|
||||||
"Discord Webhook URL": "Discord Webhook URL",
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
wayToGetDiscordURL: "Để lấy Discord, hãy vào: Server Settings -> Integrations -> Create Webhook",
|
wayToGetDiscordURL: "Để lấy Discord, hãy vào: Server Settings -> Integrations -> Create Webhook",
|
||||||
"Bot Display Name": "Tên hiển thị của Bot",
|
"Bot Display Name": "Tên hiển thị của BOT",
|
||||||
"Prefix Custom Message": "Tiền tố tin nhắn tuỳ chọn",
|
"Prefix Custom Message": "Tiền tố tin nhắn tuỳ chọn",
|
||||||
"Hello @everyone is...": "Xin chào {'@'} mọi người đang...",
|
"Hello @everyone is...": "Xin chào {'@'} mọi người đang...",
|
||||||
teams: "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
|
@ -220,8 +221,8 @@ export default {
|
||||||
signal: "Tín hiệu",
|
signal: "Tín hiệu",
|
||||||
Number: "Số",
|
Number: "Số",
|
||||||
Recipients: "Người nhận",
|
Recipients: "Người nhận",
|
||||||
needSignalAPI: "Bạn cần một tín hiệu client với REST API.",
|
needSignalAPI: "Bạn cần một tín hiệu kết nối với REST API.",
|
||||||
wayToCheckSignalURL: "Bạn có thể kiểm tra url này để xem cách thiết lập:",
|
wayToCheckSignalURL: "Bạn có thể kiểm tra URL này để xem cách thiết lập:",
|
||||||
signalImportant: "QUAN TRỌNG: Bạn không thể kết hợp các nhóm và số trong người nhận!",
|
signalImportant: "QUAN TRỌNG: Bạn không thể kết hợp các nhóm và số trong người nhận!",
|
||||||
gotify: "Gotify",
|
gotify: "Gotify",
|
||||||
"Application Token": "Mã Token ứng dụng",
|
"Application Token": "Mã Token ứng dụng",
|
||||||
|
@ -242,7 +243,7 @@ export default {
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
clicksendsms: "ClickSend SMS",
|
clicksendsms: "ClickSend SMS",
|
||||||
lunasea: "LunaSea",
|
lunasea: "LunaSea",
|
||||||
apprise: "Apprise (Hỗ trợ 50+ dịch vụ thông báo)",
|
apprise: "Apprise (Hỗ trợ trên 50 dịch vụ thông báo)",
|
||||||
GoogleChat: "Google Chat (Google Workspace only)",
|
GoogleChat: "Google Chat (Google Workspace only)",
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
|
@ -261,7 +262,7 @@ export default {
|
||||||
apiCredentials: "API credentials",
|
apiCredentials: "API credentials",
|
||||||
octopushLegacyHint: "Bạn muốn sử dụng phiên bản cũ của Octopush (2011-2020) hay phiên bản mới?",
|
octopushLegacyHint: "Bạn muốn sử dụng phiên bản cũ của Octopush (2011-2020) hay phiên bản mới?",
|
||||||
"Check octopush prices": "Kiểm tra giá octopush {0}.",
|
"Check octopush prices": "Kiểm tra giá octopush {0}.",
|
||||||
octopushPhoneNumber: "Số điện thoại (Định dạng intl, vd : +84123456789) ",
|
octopushPhoneNumber: "Số điện thoại (Định dạng intl, vd : +84692341165) ",
|
||||||
octopushSMSSender: "SMS người gửi : 3-11 ký tự chữ, số và dấu cách (a-zA-Z0-9)",
|
octopushSMSSender: "SMS người gửi : 3-11 ký tự chữ, số và dấu cách (a-zA-Z0-9)",
|
||||||
"LunaSea Device ID": "LunaSea ID thiết bị",
|
"LunaSea Device ID": "LunaSea ID thiết bị",
|
||||||
"Apprise URL": "Apprise URL",
|
"Apprise URL": "Apprise URL",
|
||||||
|
@ -300,50 +301,50 @@ export default {
|
||||||
PushUrl: "Push URL",
|
PushUrl: "Push URL",
|
||||||
HeadersInvalidFormat: "Header request không hợp lệ JSON: ",
|
HeadersInvalidFormat: "Header request không hợp lệ JSON: ",
|
||||||
BodyInvalidFormat: "Tequest body không hợp lệ JSON: ",
|
BodyInvalidFormat: "Tequest body không hợp lệ JSON: ",
|
||||||
"Monitor History": "Lịch sử Monitor",
|
"Monitor History": "Lịch sử kênh theo dõi",
|
||||||
clearDataOlderThan: "Giữ dữ liệu lịch sử monitor {0} ngày.",
|
clearDataOlderThan: "Giữ dữ liệu lịch sử kênh theo dõi {0} ngày.",
|
||||||
PasswordsDoNotMatch: "Passwords không khớp.",
|
PasswordsDoNotMatch: "Passwords không khớp.",
|
||||||
records: "records",
|
records: "records",
|
||||||
"One record": "One record",
|
"One record": "One record",
|
||||||
steamApiKeyDescription: "Để monitor các Steam Game Server bạn cần một Steam Web-API key. Bạn có thể đăng ký API key tại đây: ",
|
steamApiKeyDescription: "Để theo dõi các Steam Game Server bạn cần một Steam Web-API key. Bạn có thể đăng ký API key tại đây: ",
|
||||||
"Current User": "User hiện tại",
|
"Current User": "User hiện tại",
|
||||||
recent: "Gần đây",
|
recent: "Gần đây",
|
||||||
Done: "Done",
|
Done: "Hoàn thành",
|
||||||
Info: "Info",
|
Info: "Thông tin",
|
||||||
Security: "Security",
|
Security: "Bảo mật",
|
||||||
"Steam API Key": "Steam API Key",
|
"Steam API Key": "Steam API Key",
|
||||||
"Shrink Database": "Shrink Database",
|
"Shrink Database": "Shrink Database",
|
||||||
"Pick a RR-Type...": "Pick a RR-Type...",
|
"Pick a RR-Type...": "Pick a RR-Type...",
|
||||||
"Pick Accepted Status Codes...": "Chọn các Codes trạng thái chấp nhận được...",
|
"Pick Accepted Status Codes...": "Chọn các Codes trạng thái chấp nhận được...",
|
||||||
Default: "Mặc định",
|
Default: "Mặc định",
|
||||||
"HTTP Options": "Tuỳ chọn HTTP",
|
"HTTP Options": "Tuỳ chọn HTTP",
|
||||||
"Create Incident": "Create Incident",
|
"Create Incident": "Tạo Incident",
|
||||||
Title: "Tiêu đề",
|
Title: "Tiêu đề",
|
||||||
Content: "Nội dung",
|
Content: "Nội dung",
|
||||||
Style: "Style",
|
Style: "Style",
|
||||||
info: "info",
|
info: "thông tin",
|
||||||
warning: "cảnh báo",
|
warning: "cảnh báo",
|
||||||
danger: "nguy hiểm",
|
danger: "nguy hiểm",
|
||||||
primary: "primary",
|
primary: "cơ sở",
|
||||||
light: "sáng",
|
light: "sáng",
|
||||||
dark: "tối",
|
dark: "tối",
|
||||||
Post: "Post",
|
Post: "Post",
|
||||||
"Please input title and content": "Hãy nhập tiêu đề và nội dung",
|
"Please input title and content": "Hãy nhập tiêu đề và nội dung",
|
||||||
Created: "Created",
|
Created: "Đã tạo",
|
||||||
"Last Updated": "Cập nhật mới nhất",
|
"Last Updated": "Cập nhật mới nhất",
|
||||||
Unpin: "Bỏ ghim",
|
Unpin: "Bỏ ghim",
|
||||||
"Switch to Light Theme": "Chuyển sang Theme Sáng",
|
"Switch to Light Theme": "Chuyển sang giao diện Sáng",
|
||||||
"Switch to Dark Theme": "Chuyển sang Theme Tối",
|
"Switch to Dark Theme": "Chuyển sang giao diện Tối",
|
||||||
"Show Tags": "Hiện Tags",
|
"Show Tags": "Hiện Tags",
|
||||||
"Hide Tags": "Ẩn Tags",
|
"Hide Tags": "Ẩn Tags",
|
||||||
Description: "Mô tả",
|
Description: "Mô tả",
|
||||||
"No monitors available.": "Không có monitor nào.",
|
"No monitors available.": "Không có kênh theo dõi nào.",
|
||||||
"Add one": "Thêm mới",
|
"Add one": "Thêm mới",
|
||||||
"No Monitors": "No Monitors",
|
"No Monitors": "Không có kênh theo dõi",
|
||||||
"Untitled Group": "Nhóm không có tiêu đề",
|
"Untitled Group": "Nhóm không có tiêu đề",
|
||||||
Services: "Services",
|
Services: "Dịch vụ",
|
||||||
Discard: "Discard",
|
Discard: "Bỏ",
|
||||||
Cancel: "Cancel",
|
Cancel: "Hủy",
|
||||||
"Powered by": "Được cung cấp bởi",
|
"Powered by": "Được cung cấp bởi",
|
||||||
shrinkDatabaseDescription: "Khởi chạy database VACCUM cho SQLite. Nếu database được tạo sau version 1.10.0, AUTO_VACCUM đã được bật sẵn, hành động này không cần thiết.",
|
shrinkDatabaseDescription: "Khởi chạy database VACCUM cho SQLite. Nếu database được tạo sau version 1.10.0, AUTO_VACCUM đã được bật sẵn, hành động này không cần thiết.",
|
||||||
serwersms: "SerwerSMS.pl",
|
serwersms: "SerwerSMS.pl",
|
||||||
|
@ -352,11 +353,11 @@ export default {
|
||||||
serwersmsPhoneNumber: "Số điện thoại",
|
serwersmsPhoneNumber: "Số điện thoại",
|
||||||
serwersmsSenderName: "Tên người gửi SMS (Đã đăng ký qua portal)",
|
serwersmsSenderName: "Tên người gửi SMS (Đã đăng ký qua portal)",
|
||||||
"stackfield": "Stackfield",
|
"stackfield": "Stackfield",
|
||||||
smtpDkimSettings: "DKIM Settings",
|
smtpDkimSettings: "Cài đặt xác thực Email(DKIM)",
|
||||||
smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.",
|
smtpDkimDesc: "Xem hướng dẫn tại {0}.",
|
||||||
documentation: "documentation",
|
documentation: "Nodemailer DKIM",
|
||||||
smtpDkimDomain: "Domain Name",
|
smtpDkimDomain: "Mail domain",
|
||||||
smtpDkimKeySelector: "Key Selector",
|
smtpDkimKeySelector: "DKIM Key Selector",
|
||||||
smtpDkimPrivateKey: "Private Key",
|
smtpDkimPrivateKey: "Private Key",
|
||||||
smtpDkimHashAlgo: "Hash Algorithm (Tuỳ chọn)",
|
smtpDkimHashAlgo: "Hash Algorithm (Tuỳ chọn)",
|
||||||
smtpDkimheaderFieldNames: "Header Keys to sign (Tuỳ chọn)",
|
smtpDkimheaderFieldNames: "Header Keys to sign (Tuỳ chọn)",
|
|
@ -1,91 +1,104 @@
|
||||||
export default {
|
export default {
|
||||||
languageName: "简体中文",
|
languageName: "简体中文",
|
||||||
checkEverySecond: "检测频率 {0} 秒",
|
checkEverySecond: "检测频率 {0} 秒",
|
||||||
retriesDescription: "最大重试失败次数",
|
retryCheckEverySecond: "重试间隔 {0} 秒",
|
||||||
ignoreTLSError: "忽略HTTPS站点的证书错误",
|
retriesDescription: "服务被标记为故障并发送通知之前得最大重试次数",
|
||||||
upsideDownModeDescription: "反向状态监控(状态码范围外为有效状态,反之为无效)",
|
ignoreTLSError: "忽略 HTTPS 站点的 TLS/SSL 错误",
|
||||||
maxRedirectDescription: "最大重定向次数,设置为 0 禁止重定向",
|
upsideDownModeDescription: "反转状态监控,如果服务可访问,则认为是故障。",
|
||||||
acceptedStatusCodesDescription: "选择被视为成功响应的状态码",
|
maxRedirectDescription: "允许的最大重定向次数。设置为 0 禁用重定向。",
|
||||||
passwordNotMatchMsg: "两次密码输入不一致",
|
acceptedStatusCodesDescription: "选择被视为成功响应的状态码。",
|
||||||
notificationDescription: "请为监控项配置消息通知",
|
passwordNotMatchMsg: "两次输入的密码不一致。",
|
||||||
keywordDescription: "检测响应内容中的关键字,区分大小写",
|
notificationDescription: "通知必须被分配给监控项才能正常工作。",
|
||||||
|
keywordDescription: "在纯 HTML 或 JSON 响应中搜索关键字,区分大小写。",
|
||||||
pauseDashboardHome: "暂停",
|
pauseDashboardHome: "暂停",
|
||||||
deleteMonitorMsg: "确定要删除此监控吗?",
|
deleteMonitorMsg: "确定要删除此监控项吗?",
|
||||||
deleteNotificationMsg: "确定要删除此消息通知吗?这将对所有监控生效。",
|
deleteNotificationMsg: "确定要为所有监控项删除此通知吗?",
|
||||||
resoverserverDescription: "可自定义要使用的DNS服务器",
|
resolverserverDescription: "默认服务器是 Cloudflare。您随时可以修改解析服务器。",
|
||||||
rrtypeDescription: "选择要监控的资源记录类型",
|
rrtypeDescription: "选择要监控的资源记录类型",
|
||||||
pauseMonitorMsg: "确定要暂停吗?",
|
pauseMonitorMsg: "确定要暂停吗?",
|
||||||
|
enableDefaultNotificationDescription: "新的监控项将默认启用此通知,您仍然为每个监控项单独禁用。",
|
||||||
|
clearEventsMsg: "确定要删除此监控项的所有事件吗?",
|
||||||
|
clearHeartbeatsMsg: "确定要删除此监控项的所有心跳状态吗?",
|
||||||
|
confirmClearStatisticsMsg: "确定要删除所有统计信息吗?",
|
||||||
|
importHandleDescription: "如果想跳过同名的监控项或消息通知,请选择“跳过已存在”。“覆盖”将删除所有现有的监控项和通知。",
|
||||||
|
confirmImportMsg: "确定要导入备份吗?请确保已经选择了正确的导入选项。",
|
||||||
|
twoFAVerifyLabel: "请输入令牌码以确认二次验证:",
|
||||||
|
tokenValidSettingsMsg: "令牌码有效!您现在可以保存二次验证设置了。",
|
||||||
|
confirmEnableTwoFAMsg: "确定要启用二次验证吗?",
|
||||||
|
confirmDisableTwoFAMsg: "确定要禁用二次验证吗?",
|
||||||
Settings: "设置",
|
Settings: "设置",
|
||||||
Dashboard: "仪表盘",
|
Dashboard: "仪表盘",
|
||||||
"New Update": "有新版本更新",
|
"New Update": "有新版本",
|
||||||
Language: "语言",
|
Language: "语言",
|
||||||
Appearance: "外观设置",
|
Appearance: "外观",
|
||||||
Theme: "主题",
|
Theme: "主题",
|
||||||
General: "基本设置",
|
General: "常规",
|
||||||
"Primary Base URL": "站点地址(URL)",
|
"Primary Base URL": "站点主 URL",
|
||||||
|
About: "关于",
|
||||||
Version: "版本",
|
Version: "版本",
|
||||||
"Check Update On GitHub": "检查更新",
|
"Check Update On GitHub": "检查 GitHub 上的更新",
|
||||||
List: "列表",
|
List: "列表",
|
||||||
Add: "添加",
|
Add: "添加",
|
||||||
"Add New Monitor": "创建监控项",
|
"Add New Monitor": "添加监控项",
|
||||||
"Quick Stats": "状态速览",
|
"Quick Stats": "状态速览",
|
||||||
Up: "正常",
|
Up: "正常",
|
||||||
Down: "故障",
|
Down: "故障",
|
||||||
Pending: "检测失败",
|
Pending: "正在检测",
|
||||||
Unknown: "未知",
|
Unknown: "未知",
|
||||||
Pause: "暂停",
|
Pause: "暂停",
|
||||||
Name: "名称",
|
Name: "名称",
|
||||||
Status: "状态",
|
Status: "状态",
|
||||||
DateTime: "时间",
|
DateTime: "日期时间",
|
||||||
Message: "事件",
|
Message: "消息",
|
||||||
"No important events": "暂无重要事件",
|
"No important events": "暂无重要事件",
|
||||||
Resume: "恢复",
|
Resume: "恢复",
|
||||||
Edit: "修改",
|
Edit: "编辑",
|
||||||
Delete: "删除",
|
Delete: "删除",
|
||||||
Current: "当前",
|
Current: "当前",
|
||||||
Uptime: "可用率",
|
Uptime: "在线时间",
|
||||||
"Cert Exp.": "证书有效期",
|
"Cert Exp.": "证书有效期",
|
||||||
days: "天",
|
days: "天",
|
||||||
day: "天",
|
day: "天",
|
||||||
"-day": " 天",
|
"-day": " 天",
|
||||||
hour: "小时",
|
hour: "小时",
|
||||||
"-hour": " 小时",
|
"-hour": " 小时",
|
||||||
Response: "响应时长",
|
Response: "响应",
|
||||||
Ping: "Ping",
|
Ping: "Ping",
|
||||||
"Monitor Type": "监控类型",
|
"Monitor Type": "监控类型",
|
||||||
Keyword: "关键字",
|
Keyword: "关键字",
|
||||||
"Friendly Name": "自定义名称",
|
"Friendly Name": "显示名称",
|
||||||
URL: "网址URL",
|
URL: "URL",
|
||||||
Hostname: "主机名",
|
Hostname: "主机名",
|
||||||
Port: "端口号",
|
Port: "端口号",
|
||||||
"Heartbeat Interval": "心跳间隔",
|
"Heartbeat Interval": "心跳间隔",
|
||||||
Retries: "重试次数",
|
Retries: "重试次数",
|
||||||
Advanced: "高级选项",
|
"Heartbeat Retry Interval": "心跳重试间隔",
|
||||||
"Upside Down Mode": "反向监控",
|
Advanced: "高级",
|
||||||
"Max. Redirects": "重定向次数",
|
"Upside Down Mode": "反转监控",
|
||||||
|
"Max. Redirects": "最大重定向次数",
|
||||||
"Accepted Status Codes": "有效状态码",
|
"Accepted Status Codes": "有效状态码",
|
||||||
"Push URL": "推送链接",
|
"Push URL": "推送 URL",
|
||||||
needPushEvery: "你需要每 {0} 秒调用一次",
|
needPushEvery: "您需要每 {0} 秒调用一次该 URL",
|
||||||
pushOptionalParams: "可选参数:{0}",
|
pushOptionalParams: "可选参数:{0}",
|
||||||
Save: "保存",
|
Save: "保存",
|
||||||
Notifications: "消息通知",
|
Notifications: "通知",
|
||||||
"Not available, please setup.": "无可用通道,请先设置",
|
"Not available, please setup.": "暂不可用,请先设置",
|
||||||
"Setup Notification": "设置通知",
|
"Setup Notification": "设置通知",
|
||||||
Light: "明亮",
|
Light: "明亮",
|
||||||
Dark: "黑暗",
|
Dark: "黑暗",
|
||||||
Auto: "自动",
|
Auto: "自动",
|
||||||
"Theme - Heartbeat Bar": "状态显示",
|
"Theme - Heartbeat Bar": "主题 - 心跳栏",
|
||||||
Normal: "正常显示",
|
Normal: "正常显示",
|
||||||
Bottom: "靠下显示",
|
Bottom: "靠下显示",
|
||||||
None: "不显示",
|
None: "不显示",
|
||||||
Timezone: "时区",
|
Timezone: "时区",
|
||||||
"Search Engine Visibility": "搜索引擎设置",
|
"Search Engine Visibility": "搜索引擎可见性",
|
||||||
"Allow indexing": "允许索引",
|
"Allow indexing": "允许索引",
|
||||||
"Discourage search engines from indexing site": "阻止搜索引擎索引网站",
|
"Discourage search engines from indexing site": "阻止搜索引擎索引网站",
|
||||||
"Change Password": "修改密码",
|
"Change Password": "修改密码",
|
||||||
"Current Password": "当前密码",
|
"Current Password": "当前密码",
|
||||||
"New Password": "新的密码",
|
"New Password": "新密码",
|
||||||
"Repeat New Password": "重复新的密码",
|
"Repeat New Password": "重复新密码",
|
||||||
"Update Password": "更新密码",
|
"Update Password": "更新密码",
|
||||||
"Disable Auth": "禁用身份验证",
|
"Disable Auth": "禁用身份验证",
|
||||||
"Enable Auth": "启用身份验证",
|
"Enable Auth": "启用身份验证",
|
||||||
|
@ -93,73 +106,61 @@ export default {
|
||||||
Leave: "离开",
|
Leave: "离开",
|
||||||
"I understand, please disable": "我已了解,继续禁用",
|
"I understand, please disable": "我已了解,继续禁用",
|
||||||
Confirm: "确认",
|
Confirm: "确认",
|
||||||
Yes: "确定",
|
Yes: "是",
|
||||||
No: "取消",
|
No: "否",
|
||||||
Username: "用户名",
|
Username: "用户名",
|
||||||
Password: "密码",
|
Password: "密码",
|
||||||
"Remember me": "记住登录",
|
"Remember me": "记住我",
|
||||||
Login: "登录",
|
Login: "登录",
|
||||||
"No Monitors, please": "还没有监控项,",
|
"No Monitors, please": "还没有监控项,",
|
||||||
"add one": "点击新增",
|
"add one": "点击添加",
|
||||||
"Notification Type": "消息类型",
|
"Notification Type": "通知类型",
|
||||||
Email: "邮件",
|
Email: "邮件",
|
||||||
Test: "测试一下",
|
Test: "测试",
|
||||||
"Certificate Info": "证书信息",
|
"Certificate Info": "证书信息",
|
||||||
"Resolver Server": "解析服务器",
|
"Resolver Server": "解析服务器",
|
||||||
"Resource Record Type": "资源记录类型",
|
"Resource Record Type": "资源记录类型",
|
||||||
"Last Result": "最后结果",
|
"Last Result": "上次结果",
|
||||||
"Create your admin account": "创建管理员账号",
|
"Create your admin account": "创建管理员账户",
|
||||||
"Repeat Password": "重复密码",
|
"Repeat Password": "重复密码",
|
||||||
|
Backup: "备份",
|
||||||
|
"Import Backup": "导入备份",
|
||||||
|
"Export Backup": "导出备份",
|
||||||
|
Export: "导出",
|
||||||
|
Import: "导入",
|
||||||
respTime: "响应时间(毫秒)",
|
respTime: "响应时间(毫秒)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "默认开启",
|
||||||
|
"Apply on all existing monitors": "应用到所有现有监控项",
|
||||||
Create: "创建",
|
Create: "创建",
|
||||||
clearEventsMsg: "确定要删除此监控项的所有事件吗?",
|
|
||||||
clearHeartbeatsMsg: "确定要删除此监控项的所有状态吗?",
|
|
||||||
confirmClearStatisticsMsg: "确定要删除所有统计信息吗?",
|
|
||||||
"Clear Data": "清除数据",
|
"Clear Data": "清除数据",
|
||||||
Events: "事件",
|
Events: "事件",
|
||||||
Heartbeats: "心跳",
|
Heartbeats: "心跳",
|
||||||
"Auto Get": "自动获取",
|
"Auto Get": "自动获取",
|
||||||
enableDefaultNotificationDescription: "新的监控项将默认启用,你也可以在每个监控项中分别设置",
|
backupDescription: "您可以将所有监控项和通知备份到 JSON 文件。",
|
||||||
"Default enabled": "默认开启",
|
backupDescription2: "注意: 不包括历史状态和事件数据。",
|
||||||
"Also apply to existing monitors": "应用到所有监控项",
|
backupDescription3: "导出的文件可能包含敏感信息,例如通知的令牌信息,请小心存放!",
|
||||||
Export: "导出",
|
alertNoFile: "请选择要导入的文件",
|
||||||
Import: "导入",
|
alertWrongFileType: "请选择一个 JSON 文件",
|
||||||
backupDescription: "你可以将所有的监控项和消息通知备份到一个 JSON 文件中",
|
|
||||||
backupDescription2: "注意: 不包括历史状态和事件数据",
|
|
||||||
backupDescription3: "导出的文件中可能包含敏感信息,如消息通知的 Token 信息,请小心存放!",
|
|
||||||
alertNoFile: "请选择一个文件导入",
|
|
||||||
alertWrongFileType: "请选择一个 JSON 格式的文件",
|
|
||||||
twoFAVerifyLabel: "请输入Token以验证 2FA(二次验证)是否正常工作",
|
|
||||||
tokenValidSettingsMsg: "Token有效!您现在可以保存 2FA(二次验证)设置",
|
|
||||||
confirmEnableTwoFAMsg: "确定要启用 2FA(二次验证)吗?",
|
|
||||||
confirmDisableTwoFAMsg: "确定要禁用 2FA(二次验证)吗?",
|
|
||||||
"Apply on all existing monitors": "应用到所有监控项",
|
|
||||||
"Verify Token": "验证 Token",
|
|
||||||
"Setup 2FA": "设置 2FA",
|
|
||||||
"Enable 2FA": "启用 2FA",
|
|
||||||
"Disable 2FA": "禁用 2FA",
|
|
||||||
"2FA Settings": "2FA 设置",
|
|
||||||
"Two Factor Authentication": "双因素认证",
|
|
||||||
Active: "生效",
|
|
||||||
Inactive: "未生效",
|
|
||||||
Token: "Token",
|
|
||||||
"Show URI": "显示链接",
|
|
||||||
"Clear all statistics": "清除所有统计数据",
|
"Clear all statistics": "清除所有统计数据",
|
||||||
retryCheckEverySecond: "重试间隔 {0} 秒",
|
"Skip existing": "跳过已存在",
|
||||||
importHandleDescription: "如果想跳过同名的监控项或通知,请选择“跳过”;“覆盖”将删除所有现有的监控项和通知。",
|
|
||||||
confirmImportMsg: "确定要导入备份吗?请确保已经选择了正确的导入选项。",
|
|
||||||
"Heartbeat Retry Interval": "心跳重试间隔",
|
|
||||||
"Import Backup": "导入备份",
|
|
||||||
"Export Backup": "导出备份",
|
|
||||||
"Skip existing": "跳过",
|
|
||||||
Overwrite: "覆盖",
|
Overwrite: "覆盖",
|
||||||
Options: "选项",
|
Options: "选项",
|
||||||
"Keep both": "全部保留",
|
"Keep both": "全部保留",
|
||||||
|
"Verify Token": "验证令牌",
|
||||||
|
"Setup 2FA": "设置二次验证",
|
||||||
|
"Enable 2FA": "启用二次验证",
|
||||||
|
"Disable 2FA": "禁用二次验证",
|
||||||
|
"2FA Settings": "二次验证设置",
|
||||||
|
"Two Factor Authentication": "二次验证",
|
||||||
|
Active: "激活",
|
||||||
|
Inactive: "停用",
|
||||||
|
Token: "令牌",
|
||||||
|
"Show URI": "显示 URI",
|
||||||
Tags: "标签",
|
Tags: "标签",
|
||||||
"Add New below or Select...": "在下面新增或选择...",
|
"Add New below or Select...": "在下面添加或选择...",
|
||||||
"Tag with this name already exist.": "相同名称的标签已存在",
|
"Tag with this name already exist.": "相同名称的标签已存在。",
|
||||||
"Tag with this value already exist.": "相同内容的标签已存在",
|
"Tag with this value already exist.": "相同内容的标签已存在。",
|
||||||
color: "颜色",
|
color: "颜色",
|
||||||
"value (optional)": "值(可选)",
|
"value (optional)": "值(可选)",
|
||||||
Gray: "灰色",
|
Gray: "灰色",
|
||||||
|
@ -179,141 +180,142 @@ export default {
|
||||||
"All Systems Operational": "所有服务运行正常",
|
"All Systems Operational": "所有服务运行正常",
|
||||||
"Partially Degraded Service": "部分服务出现故障",
|
"Partially Degraded Service": "部分服务出现故障",
|
||||||
"Degraded Service": "全部服务出现故障",
|
"Degraded Service": "全部服务出现故障",
|
||||||
"Add Group": "新建分组",
|
"Add Group": "添加分组",
|
||||||
"Add a monitor": "添加监控项",
|
"Add a monitor": "添加监控项",
|
||||||
"Edit Status Page": "编辑状态页",
|
"Edit Status Page": "编辑状态页面",
|
||||||
"Go to Dashboard": "前往仪表盘",
|
"Go to Dashboard": "前往仪表盘",
|
||||||
"Status Page": "状态页",
|
"Status Page": "状态页面",
|
||||||
|
"Status Pages": "状态页面",
|
||||||
|
defaultNotificationName: "{notification} 通知({number})",
|
||||||
|
here: "这里",
|
||||||
|
Required: "必填",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "Bot Token",
|
||||||
|
wayToGetTelegramToken: "您可以从 {0} 获取 Token。",
|
||||||
|
"Chat ID": "Chat ID",
|
||||||
|
supportTelegramChatID: "支持对话/群组/频道的 Chat ID",
|
||||||
|
wayToGetTelegramChatID: "您可以发送一条消息给您的机器人,然后访问此链接来查看 chat_id:",
|
||||||
|
"YOUR BOT TOKEN HERE": "这里替换成您的 BOT TOKEN",
|
||||||
|
chatIDNotFound: "未找到 Chat ID,请先给您的机器人发送一条消息。",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
|
"Post URL": "Post URL",
|
||||||
|
"Content Type": "Content Type",
|
||||||
|
webhookJsonDesc: "{0} 适合现代的 HTTP 服务器,例如 Express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} 适合 PHP,其中 JSON 需要使用 {decodeFunction} 解码",
|
||||||
smtp: "电子邮件(SMTP)",
|
smtp: "电子邮件(SMTP)",
|
||||||
|
secureOptionNone: "无 / STARTTLS(常用端口 25、587)",
|
||||||
|
secureOptionTLS: "TLS(常用端口 465)",
|
||||||
|
"Ignore TLS Error": "忽略 TLS 错误",
|
||||||
|
"From Email": "发信人",
|
||||||
|
emailCustomSubject: "邮件主题",
|
||||||
|
"To Email": "收信人",
|
||||||
|
smtpCC: "抄送",
|
||||||
|
smtpBCC: "密送",
|
||||||
discord: "Discord",
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "要获取,可以前往服务器设置 -> 整合 -> 创建 Webhook",
|
||||||
|
"Bot Display Name": "机器人显示名称",
|
||||||
|
"Prefix Custom Message": "自定义消息前缀",
|
||||||
|
"Hello @everyone is...": "{'@'}everyone,……",
|
||||||
teams: "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "Webhook URL",
|
||||||
|
wayToGetTeamsURL: "您可以在 {0} 了解如何获取 Webhook URL。",
|
||||||
signal: "Signal",
|
signal: "Signal",
|
||||||
|
Number: "号码",
|
||||||
|
Recipients: "收件人",
|
||||||
|
needSignalAPI: "您需要有一个支持 REST API 的 Signal 客户端。",
|
||||||
|
wayToCheckSignalURL: "您可以通过下面的 URL 了解如何设置:",
|
||||||
|
signalImportant: "重要:您不能混合设定收件人的分组和号码!",
|
||||||
gotify: "Gotify",
|
gotify: "Gotify",
|
||||||
|
"Application Token": "Application Token",
|
||||||
|
"Server URL": "服务器 URL",
|
||||||
|
Priority: "优先级",
|
||||||
slack: "Slack",
|
slack: "Slack",
|
||||||
"rocket.chat": "Rocket.chat",
|
"Icon Emoji": "Emoji 图标",
|
||||||
|
"Channel Name": "频道名称",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "关于 Webhook 的更多信息:{0}",
|
||||||
|
aboutChannelName: "如果您想绕过 Webhook 频道,请在 {0} 字段输入所需的频道名称。例如:#other-channel",
|
||||||
|
aboutKumaURL: "如果保留 Uptime Kuma URL 为空,将会默认指向项目的 GitHub 页面。",
|
||||||
|
emojiCheatSheet: "Emoji 速查:{0}",
|
||||||
|
"rocket.chat": "Rocket.Chat",
|
||||||
pushover: "Pushover",
|
pushover: "Pushover",
|
||||||
pushy: "Pushy",
|
pushy: "Pushy",
|
||||||
octopush: "Octopush",
|
octopush: "Octopush",
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
lunasea: "LunaSea",
|
lunasea: "LunaSea",
|
||||||
apprise: "Apprise (支持50+种通知服务)",
|
apprise: "Apprise (支持 50+ 种通知服务)",
|
||||||
|
GoogleChat: "Google Chat(仅 Google Workspace)",
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
"Feishu WebHookUrl": "飞书 WebHook 地址",
|
|
||||||
defaultNotificationName: "{notification} 通知({number})",
|
|
||||||
here: "这里",
|
|
||||||
Required: "必填",
|
|
||||||
"Bot Token": "Bot Token",
|
|
||||||
wayToGetTelegramToken: "你可以从 {0} 获取 Token。",
|
|
||||||
"Chat ID": "Chat ID",
|
|
||||||
supportTelegramChatID: "支持对话/群组/频道的 ID",
|
|
||||||
wayToGetTelegramChatID: "你可以发送一条消息给你的机器人然后到下面的链接来查看你的 chat_id:",
|
|
||||||
"YOUR BOT TOKEN HERE": "这里替换成你的 BOT TOKEN",
|
|
||||||
chatIDNotFound: "没有找到 Chat ID,请先给你的机器人发送一条消息。",
|
|
||||||
"Post URL": "目标链接",
|
|
||||||
"Content Type": "Content Type",
|
|
||||||
webhookJsonDesc: "{0} 适合现代的服务,比如 express.js",
|
|
||||||
webhookFormDataDesc: "{multipart} 适合PHP,解码使用 {decodeFunction}",
|
|
||||||
secureOptionNone: "无 / STARTTLS(25,587)",
|
|
||||||
secureOptionTLS: "TLS(465)",
|
|
||||||
"Ignore TLS Error": "忽略 TLS 错误",
|
|
||||||
"From Email": "发信人",
|
|
||||||
"To Email": "收信人",
|
|
||||||
smtpCC: "抄送",
|
|
||||||
smtpBCC: "密送",
|
|
||||||
"Discord Webhook URL": "Discord Webhook 链接",
|
|
||||||
wayToGetDiscordURL: "获取方式:服务器设置 -> 整合 -> 创建 Webhook",
|
|
||||||
"Bot Display Name": "机器人显示名称",
|
|
||||||
"Prefix Custom Message": "自定义消息前缀",
|
|
||||||
"Hello @everyone is...": "{'@'}所有人,……",
|
|
||||||
"Webhook URL": "Webhook 链接",
|
|
||||||
wayToGetTeamsURL: "你可以在 {0} 获取 Webhook 链接。",
|
|
||||||
Number: "号码",
|
|
||||||
Recipients: "收件人",
|
|
||||||
needSignalAPI: "你需要有一个带 REST API 的 Signal 客户端。",
|
|
||||||
wayToCheckSignalURL: "你可以通过下面的链接来了解如何设置:",
|
|
||||||
signalImportant: "重要:你不能混合设定收件人的分组和号码!",
|
|
||||||
"Application Token": "Application Token",
|
|
||||||
"Server URL": "服务器链接",
|
|
||||||
Priority: "优先级",
|
|
||||||
"Icon Emoji": "Emoji 图标",
|
|
||||||
"Channel Name": "频道名称",
|
|
||||||
"Uptime Kuma URL": "Uptime Kuma 链接",
|
|
||||||
aboutWebhooks: "关于 Webhook 的更多信息:{0}",
|
|
||||||
aboutChannelName: "如果你想绕过 Webhook 设定的频道,请在设定 {0} 的频道名称字段为你想要的频道。例:#other-channel",
|
|
||||||
aboutKumaURL: "如果保留 Uptime Kuma 链接为空,将会默认指向项目的 Github 页面。",
|
|
||||||
emojiCheatSheet: "Emoji 参考表:{0}",
|
|
||||||
"User Key": "User Key",
|
"User Key": "User Key",
|
||||||
Device: "设备",
|
Device: "设备",
|
||||||
"Message Title": "消息标题",
|
"Message Title": "消息标题",
|
||||||
"Notification Sound": "通知铃声",
|
"Notification Sound": "通知铃声",
|
||||||
"More info on:": "更多信息:{0}",
|
"More info on:": "更多信息:{0}",
|
||||||
pushoverDesc1: "紧急优先级(2)会在一小时内每30秒重试一次。",
|
pushoverDesc1: "紧急优先级(2)会在一小时内每隔 30 秒重试一次。",
|
||||||
pushoverDesc2: "如果你想发送通知给不同的设备,请填写“设备”字段。",
|
pushoverDesc2: "如果您想发送通知给不同的设备,请填写“设备”字段。",
|
||||||
"SMS Type": "短信类型",
|
"SMS Type": "短信类型",
|
||||||
octopushTypePremium: "Premium(快 - 推荐用于警报)",
|
octopushTypePremium: "Premium(快 - 推荐用于警报)",
|
||||||
octopushTypeLowCost: "Low Cost(慢 - 有时会被运营商屏蔽)",
|
octopushTypeLowCost: "Low Cost(慢 - 有时会被运营商屏蔽)",
|
||||||
|
checkPrice: "查看 {0} 的价格:",
|
||||||
|
apiCredentials: "API Credentials",
|
||||||
|
octopushLegacyHint: "您是否在使用旧版本的 Octopush(2011-2020)?",
|
||||||
"Check octopush prices": "查看 Octopush 的价格 {0}。",
|
"Check octopush prices": "查看 Octopush 的价格 {0}。",
|
||||||
octopushPhoneNumber: "电话号码(国际格式,例:+33612345678)",
|
octopushPhoneNumber: "电话号码(国际格式,例如:+33612345678)",
|
||||||
octopushSMSSender: "短信发送名称:3-11位大小写字母、数字和空格(a-zA-Z0-9)",
|
octopushSMSSender: "短信发送名称:3-11 位大小写字母、数字和空格(a-zA-Z0-9)",
|
||||||
"LunaSea Device ID": "LunaSea 设备 ID",
|
"LunaSea Device ID": "LunaSea 设备 ID",
|
||||||
"Apprise URL": "Apprise 链接",
|
"Apprise URL": "Apprise URL",
|
||||||
"Example:": "例:{0}",
|
"Example:": "例如:{0}",
|
||||||
"Read more:": "了解更多:{0}",
|
"Read more:": "了解更多:{0}",
|
||||||
"Status:": "状态:{0}",
|
"Status:": "状态:{0}",
|
||||||
"Read more": "了解更多",
|
"Read more": "了解更多",
|
||||||
appriseInstalled: "Apprise 已安装",
|
appriseInstalled: "Apprise 已安装",
|
||||||
appriseNotInstalled: "Apprise 未安装。{0}",
|
appriseNotInstalled: "Apprise 未安装。{0}",
|
||||||
"Access Token": "Access Token",
|
"Access Token": "Access Token",
|
||||||
"Channel access token": "频道 access token",
|
"Channel access token": "频道 Access Token",
|
||||||
"Line Developers Console": "Line Developers Console",
|
"Line Developers Console": "Line 开发者控制台",
|
||||||
lineDevConsoleTo: "Line Developers Console - {0}",
|
lineDevConsoleTo: "Line 开发者控制台 - {0}",
|
||||||
"Basic Settings": "Basic Settings",
|
"Basic Settings": "基本设置",
|
||||||
"User ID": "User ID",
|
"User ID": "用户 ID",
|
||||||
"Messaging API": "Messaging API",
|
"Messaging API": "Messaging API",
|
||||||
wayToGetLineChannelToken: "首先访问 {0},创建一个提供者和频道(Messaging API),然后你就可以从上面提到的地方获取频道的 access token 和用户 ID。",
|
wayToGetLineChannelToken: "首先访问 {0},创建一个提供者和频道(Messaging API),然后您就可以从上面提到的菜单获取频道的 Access Token 和用户 ID。",
|
||||||
"Icon URL": "图标链接",
|
"Icon URL": "图标 URL",
|
||||||
aboutIconURL: "你可以在“Icon URL”中提供一个图片地址来覆盖默认的资料图片。如果设置了 Emoji 图标此字段会被忽略。",
|
aboutIconURL: "您可以在“图标 URL”中提供一个图片链接来覆盖默认的资料图片。如果设置了 Emoji 图标则此字段会被忽略。",
|
||||||
aboutMattermostChannelName: "如果你想覆盖 Webhook 设定的频道,请在“频道名称”字段为你想要的频道。这需要在 Mattermost 的 Webhook 设定中启用。例:#other-channel",
|
aboutMattermostChannelName: "您可以覆盖 Webhook 发送消息的默认频道,只需在“频道名称”字段中输入您想要的频道名。这需要在 Mattermost 的 Webhook 设置中启用。例如:#other-channel",
|
||||||
matrix: "Matrix",
|
matrix: "Matrix",
|
||||||
promosmsTypeEco: "SMS ECO - 便宜但是慢,并且容易超负荷。仅限波兰地区的收件人。",
|
promosmsTypeEco: "SMS ECO - 便宜但是慢,并且容易超负荷。仅限波兰地区的收信人。",
|
||||||
promosmsTypeFlash: "SMS FLASH - 消息会自动显示在收件人设备上。仅限波兰地区的收件人。",
|
promosmsTypeFlash: "SMS FLASH - 消息会自动显示在收信人设备上。仅限波兰地区的收信人。",
|
||||||
promosmsTypeFull: "SMS FULL - 高等级,你可以使用你自己的发件人名称(你需要先注册一个). 对于警报来说更可靠。",
|
promosmsTypeFull: "SMS FULL - 高级短信,您可以使用您自己的发信人名称(需要先注册)。对于警报来说更可靠。",
|
||||||
promosmsTypeSpeed: "SMS SPEED - 最高优先级。非常快速可靠,但更贵(越两倍 SMS FULL 等级的价格)。",
|
promosmsTypeSpeed: "SMS SPEED - 最高优先级。非常快速可靠,但更贵(大约两倍 SMS FULL 的价格)。",
|
||||||
promosmsPhoneNumber: "电话号码(波兰地区收件人可以不填区号)",
|
promosmsPhoneNumber: "电话号码(波兰地区收信人可以不填区号)",
|
||||||
promosmsSMSSender: "短信发件人名称:已注册的名称或以下默认值之一:InfoSMS,SMS Info,MaxSMS,INFO,SMS",
|
promosmsSMSSender: "短信发信人名称:已注册的名称或以下默认值之一:InfoSMS、SMS Info、MaxSMS、INFO、SMS",
|
||||||
checkPrice: "查看 {0} 的价格:",
|
"Feishu WebHookUrl": "飞书 WebHook URL",
|
||||||
octopushLegacyHint: "你是否在使用旧版本的 Octopush(2011-2020)?",
|
matrixHomeserverURL: "服务器 URL(包含 http(s):// 和可选的端口号)",
|
||||||
matrixHomeserverURL: "服务器链接(开头带 http(s):// 和可能的需要的端口号)",
|
"Internal Room Id": "内部房间 ID",
|
||||||
"Internal Room Id": "Internal Room Id",
|
matrixDesc1: "您可以在 Matrix 客户端房间设置的高级选项内找到内部房间 ID。格式类似于 !QMdRCpUIfLwsfjxye6:home.server。",
|
||||||
matrixDesc1: "你可以在 Matrix 客户端房间设置的高级选项找到 Internal Room Id。格式类似于 !QMdRCpUIfLwsfjxye6:home.server。",
|
matrixDesc2: "请不要使用您自己的 Access Token,这将开放您所有的账户权限和您已加入房间的权限。我们强烈建议您创建一个新用户并邀请它至您接收通知的房间中。您可以运行以下命令来获取 Access Token:{0}",
|
||||||
matrixDesc2: "请不要使用你自己的 Access Token,这将开放你所有的账户权限和你加入的房间权限。你可以创建一个新的用户并邀请它至你允许的的房间中。你可以运行以下命令来获取 Access Token:{0}",
|
|
||||||
emailCustomSubject: "邮件主题",
|
|
||||||
clicksendsms: "ClickSend SMS",
|
|
||||||
GoogleChat: "Google Chat (Google Workspace only)",
|
|
||||||
apiCredentials: "API credentials",
|
|
||||||
Method: "方法",
|
Method: "方法",
|
||||||
Body: "请求体",
|
Body: "请求体",
|
||||||
Headers: "请求头",
|
Headers: "请求头",
|
||||||
PushUrl: "Push URL",
|
PushUrl: "推送 URL",
|
||||||
HeadersInvalidFormat: "请求头不是有效的JSON: ",
|
HeadersInvalidFormat: "请求头不是有效的 JSON: ",
|
||||||
BodyInvalidFormat: "请求体不是有效的JSON: ",
|
BodyInvalidFormat: "请求体不是有效的 JSON: ",
|
||||||
"Monitor History": "监控历史数据",
|
"Monitor History": "监控历史",
|
||||||
clearDataOlderThan: "保留监控历史数据 {0} 天",
|
clearDataOlderThan: "保留监控历史数据 {0} 天。",
|
||||||
PasswordsDoNotMatch: "密码不匹配",
|
PasswordsDoNotMatch: "密码不匹配",
|
||||||
records: "records",
|
records: "记录",
|
||||||
"One record": "One record",
|
"One record": "一条记录",
|
||||||
steamApiKeyDescription: "为了监控Steam游戏服务器,你需要一个Steam Web-API key。你可以在这里注册你的API密钥: ",
|
steamApiKeyDescription: "要监控 Steam 游戏服务器,您需要 Steam Web-API 密钥。您可以在这里注册您的 API 密钥: ",
|
||||||
"Current User": "当前用户",
|
"Current User": "当前用户",
|
||||||
recent: "最近",
|
recent: "最近",
|
||||||
Done: "完成",
|
Done: "完成",
|
||||||
Info: "信息",
|
Info: "信息",
|
||||||
Security: "安全性",
|
Security: "安全性",
|
||||||
"Steam API Key": "Steam API Key",
|
"Steam API Key": "Steam API 密钥",
|
||||||
"Shrink Database": "缩小数据库",
|
"Shrink Database": "压缩数据库",
|
||||||
"Pick a RR-Type...": "选择资源记录类型...",
|
"Pick a RR-Type...": "选择资源记录类型...",
|
||||||
"Pick Accepted Status Codes...": "选择有效的状态码...",
|
"Pick Accepted Status Codes...": "选择有效的状态码...",
|
||||||
Default: "默认",
|
Default: "默认",
|
||||||
|
@ -322,44 +324,53 @@ export default {
|
||||||
Title: "标题",
|
Title: "标题",
|
||||||
Content: "内容",
|
Content: "内容",
|
||||||
Style: "类型",
|
Style: "类型",
|
||||||
info: "info",
|
info: "信息",
|
||||||
warning: "warning",
|
warning: "警告",
|
||||||
danger: "danger",
|
danger: "危险",
|
||||||
primary: "primary",
|
primary: "主要",
|
||||||
light: "light",
|
light: "明亮",
|
||||||
dark: "dark",
|
dark: "黑暗",
|
||||||
Post: "发布",
|
Post: "发布",
|
||||||
"Please input title and content": "请输入标题和内容",
|
"Please input title and content": "请输入标题和内容",
|
||||||
Created: "创建于",
|
Created: "创建时间",
|
||||||
"Last Updated": "最后更新",
|
"Last Updated": "更新时间",
|
||||||
Unpin: "删除",
|
Unpin: "取消钉选",
|
||||||
"Switch to Light Theme": "切换到浅色主题",
|
"Switch to Light Theme": "切换到浅色主题",
|
||||||
"Switch to Dark Theme": "切换到深色主题",
|
"Switch to Dark Theme": "切换到深色主题",
|
||||||
"Show Tags": "显示标签",
|
"Show Tags": "显示标签",
|
||||||
"Hide Tags": "隐藏标签",
|
"Hide Tags": "隐藏标签",
|
||||||
Description: "描述",
|
Description: "描述",
|
||||||
"No monitors available.": "没有可用的监控项",
|
"No monitors available.": "没有可用的监控项。",
|
||||||
"Add one": "Add one",
|
"Add one": "添加一个",
|
||||||
"No Monitors": "没有监控项",
|
"No Monitors": "没有监控项",
|
||||||
"Untitled Group": "无标题的分组",
|
"Untitled Group": "无标题分组",
|
||||||
Services: "服务",
|
Services: "服务",
|
||||||
Discard: "取消",
|
Discard: "放弃",
|
||||||
Cancel: "取消",
|
Cancel: "取消",
|
||||||
"Powered by": "Powered by",
|
"Powered by": "Powered by",
|
||||||
shrinkDatabaseDescription: "这将触发SQLite数据库的 VACUUM 命令,如果您的数据库是在1.10.0版本之后创建的,AUTO_VACUUM已经启用了,则不需要再使用此功能",
|
shrinkDatabaseDescription: "触发 SQLite 数据库的 VACUUM 命令,如果您的数据库是在 1.10.0 版本之后创建的,则已启用 AUTO_VACUUM,不再需要此操作。",
|
||||||
serwersms: "SerwerSMS.pl",
|
serwersms: "SerwerSMS.pl",
|
||||||
serwersmsAPIUser: "API Username (incl. webapi_ prefix)",
|
serwersmsAPIUser: "API 用户名(包括 webapi_ 前缀)",
|
||||||
serwersmsAPIPassword: "API Password",
|
serwersmsAPIPassword: "API 密码",
|
||||||
serwersmsPhoneNumber: "Phone number",
|
serwersmsPhoneNumber: "电话号码",
|
||||||
serwersmsSenderName: "SMS Sender Name (registered via customer portal)",
|
serwersmsSenderName: "SMS 发信人名称(需要在客户中心注册)",
|
||||||
stackfield: "Stackfield",
|
stackfield: "Stackfield",
|
||||||
smtpDkimSettings: "DKIM Settings",
|
smtpDkimSettings: "DKIM 设置",
|
||||||
smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.",
|
smtpDkimDesc: "请访问 Nodemailer DKIM {0} 了解配置方法。",
|
||||||
documentation: "documentation",
|
documentation: "文档",
|
||||||
smtpDkimDomain: "域名",
|
smtpDkimDomain: "域名",
|
||||||
smtpDkimKeySelector: "Key Selector",
|
smtpDkimKeySelector: "前缀选择器",
|
||||||
smtpDkimPrivateKey: "Private Key",
|
smtpDkimPrivateKey: "密钥",
|
||||||
smtpDkimHashAlgo: "Hash Algorithm (可选)",
|
smtpDkimHashAlgo: "哈希算法(可选)",
|
||||||
smtpDkimheaderFieldNames: "Header Keys to sign (可选)",
|
smtpDkimheaderFieldNames: "包含在哈希计算对象内的 Header 列表(可选)",
|
||||||
smtpDkimskipFields: "Header Keys not to sign (可选)",
|
smtpDkimskipFields: "不包含在哈希计算对象内的 Header 列表(可选)",
|
||||||
|
Feishu: "飞书",
|
||||||
|
AliyunSMS: "阿里云短信服务",
|
||||||
|
"Sms template must contain parameters: ": "短信模板必须包含以下变量:",
|
||||||
|
DingDing: "钉钉自定义机器人",
|
||||||
|
WebHookUrl: "钉钉自定义机器人 Webhook 地址",
|
||||||
|
SecretKey: "钉钉自定义机器人加签密钥",
|
||||||
|
"For safety, must use secret key": "出于安全考虑,必须使用加签密钥",
|
||||||
|
WeCom: "企业微信群机器人",
|
||||||
|
"WeCom Bot Key": "企业微信群机器人 Key",
|
||||||
};
|
};
|
||||||
|
|
|
@ -96,11 +96,11 @@ export default {
|
||||||
Test: "測試",
|
Test: "測試",
|
||||||
keywordDescription: "搜索 HTML 或 JSON 裡是否有出現關鍵字(注意英文大細階)",
|
keywordDescription: "搜索 HTML 或 JSON 裡是否有出現關鍵字(注意英文大細階)",
|
||||||
"Certificate Info": "憑證詳細資料",
|
"Certificate Info": "憑證詳細資料",
|
||||||
deleteMonitorMsg: "是否確定刪除這個監測器",
|
deleteMonitorMsg: "是否確定刪除這個監測器?",
|
||||||
deleteNotificationMsg: "是否確定刪除這個通知設定?如監測器啟用了這個通知,將會收不到通知。",
|
deleteNotificationMsg: "是否確定刪除這個通知設定?如監測器啟用了這個通知,將會收不到通知。",
|
||||||
"Resolver Server": "DNS 伺服器",
|
"Resolver Server": "DNS 伺服器",
|
||||||
"Resource Record Type": "DNS 記錄類型",
|
"Resource Record Type": "DNS 記錄類型",
|
||||||
resoverserverDescription: "預設值為 Cloudflare DNS 伺服器,你可以轉用其他 DNS 伺服器。",
|
resolverserverDescription: "預設值為 Cloudflare DNS 伺服器,你可以轉用其他 DNS 伺服器。",
|
||||||
rrtypeDescription: "請選擇 DNS 記錄類型",
|
rrtypeDescription: "請選擇 DNS 記錄類型",
|
||||||
pauseMonitorMsg: "是否確定暫停?",
|
pauseMonitorMsg: "是否確定暫停?",
|
||||||
"Last Result": "最後結果",
|
"Last Result": "最後結果",
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
"Edit Status Page": "編輯 Status Page",
|
"Edit Status Page": "編輯 Status Page",
|
||||||
"Go to Dashboard": "前往主控台",
|
"Go to Dashboard": "前往主控台",
|
||||||
"Status Page": "Status Page",
|
"Status Page": "Status Page",
|
||||||
|
"Status Pages": "Status Pages",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "電郵 (SMTP)",
|
smtp: "電郵 (SMTP)",
|
||||||
|
@ -198,4 +199,5 @@ export default {
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
deleteStatusPageMsg: "是否確定刪除這個 Status Page?",
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
||||||
pauseDashboardHome: "暫停",
|
pauseDashboardHome: "暫停",
|
||||||
deleteMonitorMsg: "您確定要刪除此監測器嗎?",
|
deleteMonitorMsg: "您確定要刪除此監測器嗎?",
|
||||||
deleteNotificationMsg: "您確定要為所有監測器刪除此通知嗎?",
|
deleteNotificationMsg: "您確定要為所有監測器刪除此通知嗎?",
|
||||||
resoverserverDescription: "Cloudflare 為預設伺服器。您可以隨時更換解析伺服器。",
|
resolverserverDescription: "Cloudflare 為預設伺服器。您可以隨時更換解析伺服器。",
|
||||||
rrtypeDescription: "選擇您想要監測的資源記錄類型",
|
rrtypeDescription: "選擇您想要監測的資源記錄類型",
|
||||||
pauseMonitorMsg: "您確定要暫停嗎?",
|
pauseMonitorMsg: "您確定要暫停嗎?",
|
||||||
enableDefaultNotificationDescription: "預設情況下,新監測器將啟用此通知。您仍可分別停用各監測器的通知。",
|
enableDefaultNotificationDescription: "預設情況下,新監測器將啟用此通知。您仍可分別停用各監測器的通知。",
|
||||||
|
@ -183,6 +183,7 @@ export default {
|
||||||
"Edit Status Page": "編輯狀態頁",
|
"Edit Status Page": "編輯狀態頁",
|
||||||
"Go to Dashboard": "前往儀表板",
|
"Go to Dashboard": "前往儀表板",
|
||||||
"Status Page": "狀態頁",
|
"Status Page": "狀態頁",
|
||||||
|
"Status Pages": "狀態頁",
|
||||||
defaultNotificationName: "我的 {notification} 通知 ({number})",
|
defaultNotificationName: "我的 {notification} 通知 ({number})",
|
||||||
here: "此處",
|
here: "此處",
|
||||||
Required: "必填",
|
Required: "必填",
|
||||||
|
@ -340,7 +341,6 @@ export default {
|
||||||
"No monitors available.": "沒有可用的監測器。",
|
"No monitors available.": "沒有可用的監測器。",
|
||||||
"Add one": "新增一個",
|
"Add one": "新增一個",
|
||||||
"No Monitors": "無監測器",
|
"No Monitors": "無監測器",
|
||||||
"Add one": "新增一個",
|
|
||||||
"Untitled Group": "未命名群組",
|
"Untitled Group": "未命名群組",
|
||||||
Services: "服務",
|
Services: "服務",
|
||||||
Discard: "捨棄",
|
Discard: "捨棄",
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<li class="nav-item me-2">
|
<li v-if="$root.loggedIn" class="nav-item me-2">
|
||||||
<a href="/status" class="nav-link status-page">
|
<router-link to="/manage-status-page" class="nav-link">
|
||||||
<font-awesome-icon icon="stream" /> {{ $t("Status Page") }}
|
<font-awesome-icon icon="stream" /> {{ $t("Status Pages") }}
|
||||||
</a>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="$root.loggedIn" class="nav-item me-2">
|
<li v-if="$root.loggedIn" class="nav-item me-2">
|
||||||
<router-link to="/dashboard" class="nav-link">
|
<router-link to="/dashboard" class="nav-link">
|
||||||
|
@ -157,7 +157,7 @@ export default {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&.router-link-exact-active {
|
&.router-link-exact-active, &.active {
|
||||||
color: $primary;
|
color: $primary;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
import { useToast } from "vue-toastification";
|
import { useToast } from "vue-toastification";
|
||||||
import jwt_decode from "jwt-decode";
|
import jwt_decode from "jwt-decode";
|
||||||
|
import Favico from "favico.js";
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
let socket;
|
let socket;
|
||||||
|
|
||||||
const noSocketIOPages = [
|
const noSocketIOPages = [
|
||||||
"/status-page",
|
/^\/status-page$/, // /status-page
|
||||||
"/status",
|
/^\/status/, // /status**
|
||||||
"/"
|
/^\/$/ // /
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const favicon = new Favico({
|
||||||
|
animation: "none"
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@ -33,6 +38,8 @@ export default {
|
||||||
uptimeList: { },
|
uptimeList: { },
|
||||||
tlsInfoList: {},
|
tlsInfoList: {},
|
||||||
notificationList: [],
|
notificationList: [],
|
||||||
|
statusPageListLoaded: false,
|
||||||
|
statusPageList: [],
|
||||||
connectionErrorMsg: "Cannot connect to the socket server. Reconnecting...",
|
connectionErrorMsg: "Cannot connect to the socket server. Reconnecting...",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -51,9 +58,13 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to connect to the socket.io for status page
|
// No need to connect to the socket.io for status page
|
||||||
if (! bypass && noSocketIOPages.includes(location.pathname)) {
|
if (! bypass && location.pathname) {
|
||||||
|
for (let page of noSocketIOPages) {
|
||||||
|
if (location.pathname.match(page)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.socket.initedSocketIO = true;
|
this.socket.initedSocketIO = true;
|
||||||
|
|
||||||
|
@ -103,6 +114,11 @@ export default {
|
||||||
this.notificationList = data;
|
this.notificationList = data;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("statusPageList", (data) => {
|
||||||
|
this.statusPageListLoaded = true;
|
||||||
|
this.statusPageList = data;
|
||||||
|
});
|
||||||
|
|
||||||
socket.on("heartbeat", (data) => {
|
socket.on("heartbeat", (data) => {
|
||||||
if (! (data.monitorID in this.heartbeatList)) {
|
if (! (data.monitorID in this.heartbeatList)) {
|
||||||
this.heartbeatList[data.monitorID] = [];
|
this.heartbeatList[data.monitorID] = [];
|
||||||
|
@ -239,6 +255,14 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toastSuccess(msg) {
|
||||||
|
toast.success(msg);
|
||||||
|
},
|
||||||
|
|
||||||
|
toastError(msg) {
|
||||||
|
toast.error(msg);
|
||||||
|
},
|
||||||
|
|
||||||
login(username, password, token, callback) {
|
login(username, password, token, callback) {
|
||||||
socket.emit("login", {
|
socket.emit("login", {
|
||||||
username,
|
username,
|
||||||
|
@ -392,10 +416,49 @@ export default {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
stats() {
|
||||||
|
let result = {
|
||||||
|
up: 0,
|
||||||
|
down: 0,
|
||||||
|
unknown: 0,
|
||||||
|
pause: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let monitorID in this.$root.monitorList) {
|
||||||
|
let beat = this.$root.lastHeartbeatList[monitorID];
|
||||||
|
let monitor = this.$root.monitorList[monitorID];
|
||||||
|
|
||||||
|
if (monitor && ! monitor.active) {
|
||||||
|
result.pause++;
|
||||||
|
} else if (beat) {
|
||||||
|
if (beat.status === 1) {
|
||||||
|
result.up++;
|
||||||
|
} else if (beat.status === 0) {
|
||||||
|
result.down++;
|
||||||
|
} else if (beat.status === 2) {
|
||||||
|
result.up++;
|
||||||
|
} else {
|
||||||
|
result.unknown++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.unknown++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
|
||||||
|
// Update Badge
|
||||||
|
"stats.down"(to, from) {
|
||||||
|
if (to !== from) {
|
||||||
|
favicon.badge(to);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Reload the SPA if the server version is changed.
|
// Reload the SPA if the server version is changed.
|
||||||
"info.version"(to, from) {
|
"info.version"(to, from) {
|
||||||
if (from && from !== to) {
|
if (from && from !== to) {
|
||||||
|
@ -409,9 +472,15 @@ export default {
|
||||||
|
|
||||||
// Reconnect the socket io, if status-page to dashboard
|
// Reconnect the socket io, if status-page to dashboard
|
||||||
"$route.fullPath"(newValue, oldValue) {
|
"$route.fullPath"(newValue, oldValue) {
|
||||||
if (noSocketIOPages.includes(newValue)) {
|
|
||||||
|
if (newValue) {
|
||||||
|
for (let page of noSocketIOPages) {
|
||||||
|
if (newValue.match(page)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.initSocketIO();
|
this.initSocketIO();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default {
|
||||||
return "light";
|
return "light";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.path === "/status-page" || this.path === "/status") {
|
if (this.path.startsWith("/status-page") || this.path.startsWith("/status")) {
|
||||||
return this.statusPageTheme;
|
return this.statusPageTheme;
|
||||||
} else {
|
} else {
|
||||||
if (this.userTheme === "auto") {
|
if (this.userTheme === "auto") {
|
||||||
|
|
79
src/pages/AddStatusPage.vue
Normal file
79
src/pages/AddStatusPage.vue
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<template>
|
||||||
|
<transition name="slide-fade" appear>
|
||||||
|
<div>
|
||||||
|
<h1 class="mb-3">
|
||||||
|
{{ $t("Add New Status Page") }}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<form @submit.prevent="submit">
|
||||||
|
<div class="shadow-box">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">{{ $t("Name") }}</label>
|
||||||
|
<input id="name" v-model="title" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="slug" class="form-label">{{ $t("Slug") }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span id="basic-addon3" class="input-group-text">/status/</span>
|
||||||
|
<input id="slug" v-model="slug" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-text">
|
||||||
|
<ul>
|
||||||
|
<li>{{ $t("Accept characters:") }} <mark>a-z</mark> <mark>0-9</mark> <mark>-</mark></li>
|
||||||
|
<li>{{ $t("Start or end with") }} <mark>a-z</mark> <mark>0-9</mark> only</li>
|
||||||
|
<li>{{ $t("No consecutive dashes") }} <mark>--</mark></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2 mb-1">
|
||||||
|
<button id="monitor-submit-btn" class="btn btn-primary w-100" type="submit" :disabled="processing">{{ $t("Next") }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
title: "",
|
||||||
|
slug: "",
|
||||||
|
processing: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async submit() {
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
this.$root.getSocket().emit("addStatusPage", this.title, this.slug, (res) => {
|
||||||
|
this.processing = false;
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
location.href = "/status/" + this.slug + "?edit";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (res.msg.includes("UNIQUE constraint")) {
|
||||||
|
this.$root.toastError(this.$t("The slug is already taken. Please choose another slug."));
|
||||||
|
} else {
|
||||||
|
this.$root.toastRes(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.shadow-box {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -9,19 +9,19 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>{{ $t("Up") }}</h3>
|
<h3>{{ $t("Up") }}</h3>
|
||||||
<span class="num">{{ stats.up }}</span>
|
<span class="num">{{ $root.stats.up }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>{{ $t("Down") }}</h3>
|
<h3>{{ $t("Down") }}</h3>
|
||||||
<span class="num text-danger">{{ stats.down }}</span>
|
<span class="num text-danger">{{ $root.stats.down }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>{{ $t("Unknown") }}</h3>
|
<h3>{{ $t("Unknown") }}</h3>
|
||||||
<span class="num text-secondary">{{ stats.unknown }}</span>
|
<span class="num text-secondary">{{ $root.stats.unknown }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>{{ $t("pauseDashboardHome") }}</h3>
|
<h3>{{ $t("pauseDashboardHome") }}</h3>
|
||||||
<span class="num text-secondary">{{ stats.pause }}</span>
|
<span class="num text-secondary">{{ $root.stats.pause }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -89,37 +89,6 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
stats() {
|
|
||||||
let result = {
|
|
||||||
up: 0,
|
|
||||||
down: 0,
|
|
||||||
unknown: 0,
|
|
||||||
pause: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let monitorID in this.$root.monitorList) {
|
|
||||||
let beat = this.$root.lastHeartbeatList[monitorID];
|
|
||||||
let monitor = this.$root.monitorList[monitorID];
|
|
||||||
|
|
||||||
if (monitor && ! monitor.active) {
|
|
||||||
result.pause++;
|
|
||||||
} else if (beat) {
|
|
||||||
if (beat.status === 1) {
|
|
||||||
result.up++;
|
|
||||||
} else if (beat.status === 0) {
|
|
||||||
result.down++;
|
|
||||||
} else if (beat.status === 2) {
|
|
||||||
result.up++;
|
|
||||||
} else {
|
|
||||||
result.unknown++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.unknown++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
importantHeartBeatList() {
|
importantHeartBeatList() {
|
||||||
let result = [];
|
let result = [];
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
<label for="dns_resolve_server" class="form-label">{{ $t("Resolver Server") }}</label>
|
<label for="dns_resolve_server" class="form-label">{{ $t("Resolver Server") }}</label>
|
||||||
<input id="dns_resolve_server" v-model="monitor.dns_resolve_server" type="text" class="form-control" :pattern="ipRegex" required>
|
<input id="dns_resolve_server" v-model="monitor.dns_resolve_server" type="text" class="form-control" :pattern="ipRegex" required>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
{{ $t("resoverserverDescription") }}
|
{{ $t("resolverserverDescription") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
118
src/pages/ManageStatusPage.vue
Normal file
118
src/pages/ManageStatusPage.vue
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
<template>
|
||||||
|
<transition name="slide-fade" appear>
|
||||||
|
<div>
|
||||||
|
<h1 class="mb-3">
|
||||||
|
{{ $t("Status Pages") }}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<router-link to="/add-status-page" class="btn btn-primary mb-3"><font-awesome-icon icon="plus" /> {{ $t("New Status Page") }}</router-link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="shadow-box">
|
||||||
|
<template v-if="$root.statusPageListLoaded">
|
||||||
|
<span v-if="Object.keys($root.statusPageList).length === 0" class="d-flex align-items-center justify-content-center my-3">
|
||||||
|
No status pages
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- use <a> instead of <router-link>, because the heartbeat won't load. -->
|
||||||
|
<a v-for="statusPage in $root.statusPageList" :key="statusPage.slug" :href="'/status/' + statusPage.slug" class="item">
|
||||||
|
<img :src="icon(statusPage.icon)" alt class="logo me-2" />
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">{{ statusPage.title }}</div>
|
||||||
|
<div class="slug">/status/{{ statusPage.slug }}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<div v-else class="d-flex align-items-center justify-content-center my-3 spinner">
|
||||||
|
<font-awesome-icon icon="spinner" size="2x" spin />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { getResBaseURL } from "../util-frontend";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
icon(icon) {
|
||||||
|
if (icon === "/icon.svg") {
|
||||||
|
return icon;
|
||||||
|
} else {
|
||||||
|
return getResBaseURL() + icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../assets/vars.scss";
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
transition: all ease-in-out 0.15s;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $highlight-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #cdf8f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
$logo-width: 70px;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: $logo-width;
|
||||||
|
|
||||||
|
// Better when the image is loading
|
||||||
|
min-height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slug {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
.item {
|
||||||
|
&:hover {
|
||||||
|
background-color: $dark-bg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: $dark-bg2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<div class="shadow-box">
|
<div class="shadow-box">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="settings-menu">
|
<div v-if="showSubMenu" class="settings-menu col-lg-3 col-md-5">
|
||||||
<router-link
|
<router-link
|
||||||
v-for="(item, key) in subMenus"
|
v-for="(item, key) in subMenus"
|
||||||
:key="key"
|
:key="key"
|
||||||
|
@ -17,8 +17,8 @@
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-content">
|
<div class="settings-content col-lg-9 col-md-7">
|
||||||
<div class="settings-content-header">
|
<div v-if="currentPage" class="settings-content-header">
|
||||||
{{ subMenus[currentPage].title }}
|
{{ subMenus[currentPage].title }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-3">
|
<div class="mx-3">
|
||||||
|
@ -41,7 +41,6 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
show: true,
|
show: true,
|
||||||
|
|
||||||
settings: {},
|
settings: {},
|
||||||
settingsLoaded: false,
|
settingsLoaded: false,
|
||||||
};
|
};
|
||||||
|
@ -52,11 +51,19 @@ export default {
|
||||||
let pathSplit = useRoute().path.split("/");
|
let pathSplit = useRoute().path.split("/");
|
||||||
let pathEnd = pathSplit[pathSplit.length - 1];
|
let pathEnd = pathSplit[pathSplit.length - 1];
|
||||||
if (!pathEnd || pathEnd === "settings") {
|
if (!pathEnd || pathEnd === "settings") {
|
||||||
return "general";
|
return null;
|
||||||
}
|
}
|
||||||
return pathEnd;
|
return pathEnd;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showSubMenu() {
|
||||||
|
if (this.$root.isMobile) {
|
||||||
|
return !this.currentPage;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
subMenus() {
|
subMenus() {
|
||||||
return {
|
return {
|
||||||
general: {
|
general: {
|
||||||
|
@ -84,11 +91,26 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
"$root.isMobile"() {
|
||||||
|
this.loadGeneralPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.loadSettings();
|
this.loadSettings();
|
||||||
|
this.loadGeneralPage();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
// For desktop only, mobile do nothing
|
||||||
|
loadGeneralPage() {
|
||||||
|
if (!this.currentPage && !this.$root.isMobile) {
|
||||||
|
this.$router.push("/settings/general");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
loadSettings() {
|
loadSettings() {
|
||||||
this.$root.getSocket().emit("getSettings", (res) => {
|
this.$root.getSocket().emit("getSettings", (res) => {
|
||||||
this.settings = res.data;
|
this.settings = res.data;
|
||||||
|
@ -115,7 +137,7 @@ export default {
|
||||||
this.loadSettings();
|
this.loadSettings();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -136,9 +158,6 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-menu {
|
.settings-menu {
|
||||||
flex: 0 0 auto;
|
|
||||||
width: 300px;
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
@ -148,6 +167,8 @@ footer {
|
||||||
margin: 0.5em;
|
margin: 0.5em;
|
||||||
padding: 0.7em 1em;
|
padding: 0.7em 1em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-left-width: 0;
|
||||||
|
transition: all ease-in-out 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item:hover {
|
.menu-item:hover {
|
||||||
|
@ -171,9 +192,6 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-content {
|
.settings-content {
|
||||||
flex: 0 0 auto;
|
|
||||||
width: calc(100% - 300px);
|
|
||||||
|
|
||||||
.settings-content-header {
|
.settings-content-header {
|
||||||
width: calc(100% + 20px);
|
width: calc(100% + 20px);
|
||||||
border-bottom: 1px solid #dee2e6;
|
border-bottom: 1px solid #dee2e6;
|
||||||
|
@ -187,6 +205,14 @@ footer {
|
||||||
background: $dark-header-bg;
|
background: $dark-header-bg;
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile & {
|
||||||
|
padding: 15px 0 0 0;
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,70 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="loadedTheme" class="container mt-3">
|
<div v-if="loadedTheme" class="container mt-3">
|
||||||
|
<!-- Sidebar for edit mode -->
|
||||||
|
<div v-if="enableEditMode" class="sidebar">
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="slug" class="form-label">{{ $t("Slug") }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span id="basic-addon3" class="input-group-text">/status/</span>
|
||||||
|
<input id="slug" v-model="config.slug" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="title" class="form-label">{{ $t("Title") }}</label>
|
||||||
|
<input id="title" v-model="config.title" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="description" class="form-label">{{ $t("Description") }}</label>
|
||||||
|
<textarea id="description" v-model="config.description" class="form-control"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-3 form-check form-switch">
|
||||||
|
<input id="switch-theme" v-model="config.theme" class="form-check-input" type="checkbox" true-value="dark" false-value="light">
|
||||||
|
<label class="form-check-label" for="switch-theme">{{ $t("Switch to Dark Theme") }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-3 form-check form-switch">
|
||||||
|
<input id="showTags" v-model="config.showTags" class="form-check-input" type="checkbox">
|
||||||
|
<label class="form-check-label" for="showTags">{{ $t("Show Tags") }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="false" class="my-3">
|
||||||
|
<label for="password" class="form-label">{{ $t("Password") }} <sup>Coming Soon</sup></label>
|
||||||
|
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="false" class="my-3">
|
||||||
|
<label for="cname" class="form-label">Domain Names <sup>Coming Soon</sup></label>
|
||||||
|
<textarea id="cname" v-model="config.domanNames" rows="3" disabled class="form-control" :placeholder="domainNamesPlaceholder"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="danger-zone">
|
||||||
|
<button class="btn btn-danger me-2" @click="deleteDialog">
|
||||||
|
<font-awesome-icon icon="trash" />
|
||||||
|
{{ $t("Delete") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sidebar Footer -->
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
<button class="btn btn-success me-2" @click="save">
|
||||||
|
<font-awesome-icon icon="save" />
|
||||||
|
{{ $t("Save") }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn btn-danger me-2" @click="discard">
|
||||||
|
<font-awesome-icon icon="save" />
|
||||||
|
{{ $t("Discard") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Status Page -->
|
||||||
|
<div :class="{ edit: enableEditMode}" class="main">
|
||||||
<!-- Logo & Title -->
|
<!-- Logo & Title -->
|
||||||
<h1 class="mb-4">
|
<h1 class="mb-4 title-flex">
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<span class="logo-wrapper" @click="showImageCropUploadMethod">
|
<span class="logo-wrapper" @click="showImageCropUploadMethod">
|
||||||
<img :src="logoURL" alt class="logo me-2" :class="logoClass" />
|
<img :src="logoURL" alt class="logo me-2" :class="logoClass" />
|
||||||
|
@ -33,61 +96,17 @@
|
||||||
{{ $t("Edit Status Page") }}
|
{{ $t("Edit Status Page") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<a href="/dashboard" class="btn btn-info">
|
<a href="/manage-status-page" class="btn btn-info">
|
||||||
<font-awesome-icon icon="tachometer-alt" />
|
<font-awesome-icon icon="tachometer-alt" />
|
||||||
{{ $t("Go to Dashboard") }}
|
{{ $t("Go to Dashboard") }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<button class="btn btn-success me-2" @click="save">
|
|
||||||
<font-awesome-icon icon="save" />
|
|
||||||
{{ $t("Save") }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-danger me-2" @click="discard">
|
|
||||||
<font-awesome-icon icon="save" />
|
|
||||||
{{ $t("Discard") }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-primary btn-add-group me-2" @click="createIncident">
|
<button class="btn btn-primary btn-add-group me-2" @click="createIncident">
|
||||||
<font-awesome-icon icon="bullhorn" />
|
<font-awesome-icon icon="bullhorn" />
|
||||||
{{ $t("Create Incident") }}
|
{{ $t("Create Incident") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!--
|
|
||||||
<button v-if="isPublished" class="btn btn-light me-2" @click="">
|
|
||||||
<font-awesome-icon icon="save" />
|
|
||||||
{{ $t("Unpublish") }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button v-if="!isPublished" class="btn btn-info me-2" @click="">
|
|
||||||
<font-awesome-icon icon="save" />
|
|
||||||
{{ $t("Publish") }}
|
|
||||||
</button>-->
|
|
||||||
|
|
||||||
<!-- Set Default Language -->
|
|
||||||
<!-- Set theme -->
|
|
||||||
<button v-if="theme == 'dark'" class="btn btn-light me-2" @click="changeTheme('light')">
|
|
||||||
<font-awesome-icon icon="save" />
|
|
||||||
{{ $t("Switch to Light Theme") }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button v-if="theme == 'light'" class="btn btn-dark me-2" @click="changeTheme('dark')">
|
|
||||||
<font-awesome-icon icon="save" />
|
|
||||||
{{ $t("Switch to Dark Theme") }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-secondary me-2" @click="changeTagsVisibilty(!tagsVisible)">
|
|
||||||
<template v-if="tagsVisible">
|
|
||||||
<font-awesome-icon icon="eye-slash" />
|
|
||||||
{{ $t("Hide Tags") }}
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<font-awesome-icon icon="eye" />
|
|
||||||
{{ $t("Show Tags") }}
|
|
||||||
</template>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -204,13 +223,18 @@
|
||||||
👀 {{ $t("statusPageNothing") }}
|
👀 {{ $t("statusPageNothing") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PublicGroupList :edit-mode="enableEditMode" />
|
<PublicGroupList :edit-mode="enableEditMode" :show-tags="config.showTags" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="mt-5 mb-4">
|
<footer class="mt-5 mb-4">
|
||||||
{{ $t("Powered by") }} <a target="_blank" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
{{ $t("Powered by") }} <a target="_blank" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteStatusPage">
|
||||||
|
{{ $t("deleteStatusPageMsg") }}
|
||||||
|
</Confirm>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -220,16 +244,25 @@ import ImageCropUpload from "vue-image-crop-upload";
|
||||||
import { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_PARTIAL_DOWN, UP } from "../util.ts";
|
import { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_PARTIAL_DOWN, UP } from "../util.ts";
|
||||||
import { useToast } from "vue-toastification";
|
import { useToast } from "vue-toastification";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import Favico from "favico.js";
|
||||||
|
import { getResBaseURL } from "../util-frontend";
|
||||||
|
import Confirm from "../components/Confirm.vue";
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const leavePageMsg = "Do you really want to leave? you have unsaved changes!";
|
const leavePageMsg = "Do you really want to leave? you have unsaved changes!";
|
||||||
|
|
||||||
let feedInterval;
|
let feedInterval;
|
||||||
|
|
||||||
|
const favicon = new Favico({
|
||||||
|
animation: "none"
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
PublicGroupList,
|
PublicGroupList,
|
||||||
ImageCropUpload
|
ImageCropUpload,
|
||||||
|
Confirm,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Leave Page for vue route change
|
// Leave Page for vue route change
|
||||||
|
@ -247,6 +280,7 @@ export default {
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
slug: null,
|
||||||
enableEditMode: false,
|
enableEditMode: false,
|
||||||
enableEditIncidentMode: false,
|
enableEditIncidentMode: false,
|
||||||
hasToken: false,
|
hasToken: false,
|
||||||
|
@ -259,6 +293,8 @@ export default {
|
||||||
loadedTheme: false,
|
loadedTheme: false,
|
||||||
loadedData: false,
|
loadedData: false,
|
||||||
baseURL: "",
|
baseURL: "",
|
||||||
|
clickedEditButton: false,
|
||||||
|
domainNamesPlaceholder: "domain1.com\ndomain2.com\n..."
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -296,15 +332,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
isPublished() {
|
isPublished() {
|
||||||
return this.config.statusPagePublished;
|
return this.config.published;
|
||||||
},
|
|
||||||
|
|
||||||
theme() {
|
|
||||||
return this.config.statusPageTheme;
|
|
||||||
},
|
|
||||||
|
|
||||||
tagsVisible() {
|
|
||||||
return this.config.statusPageTags
|
|
||||||
},
|
},
|
||||||
|
|
||||||
logoClass() {
|
logoClass() {
|
||||||
|
@ -378,13 +406,28 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Set Theme
|
// Set Theme
|
||||||
"config.statusPageTheme"() {
|
"config.theme"() {
|
||||||
this.$root.statusPageTheme = this.config.statusPageTheme;
|
this.$root.statusPageTheme = this.config.theme;
|
||||||
this.loadedTheme = true;
|
this.loadedTheme = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
"config.title"(title) {
|
"config.title"(title) {
|
||||||
document.title = title;
|
document.title = title;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$root.monitorList"() {
|
||||||
|
let count = Object.keys(this.$root.monitorList).length;
|
||||||
|
|
||||||
|
// Since publicGroupList is getting from public rest api, monitors' tags may not present if showTags = false
|
||||||
|
if (count > 0) {
|
||||||
|
for (let group of this.$root.publicGroupList) {
|
||||||
|
for (let monitor of group.monitorList) {
|
||||||
|
if (monitor.tags === undefined && this.$root.monitorList[monitor.id]) {
|
||||||
|
monitor.tags = this.$root.monitorList[monitor.id].tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -403,28 +446,24 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Special handle for dev
|
// Special handle for dev
|
||||||
const env = process.env.NODE_ENV;
|
this.baseURL = getResBaseURL();
|
||||||
if (env === "development" || localStorage.dev === "dev") {
|
|
||||||
this.baseURL = location.protocol + "//" + location.hostname + ":3001";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
axios.get("/api/status-page/config").then((res) => {
|
this.slug = this.$route.params.slug;
|
||||||
this.config = res.data;
|
|
||||||
|
|
||||||
if (this.config.logo) {
|
if (!this.slug) {
|
||||||
this.imgDataUrl = this.config.logo;
|
this.slug = "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.get("/api/status-page/" + this.slug).then((res) => {
|
||||||
|
this.config = res.data.config;
|
||||||
|
|
||||||
|
if (this.config.icon) {
|
||||||
|
this.imgDataUrl = this.config.icon;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
axios.get("/api/status-page/incident").then((res) => {
|
|
||||||
if (res.data.ok) {
|
|
||||||
this.incident = res.data.incident;
|
this.incident = res.data.incident;
|
||||||
}
|
this.$root.publicGroupList = res.data.publicGroupList;
|
||||||
});
|
|
||||||
|
|
||||||
axios.get("/api/status-page/monitor-list").then((res) => {
|
|
||||||
this.$root.publicGroupList = res.data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 5mins a loop
|
// 5mins a loop
|
||||||
|
@ -432,31 +471,86 @@ export default {
|
||||||
feedInterval = setInterval(() => {
|
feedInterval = setInterval(() => {
|
||||||
this.updateHeartbeatList();
|
this.updateHeartbeatList();
|
||||||
}, (300 + 10) * 1000);
|
}, (300 + 10) * 1000);
|
||||||
|
|
||||||
|
// Go to edit page if ?edit present
|
||||||
|
// null means ?edit present, but no value
|
||||||
|
if (this.$route.query.edit || this.$route.query.edit === null) {
|
||||||
|
this.edit();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
updateHeartbeatList() {
|
updateHeartbeatList() {
|
||||||
// If editMode, it will use the data from websocket.
|
// If editMode, it will use the data from websocket.
|
||||||
if (! this.editMode) {
|
if (! this.editMode) {
|
||||||
axios.get("/api/status-page/heartbeat").then((res) => {
|
axios.get("/api/status-page/heartbeat/" + this.slug).then((res) => {
|
||||||
this.$root.heartbeatList = res.data.heartbeatList;
|
const { heartbeatList, uptimeList } = res.data;
|
||||||
this.$root.uptimeList = res.data.uptimeList;
|
|
||||||
|
this.$root.heartbeatList = heartbeatList;
|
||||||
|
this.$root.uptimeList = uptimeList;
|
||||||
|
|
||||||
|
const heartbeatIds = Object.keys(heartbeatList);
|
||||||
|
const downMonitors = heartbeatIds.reduce((downMonitorsAmount, currentId) => {
|
||||||
|
const monitorHeartbeats = heartbeatList[currentId];
|
||||||
|
const lastHeartbeat = monitorHeartbeats.at(-1);
|
||||||
|
|
||||||
|
if (lastHeartbeat) {
|
||||||
|
return lastHeartbeat.status === 0 ? downMonitorsAmount + 1 : downMonitorsAmount;
|
||||||
|
} else {
|
||||||
|
return downMonitorsAmount;
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
favicon.badge(downMonitors);
|
||||||
|
|
||||||
this.loadedData = true;
|
this.loadedData = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
edit() {
|
edit() {
|
||||||
|
if (this.hasToken) {
|
||||||
this.$root.initSocketIO(true);
|
this.$root.initSocketIO(true);
|
||||||
this.enableEditMode = true;
|
this.enableEditMode = true;
|
||||||
|
this.clickedEditButton = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.$root.getSocket().emit("saveStatusPage", this.config, this.imgDataUrl, this.$root.publicGroupList, (res) => {
|
let startTime = new Date();
|
||||||
|
|
||||||
|
this.$root.getSocket().emit("saveStatusPage", this.slug, this.config, this.imgDataUrl, this.$root.publicGroupList, (res) => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.enableEditMode = false;
|
this.enableEditMode = false;
|
||||||
this.$root.publicGroupList = res.publicGroupList;
|
this.$root.publicGroupList = res.publicGroupList;
|
||||||
location.reload();
|
|
||||||
|
// Add some delay, so that the side menu animation would be better
|
||||||
|
let endTime = new Date();
|
||||||
|
let time = 100 - (endTime - startTime) / 1000;
|
||||||
|
|
||||||
|
if (time < 0) {
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
location.href = "/status/" + this.config.slug;
|
||||||
|
}, time);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
toast.error(res.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteDialog() {
|
||||||
|
this.$refs.confirmDelete.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteStatusPage() {
|
||||||
|
this.$root.getSocket().emit("deleteStatusPage", this.slug, (res) => {
|
||||||
|
if (res.ok) {
|
||||||
|
this.enableEditMode = false;
|
||||||
|
location.href = "/manage-status-page";
|
||||||
} else {
|
} else {
|
||||||
toast.error(res.msg);
|
toast.error(res.msg);
|
||||||
}
|
}
|
||||||
|
@ -481,30 +575,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
discard() {
|
discard() {
|
||||||
location.reload();
|
location.href = "/status/" + this.slug;
|
||||||
},
|
|
||||||
|
|
||||||
changeTheme(name) {
|
|
||||||
this.config.statusPageTheme = name;
|
|
||||||
},
|
|
||||||
changeTagsVisibilty(newState) {
|
|
||||||
this.config.statusPageTags = newState;
|
|
||||||
|
|
||||||
// On load, the status page will not include tags if it's not enabled for security reasons
|
|
||||||
// Which means if we enable tags, it won't show in the UI until saved
|
|
||||||
// So we have this to enhance UX and load in the tags from the authenticated source instantly
|
|
||||||
this.$root.publicGroupList = this.$root.publicGroupList.map((group) => {
|
|
||||||
return {
|
|
||||||
...group,
|
|
||||||
monitorList: group.monitorList.map((monitor) => {
|
|
||||||
// We only include the tags if visible so we can reuse the logic to hide the tags on disable
|
|
||||||
return {
|
|
||||||
...monitor,
|
|
||||||
tags: newState ? this.$root.monitorList[monitor.id].tags : []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -540,7 +611,7 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$root.getSocket().emit("postIncident", this.incident, (res) => {
|
this.$root.getSocket().emit("postIncident", this.slug, this.incident, (res) => {
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.enableEditIncidentMode = false;
|
this.enableEditIncidentMode = false;
|
||||||
|
@ -571,7 +642,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
unpinIncident() {
|
unpinIncident() {
|
||||||
this.$root.getSocket().emit("unpinIncident", () => {
|
this.$root.getSocket().emit("unpinIncident", this.slug, () => {
|
||||||
this.incident = null;
|
this.incident = null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -614,6 +685,40 @@ h1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
transition: all ease-in-out 0.1s;
|
||||||
|
|
||||||
|
&.edit {
|
||||||
|
margin-left: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 300px;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 15px 15px 68px 15px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
border-right: 1px solid #ededed;
|
||||||
|
|
||||||
|
.danger-zone {
|
||||||
|
border-top: 1px solid #ededed;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 15px;
|
||||||
|
position: absolute;
|
||||||
|
border-top: 1px solid #ededed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -623,6 +728,12 @@ footer {
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-flex {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.logo-wrapper {
|
.logo-wrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -681,4 +792,19 @@ footer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
.sidebar {
|
||||||
|
background-color: $dark-header-bg;
|
||||||
|
border-right-color: $dark-border-color;
|
||||||
|
|
||||||
|
.danger-zone {
|
||||||
|
border-top-color: $dark-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
border-top-color: $dark-border-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -18,6 +18,8 @@ import MonitorHistory from "./components/settings/MonitorHistory.vue";
|
||||||
import Security from "./components/settings/Security.vue";
|
import Security from "./components/settings/Security.vue";
|
||||||
import Backup from "./components/settings/Backup.vue";
|
import Backup from "./components/settings/Backup.vue";
|
||||||
import About from "./components/settings/About.vue";
|
import About from "./components/settings/About.vue";
|
||||||
|
import ManageStatusPage from "./pages/ManageStatusPage.vue";
|
||||||
|
import AddStatusPage from "./pages/AddStatusPage.vue";
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
|
@ -70,7 +72,6 @@ const routes = [
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "general",
|
path: "general",
|
||||||
alias: "",
|
|
||||||
component: General,
|
component: General,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -99,6 +100,14 @@ const routes = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/manage-status-page",
|
||||||
|
component: ManageStatusPage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/add-status-page",
|
||||||
|
component: AddStatusPage,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -115,6 +124,10 @@ const routes = [
|
||||||
path: "/status",
|
path: "/status",
|
||||||
component: StatusPage,
|
component: StatusPage,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/status/:slug",
|
||||||
|
component: StatusPage,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
|
|
|
@ -51,7 +51,19 @@ export function timezoneList() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setPageLocale() {
|
export function setPageLocale() {
|
||||||
const html = document.documentElement
|
const html = document.documentElement;
|
||||||
html.setAttribute('lang', currentLocale() )
|
html.setAttribute("lang", currentLocale() );
|
||||||
html.setAttribute('dir', localeDirection() )
|
html.setAttribute("dir", localeDirection() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mainly used for dev, because the backend and the frontend are in different ports.
|
||||||
|
*/
|
||||||
|
export function getResBaseURL() {
|
||||||
|
const env = process.env.NODE_ENV;
|
||||||
|
if (env === "development" || localStorage.dev === "dev") {
|
||||||
|
return location.protocol + "//" + location.hostname + ":3001";
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue