mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-13 23:17:00 +08:00
Compare commits
313 Commits
1.19.0-bet
...
1.20.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
e631db89b8 | ||
|
d39508a007 | ||
|
b0673ba9ce | ||
|
2a6d98ff01 | ||
|
3819266fa8 | ||
|
d0ac3fc207 | ||
|
2b1cb66ff7 | ||
|
99d4b8ba50 | ||
|
e1021ba38a | ||
|
c2ca60aaa2 | ||
|
30fb5f0b7b | ||
|
a8af763f23 | ||
|
47dd7ef432 | ||
|
3bc9c19e7f | ||
|
c1461fd01f | ||
|
1aaf251840 | ||
|
3208d98738 | ||
|
fef09d3abd | ||
|
1a601c9377 | ||
|
15ec8db48c | ||
|
89465e6768 | ||
|
683f446cf5 | ||
|
a8f0f1d872 | ||
|
f82d7b4007 | ||
|
806eb799c1 | ||
|
c699868bb9 | ||
|
95c934e08b | ||
|
348d0170fa | ||
|
ce82ad1c12 | ||
|
4fb43034cd | ||
|
18ae6fa6c1 | ||
|
664da4a317 | ||
|
fca0198d35 | ||
|
6828d337ae | ||
|
ddce8f0cb0 | ||
|
1dc2546a39 | ||
|
98f5bc51a8 | ||
|
82f875beca | ||
|
50573e6c89 | ||
|
e5ca67d062 | ||
|
54e63f3e25 | ||
|
d99d37898e | ||
|
dcda520d59 | ||
|
8816be24d8 | ||
|
e3828f09a3 | ||
|
5050ebc249 | ||
|
82f33f4445 | ||
|
a9b7bbcd9e | ||
|
edd5592dca | ||
|
e3246a2705 | ||
|
e1e6227245 | ||
|
b0e1bb4057 | ||
|
2a86b43d69 | ||
|
1dabbd6442 | ||
|
9cc3bd0de4 | ||
|
c4c720027c | ||
|
3eab6e8238 | ||
|
e637fa4e40 | ||
|
83e0401dd8 | ||
|
aab04f6644 | ||
|
2408b1bffa | ||
|
417efd9711 | ||
|
bf5ac3fc19 | ||
|
434bff6714 | ||
|
1d64b0c11b | ||
|
f125534829 | ||
|
ea83af3404 | ||
|
b05c620ec2 | ||
|
9c4b03aee2 | ||
|
912686a299 | ||
|
ae0ef79060 | ||
|
a2045b59bb | ||
|
8ade7120ff | ||
|
e9044ae956 | ||
|
0c86a4d4e7 | ||
|
5683896910 | ||
|
b288d71535 | ||
|
861ddc6117 | ||
|
1197f881a1 | ||
|
211cbd4687 | ||
|
dd6a76c4cc | ||
|
fa23e7ad19 | ||
|
6ccf741bc4 | ||
|
0a58069742 | ||
|
316599210d | ||
|
2b57b3e863 | ||
|
6cd6a2edf0 | ||
|
86bcb85e9b | ||
|
6961b1bdd2 | ||
|
54d4c4d3f7 | ||
|
c47b6c5995 | ||
|
7ef404ccc1 | ||
|
a5ff27da7a | ||
|
7bb12a7e00 | ||
|
27585d0812 | ||
|
e675316635 | ||
|
b073ec2287 | ||
|
31f45dcfc9 | ||
|
49ac71e25c | ||
|
8128c8081b | ||
|
e99652c5a2 | ||
|
ceb7d48118 | ||
|
bfa32f6b07 | ||
|
ae3a543b3b | ||
|
1a9b013fc2 | ||
|
1326761a8a | ||
|
e48a987b9c | ||
|
712a3c29d4 | ||
|
e9497ac1ab | ||
|
6437ef198f | ||
|
973d5692d0 | ||
|
468cb004d6 | ||
|
f7d41a30fa | ||
|
0ef686ac2f | ||
|
3b5893ea60 | ||
|
21cd4d64c3 | ||
|
db757123ba | ||
|
4dcf31621e | ||
|
9c1ba97e7d | ||
|
e9564619f1 | ||
|
8433bceb32 | ||
|
98d001b38b | ||
|
0ed3dd5e4f | ||
|
d9f12a6376 | ||
|
56ba133a1f | ||
|
ec30147a7f | ||
|
2bc165379a | ||
|
2172112144 | ||
|
ecd661c801 | ||
|
8fab7112a1 | ||
|
cc4ed308b0 | ||
|
362280af14 | ||
|
21b418230c | ||
|
636fc8fcfc | ||
|
1c05ba09dc | ||
|
1565da87cf | ||
|
890e3abf58 | ||
|
6e50784b6b | ||
|
33355c51b7 | ||
|
5f5c2d7c46 | ||
|
71f4ab0aa6 | ||
|
24d1dd4c34 | ||
|
c00abac834 | ||
|
439f963749 | ||
|
f15c6470af | ||
|
80f2d6e2a7 | ||
|
852a088529 | ||
|
6bc0bd84af | ||
|
32f7a0084a | ||
|
f8658d6160 | ||
|
dd82f36da3 | ||
|
774d754b21 | ||
|
d596f8f7eb | ||
|
23a525e36a | ||
|
221d1d40f5 | ||
|
60ec87941e | ||
|
e8e4361e09 | ||
|
d6c91869af | ||
|
5d6770c0db | ||
|
7a13b959a3 | ||
|
675806829c | ||
|
21c1921867 | ||
|
e490ec6d29 | ||
|
7ad4392529 | ||
|
f3d3e064f8 | ||
|
80c91b8234 | ||
|
dc8289df12 | ||
|
caff9ca736 | ||
|
c7eb72e73b | ||
|
fc5ec5f492 | ||
|
40ebc2df79 | ||
|
abf5e435fe | ||
|
8a372201f1 | ||
|
8ec240fe19 | ||
|
5362aab0e5 | ||
|
bc7271b99c | ||
|
4ebf5a5f07 | ||
|
fbceefec36 | ||
|
0b959514f8 | ||
|
4c5e2ea237 | ||
|
7d92351568 | ||
|
494c53971c | ||
|
fc1914bccd | ||
|
4239cf4255 | ||
|
c196c34840 | ||
|
554402b484 | ||
|
b049e4e1b4 | ||
|
90a2668272 | ||
|
49b5de7d40 | ||
|
69e1880cd3 | ||
|
610b6248aa | ||
|
e591647b60 | ||
|
da99833d4c | ||
|
4bf23fdd1a | ||
|
f99a64da67 | ||
|
2e022789f6 | ||
|
73835f3328 | ||
|
4819112e25 | ||
|
2d3fd738e4 | ||
|
edd8fe2e22 | ||
|
204792dd2d | ||
|
942b55ca03 | ||
|
b8e8c1b9db | ||
|
0cead83705 | ||
|
7b0093b8b3 | ||
|
cd7e362b81 | ||
|
a8af2a418e | ||
|
39ac9b887e | ||
|
28c3291020 | ||
|
50711391d1 | ||
|
e88e10cc8e | ||
|
27146ffeef | ||
|
41a9f2ff8a | ||
|
cd7a6e4019 | ||
|
8bb064c6fa | ||
|
1006fbd873 | ||
|
5554432b31 | ||
|
d111db0321 | ||
|
4147a4c404 | ||
|
8c684e9293 | ||
|
f025de6eaf | ||
|
7f394d0630 | ||
|
9fe9e235ca | ||
|
50b84f5f45 | ||
|
c60b741406 | ||
|
f6ea1fe9a5 | ||
|
b7e3ec2372 | ||
|
625fd7c2aa | ||
|
aec80b53d5 | ||
|
06852bbf0d | ||
|
056d957c1e | ||
|
e12225e595 | ||
|
1b6c587cc9 | ||
|
4a1db336df | ||
|
9e9c5cd1d2 | ||
|
1e689d99b4 | ||
|
14fffcf06b | ||
|
6962e056ce | ||
|
b7a898326e | ||
|
a89be0e6d4 | ||
|
b3ac7c3d43 | ||
|
c79b2913a2 | ||
|
b58b83541b | ||
|
df4f91c20d | ||
|
fc6b040a4e | ||
|
9838f36b50 | ||
|
a60072adbc | ||
|
e7aeb6f6bf | ||
|
06e570c52d | ||
|
890b8f8333 | ||
|
df21f7da76 | ||
|
3ea6711053 | ||
|
20c37a70f7 | ||
|
b75db27658 | ||
|
765d8e1297 | ||
|
9dc2cc1f0d | ||
|
2532becf61 | ||
|
6154776b34 | ||
|
7e6b92203d | ||
|
1da00d19fd | ||
|
da4bdab4f6 | ||
|
86ab97ef56 | ||
|
345b0c1829 | ||
|
2ac87fcea7 | ||
|
4862bec965 | ||
|
aa784fb3b2 | ||
|
466b403a96 | ||
|
f32441e2f6 | ||
|
39987ba9ac | ||
|
3b87209e26 | ||
|
e6dc0a0293 | ||
|
5c5a339a36 | ||
|
3040bd41d9 | ||
|
3b58fd3b3c | ||
|
bc86f8bb5f | ||
|
ab5f6dc82c | ||
|
5176fd02c1 | ||
|
02b5cae577 | ||
|
54aa7d5dca | ||
|
4cd5b5563f | ||
|
f1c30204b6 | ||
|
9da28fbbc7 | ||
|
851a04b082 | ||
|
68bc7ac421 | ||
|
73bfdb9ef9 | ||
|
e478084ff9 | ||
|
2dff7dd380 | ||
|
9bfa43100b | ||
|
ad5e1957b1 | ||
|
cc68ebca39 | ||
|
aa27d976c2 | ||
|
ecbc0f0477 | ||
|
f8c7da7995 | ||
|
f3660a0cec | ||
|
92caec95fe | ||
|
2c3abdc146 | ||
|
0e30843a75 | ||
|
2103edb604 | ||
|
b059a36e66 | ||
|
4339ca7eb5 | ||
|
7313aa6563 | ||
|
c7871427c3 | ||
|
6b47ad07ca | ||
|
a42f7416b5 | ||
|
7aa3f6c559 | ||
|
db4b2cd984 | ||
|
b4f0f8bca5 | ||
|
b382064384 | ||
|
742b1337be | ||
|
c3d655afb4 | ||
|
b5f04573f2 | ||
|
a54e58b4d6 | ||
|
219b00f660 |
@@ -31,6 +31,9 @@ tsconfig.json
|
||||
/tmp
|
||||
/babel.config.js
|
||||
/ecosystem.config.js
|
||||
/extra/healthcheck.exe
|
||||
/extra/healthcheck
|
||||
|
||||
|
||||
### .gitignore content (commented rules are duplicated)
|
||||
|
||||
|
@@ -19,3 +19,6 @@ indent_size = 2
|
||||
|
||||
[*.vue]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
|
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -16,7 +16,6 @@ Please delete any options that are not relevant.
|
||||
- User interface (UI)
|
||||
- New feature (non-breaking change which adds functionality)
|
||||
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- Translation update
|
||||
- Other
|
||||
- This change requires a documentation update
|
||||
|
||||
|
18
.github/workflows/auto-test.yml
vendored
18
.github/workflows/auto-test.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
node: [ 14, 16, 17, 18 ]
|
||||
node: [ 14, 16, 18, 19 ]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
@@ -66,3 +66,19 @@ jobs:
|
||||
- run: npm install
|
||||
- run: npm run build
|
||||
- run: npm run cy:test
|
||||
|
||||
frontend-unit-tests:
|
||||
needs: [ check-linters ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: git config --global core.autocrlf false # Mainly for Windows
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 14
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 14
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- run: npm run build
|
||||
- run: npm run cy:run:unit
|
||||
|
6
.github/workflows/stale-bot.yml
vendored
6
.github/workflows/stale-bot.yml
vendored
@@ -12,13 +12,11 @@ jobs:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.'
|
||||
stale-pr-message: 'We are clearing up our old Pull Requests and yours has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.'
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 2 days with no activity.'
|
||||
close-pr-message: 'This PR was closed because it has been stalled for 2 days with no activity.'
|
||||
days-before-stale: 90
|
||||
days-before-close: 2
|
||||
days-before-pr-stale: 999999999
|
||||
days-before-pr-close: 1
|
||||
exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,feature-request'
|
||||
exempt-pr-labels: 'awaiting-approval,work-in-progress,enhancement,feature-request'
|
||||
exempt-issue-assignees: 'louislam'
|
||||
exempt-pr-assignees: 'louislam'
|
||||
operations-per-run: 200
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -16,3 +16,7 @@ dist-ssr
|
||||
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
|
||||
/extra/healthcheck.exe
|
||||
/extra/healthcheck
|
||||
/extra/healthcheck-armv7
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Project Info
|
||||
|
||||
First of all, thank you everyone who made pull requests for Uptime Kuma, I never thought GitHub Community can be that nice! And also because of this, I also never thought other people actually read my code and edit my code. It is not structured and commented so well, lol. Sorry about that.
|
||||
First of all, I want to thank everyone who made pull requests for Uptime Kuma. I never thought the GitHub Community would be so nice! Because of this, I also never thought that other people would actually read and edit my code. It is not very well structured or commented, sorry about that.
|
||||
|
||||
The project was created with vite.js (vue3). Then I created a subdirectory called "server" for server part. Both frontend and backend share the same package.json.
|
||||
|
||||
@@ -17,8 +17,11 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
|
||||
|
||||
## Directories
|
||||
|
||||
- config (dev config files)
|
||||
- data (App data)
|
||||
- db (Base database and migration scripts)
|
||||
- dist (Frontend build)
|
||||
- docker (Dockerfiles)
|
||||
- extra (Extra useful scripts)
|
||||
- public (Frontend resources for dev only)
|
||||
- server (Server source code)
|
||||
@@ -27,20 +30,23 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
|
||||
|
||||
## Can I create a pull request for Uptime Kuma?
|
||||
|
||||
Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create an empty draft pull request or open an issue, so we can discuss first**. Especially for a large pull request or you don't know it will be merged or not.
|
||||
Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**. Especially for a large pull request or you don't know it will be merged or not.
|
||||
|
||||
Here are some references:
|
||||
|
||||
✅ Usually Accept:
|
||||
- Bug/Security fix
|
||||
- Translations
|
||||
- Bug fix
|
||||
- Security fix
|
||||
- Adding notification providers
|
||||
- Adding new language files (You should go to https://weblate.kuma.pet for existing languages)
|
||||
- Adding new language keys: `$t("...")`
|
||||
|
||||
⚠️ Discussion First
|
||||
- Large pull requests
|
||||
- New features
|
||||
|
||||
❌ Won't Merge
|
||||
- A dedicated pr for translating existing languages (You can now translate on https://weblate.kuma.pet)
|
||||
- Do not pass auto test
|
||||
- Any breaking changes
|
||||
- Duplicated pull request
|
||||
@@ -48,8 +54,13 @@ Here are some references:
|
||||
- UI/UX is not close to Uptime Kuma
|
||||
- Existing logic is completely modified or deleted for no reason
|
||||
- A function that is completely out of scope
|
||||
- Convert existing code into other programming languages
|
||||
- Unnecessary large code changes (Hard to review, causes code conflicts to other pull requests)
|
||||
|
||||
The above cases cannot cover all situations.
|
||||
|
||||
I (@louislam) have the final say. If your pull request does not meet my expectations, I will reject it, no matter how much time you spend on it. Therefore, it is essential to have a discussion beforehand.
|
||||
|
||||
I will mark your pull request in the [milestones](https://github.com/louislam/uptime-kuma/milestones), if I am plan to review and merge it.
|
||||
|
||||
Also, please don't rush or ask for ETA, because I have to understand the pull request, make sure it is no breaking changes and stick to my vision of this project, especially for large pull requests.
|
||||
@@ -72,13 +83,13 @@ Before deep into coding, discussion first is preferred. Creating an empty pull r
|
||||
|
||||
## Project Styles
|
||||
|
||||
I personally do not like something need to learn so much and need to config so much before you can finally start the app.
|
||||
I personally do not like something that requires so many configurations before you can finally start the app. I hope Uptime Kuma installation could be as easy as like installing a mobile app.
|
||||
|
||||
- Easy to install for non-Docker users, no native build dependency is needed (at least for x86_64), no extra config, no extra effort to get it run
|
||||
- Easy to install for non-Docker users, no native build dependency is needed (for x86_64/armv7/arm64), no extra config, no extra effort required to get it running
|
||||
- Single container for Docker users, no very complex docker-compose file. Just map the volume and expose the port, then good to go
|
||||
- Settings should be configurable in the frontend. Environment variable is not encouraged, unless it is related to startup such as `DATA_DIR`.
|
||||
- Settings should be configurable in the frontend. Environment variable is not encouraged, unless it is related to startup such as `DATA_DIR`
|
||||
- Easy to use
|
||||
- The web UI styling should be consistent and nice.
|
||||
- The web UI styling should be consistent and nice
|
||||
|
||||
## Coding Styles
|
||||
|
||||
@@ -87,7 +98,7 @@ I personally do not like something need to learn so much and need to config so m
|
||||
- Follow ESLint
|
||||
- Methods and functions should be documented with JSDoc
|
||||
|
||||
## Name convention
|
||||
## Name Conventions
|
||||
|
||||
- Javascript/Typescript: camelCaseType
|
||||
- SQLite: snake_case (Underscore)
|
||||
@@ -101,7 +112,7 @@ I personally do not like something need to learn so much and need to config so m
|
||||
- IDE that supports ESLint and EditorConfig (I am using IntelliJ IDEA)
|
||||
- A SQLite GUI tool (SQLite Expert Personal is suggested)
|
||||
|
||||
## Install dependencies
|
||||
## Install Dependencies for Development
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
@@ -119,6 +130,12 @@ Port `3000` and port `3001` will be used.
|
||||
npm run dev
|
||||
```
|
||||
|
||||
But sometimes, you would like to keep restart the server, but not the frontend, you can run these command in two terminals:
|
||||
```
|
||||
npm run start-frontend-dev
|
||||
npm run start-server-dev
|
||||
```
|
||||
|
||||
## Backend Server
|
||||
|
||||
It binds to `0.0.0.0:3001` by default.
|
||||
@@ -134,12 +151,15 @@ express.js is used for:
|
||||
|
||||
### Structure in /server/
|
||||
|
||||
- jobs/ (Jobs that are running in another process)
|
||||
- model/ (Object model, auto mapping to the database table name)
|
||||
- modules/ (Modified 3rd-party modules)
|
||||
- monitor_types (Monitor Types)
|
||||
- notification-providers/ (individual notification logic)
|
||||
- routers/ (Express Routers)
|
||||
- socket-handler (Socket.io Handlers)
|
||||
- server.js (Server entry point and main logic)
|
||||
- server.js (Server entry point)
|
||||
- uptime-kuma-server.js (UptimeKumaServer class, main logic should be here, but some still in `server.js`)
|
||||
|
||||
## Frontend Dev Server
|
||||
|
||||
@@ -172,15 +192,11 @@ The data and socket logic are in `src/mixins/socket.js`.
|
||||
|
||||
## Unit Test
|
||||
|
||||
It is an end-to-end testing. It is using Jest and Puppeteer.
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm test
|
||||
```
|
||||
|
||||
By default, the Chromium window will be shown up during the test. Specifying `HEADLESS_TEST=1` for terminal environments.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Both frontend and backend share the same package.json. However, the frontend dependencies are eventually not used in the production environment, because it is usually also baked into dist files. So:
|
||||
@@ -194,18 +210,12 @@ Both frontend and backend share the same package.json. However, the frontend dep
|
||||
|
||||
### Update Dependencies
|
||||
|
||||
Install `ncu`
|
||||
https://github.com/raineorshine/npm-check-updates
|
||||
|
||||
```bash
|
||||
ncu -u -t patch
|
||||
npm install
|
||||
```
|
||||
|
||||
Since previously updating Vite 2.5.10 to 2.6.0 broke the application completely, from now on, it should update patch release version only.
|
||||
|
||||
Patch release = the third digit ([Semantic Versioning](https://semver.org/))
|
||||
|
||||
If for maybe security reasons, a library must be updated. Then you must need to check if there are any breaking changes.
|
||||
|
||||
## Translations
|
||||
|
||||
Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
|
||||
|
38
README.md
38
README.md
@@ -1,15 +1,17 @@
|
||||
# Uptime Kuma
|
||||
|
||||
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Open%20Collective%20Backers&color=brightgreen" /></a>
|
||||
[](https://github.com/sponsors/louislam)
|
||||
[](https://github.com/sponsors/louislam) <a href="https://weblate.kuma.pet/engage/uptime-kuma/">
|
||||
<img src="https://weblate.kuma.pet/widgets/uptime-kuma/-/svg-badge.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
<div align="center" width="100%">
|
||||
<img src="./public/icon.svg" width="128" alt="" />
|
||||
</div>
|
||||
|
||||
It is a self-hosted monitoring tool like "Uptime Robot".
|
||||
Uptime Kuma is an easy-to-use self-hosted monitoring tool.
|
||||
|
||||
<img src="https://uptime.kuma.pet/img/dark.jpg" width="700" alt="" />
|
||||
<img src="https://user-images.githubusercontent.com/1336778/212262296-e6205815-ad62-488c-83ec-a5b0d0689f7c.jpg" width="700" alt="" />
|
||||
|
||||
## 🥔 Live Demo
|
||||
|
||||
@@ -22,17 +24,17 @@ It is a temporary live demo, all data will be deleted after 10 minutes. Use the
|
||||
|
||||
## ⭐ Features
|
||||
|
||||
* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server / Docker Containers.
|
||||
* Fancy, Reactive, Fast UI/UX.
|
||||
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications).
|
||||
* 20 second intervals.
|
||||
* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/languages)
|
||||
* Multiple Status Pages
|
||||
* Map Status Page to Domain
|
||||
* Ping Chart
|
||||
* Certificate Info
|
||||
* Proxy Support
|
||||
* 2FA available
|
||||
* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server / Docker Containers
|
||||
* Fancy, Reactive, Fast UI/UX
|
||||
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications)
|
||||
* 20 second intervals
|
||||
* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/lang)
|
||||
* Multiple status pages
|
||||
* Map status pages to specific domains
|
||||
* Ping chart
|
||||
* Certificate info
|
||||
* Proxy support
|
||||
* 2FA support
|
||||
|
||||
## 🔧 How to Install
|
||||
|
||||
@@ -44,14 +46,14 @@ docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name upti
|
||||
|
||||
⚠️ Please use a **local volume** only. Other types such as NFS are not supported.
|
||||
|
||||
Browse to http://localhost:3001 after starting.
|
||||
Uptime Kuma is now running on http://localhost:3001
|
||||
|
||||
### 💪🏻 Non-Docker
|
||||
|
||||
Required Tools:
|
||||
- [Node.js](https://nodejs.org/en/download/) >= 14
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
- [pm2](https://pm2.keymetrics.io/) - For run in background
|
||||
- [pm2](https://pm2.keymetrics.io/) - For running Uptime Kuma in the background
|
||||
|
||||
```bash
|
||||
# Update your npm to the latest version
|
||||
@@ -73,7 +75,7 @@ pm2 start server/server.js --name uptime-kuma
|
||||
|
||||
|
||||
```
|
||||
Browse to http://localhost:3001 after starting.
|
||||
Uptime Kuma is now running on http://localhost:3001
|
||||
|
||||
More useful PM2 Commands
|
||||
|
||||
@@ -171,7 +173,7 @@ Check out the latest beta release here: https://github.com/louislam/uptime-kuma/
|
||||
If you want to report a bug or request a new feature, feel free to open a [new issue](https://github.com/louislam/uptime-kuma/issues).
|
||||
|
||||
### Translations
|
||||
If you want to translate Uptime Kuma into your language, please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
|
||||
If you want to translate Uptime Kuma into your language, please visit [Weblate Readme](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
|
||||
|
||||
Feel free to correct my grammar in this README, source code, or wiki, as my mother language is not English and my grammar is not that great.
|
||||
|
||||
|
@@ -2,9 +2,9 @@
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report security issues to uptime@kuma.pet.
|
||||
Please report security issues to https://github.com/louislam/uptime-kuma/security/advisories/new.
|
||||
|
||||
Do not use the issue tracker or discuss it in the public as it will cause more damage.
|
||||
Do not use the public issue tracker or discuss it in the public as it will cause more damage.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
|
10
config/cypress.frontend.config.js
Normal file
10
config/cypress.frontend.config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const { defineConfig } = require("cypress");
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
supportFile: false,
|
||||
specPattern: [
|
||||
"test/cypress/unit/**/*.js"
|
||||
],
|
||||
}
|
||||
});
|
5
db/patch-add-gamedig-monitor.sql
Normal file
5
db/patch-add-gamedig-monitor.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD game VARCHAR(255);
|
||||
COMMIT
|
5
db/patch-ping-packet-size.sql
Normal file
5
db/patch-ping-packet-size.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE monitor
|
||||
ADD packet_size INTEGER DEFAULT 56 NOT NULL;
|
||||
COMMIT;
|
@@ -3,6 +3,6 @@ FROM node:16-alpine3.12
|
||||
WORKDIR /app
|
||||
|
||||
# Install apprise, iputils for non-root ping, setpriv
|
||||
RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \
|
||||
pip3 --no-cache-dir install apprise==1.2.0 && \
|
||||
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 git && \
|
||||
pip3 --no-cache-dir install apprise==1.2.1 && \
|
||||
rm -rf /root/.cache
|
||||
|
16
docker/builder-go.dockerfile
Normal file
16
docker/builder-go.dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
############################################
|
||||
# Build in Golang
|
||||
# Run npm run build-healthcheck-armv7 in the host first, another it will be super slow where it is building the armv7 healthcheck
|
||||
############################################
|
||||
FROM golang:1.19-buster
|
||||
WORKDIR /app
|
||||
ARG TARGETPLATFORM
|
||||
COPY ./extra/ ./extra/
|
||||
|
||||
# Compile healthcheck.go
|
||||
RUN apt update && \
|
||||
apt --yes --no-install-recommends install curl && \
|
||||
curl -sL https://deb.nodesource.com/setup_18.x | bash && \
|
||||
apt --yes --no-install-recommends install nodejs && \
|
||||
node ./extra/build-healthcheck.js $TARGETPLATFORM && \
|
||||
apt --yes remove nodejs
|
@@ -10,8 +10,8 @@ WORKDIR /app
|
||||
# Stupid python3 and python3-pip actually install a lot of useless things into Debian, specify --no-install-recommends to skip them, make the base even smaller than alpine!
|
||||
RUN apt update && \
|
||||
apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
|
||||
sqlite3 iputils-ping util-linux dumb-init && \
|
||||
pip3 --no-cache-dir install apprise==1.2.0 && \
|
||||
sqlite3 iputils-ping util-linux dumb-init git && \
|
||||
pip3 --no-cache-dir install apprise==1.2.1 && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
apt --yes autoremove
|
||||
|
||||
|
@@ -1,30 +1,50 @@
|
||||
############################################
|
||||
# Build in Golang
|
||||
# Run npm run build-healthcheck-armv7 in the host first, another it will be super slow where it is building the armv7 healthcheck
|
||||
# Check file: builder-go.dockerfile
|
||||
############################################
|
||||
FROM louislam/uptime-kuma:builder-go AS build_healthcheck
|
||||
|
||||
############################################
|
||||
# Build in Node.js
|
||||
############################################
|
||||
FROM louislam/uptime-kuma:base-debian AS build
|
||||
WORKDIR /app
|
||||
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
|
||||
|
||||
COPY .npmrc .npmrc
|
||||
COPY package.json package.json
|
||||
COPY package-lock.json package-lock.json
|
||||
RUN npm ci --omit=dev
|
||||
COPY . .
|
||||
RUN npm ci --production && \
|
||||
chmod +x /app/extra/entrypoint.sh
|
||||
|
||||
COPY --from=build_healthcheck /app/extra/healthcheck /app/extra/healthcheck
|
||||
RUN chmod +x /app/extra/entrypoint.sh
|
||||
|
||||
############################################
|
||||
# ⭐ Main Image
|
||||
############################################
|
||||
FROM louislam/uptime-kuma:base-debian AS release
|
||||
WORKDIR /app
|
||||
|
||||
# Copy app files from build layer
|
||||
COPY --from=build /app /app
|
||||
|
||||
|
||||
EXPOSE 3001
|
||||
VOLUME ["/app/data"]
|
||||
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js
|
||||
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD extra/healthcheck
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"]
|
||||
CMD ["node", "server/server.js"]
|
||||
|
||||
|
||||
############################################
|
||||
# Mark as Nightly
|
||||
############################################
|
||||
FROM release AS nightly
|
||||
RUN npm run mark-as-nightly
|
||||
|
||||
############################################
|
||||
# Build an image for testing pr
|
||||
############################################
|
||||
FROM louislam/uptime-kuma:base-debian AS pr-test
|
||||
|
||||
WORKDIR /app
|
||||
@@ -54,8 +74,9 @@ VOLUME ["/app/data"]
|
||||
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js
|
||||
CMD ["npm", "run", "start-pr-test"]
|
||||
|
||||
|
||||
############################################
|
||||
# Upload the artifact to Github
|
||||
############################################
|
||||
FROM louislam/uptime-kuma:base-debian AS upload-artifact
|
||||
WORKDIR /
|
||||
RUN apt update && \
|
||||
|
@@ -3,10 +3,12 @@ WORKDIR /app
|
||||
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
|
||||
|
||||
COPY .npmrc .npmrc
|
||||
COPY package.json package.json
|
||||
COPY package-lock.json package-lock.json
|
||||
RUN npm ci --omit=dev
|
||||
COPY . .
|
||||
RUN npm ci --production && \
|
||||
chmod +x /app/extra/entrypoint.sh
|
||||
|
||||
RUN chmod +x /app/extra/entrypoint.sh
|
||||
|
||||
FROM louislam/uptime-kuma:base-alpine AS release
|
||||
WORKDIR /app
|
||||
|
@@ -32,6 +32,10 @@ if (! exists) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit updated files
|
||||
* @param {string} version Version to update to
|
||||
*/
|
||||
function commit(version) {
|
||||
let msg = "Update to " + version;
|
||||
|
||||
@@ -47,6 +51,10 @@ function commit(version) {
|
||||
console.log(res.stdout.toString().trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag with the specified version
|
||||
* @param {string} version Tag to create
|
||||
*/
|
||||
function tag(version) {
|
||||
let res = childProcess.spawnSync("git", [ "tag", version ]);
|
||||
console.log(res.stdout.toString().trim());
|
||||
@@ -55,6 +63,11 @@ function tag(version) {
|
||||
console.log(res.stdout.toString().trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tag exists for the specified version
|
||||
* @param {string} version Version to check
|
||||
* @returns {boolean} Does the tag already exist
|
||||
*/
|
||||
function tagExists(version) {
|
||||
if (! version) {
|
||||
throw new Error("invalid version");
|
||||
|
27
extra/build-healthcheck.js
Normal file
27
extra/build-healthcheck.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const childProcess = require("child_process");
|
||||
const fs = require("fs");
|
||||
const platform = process.argv[2];
|
||||
|
||||
if (!platform) {
|
||||
console.error("No platform??");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (platform === "linux/arm/v7") {
|
||||
console.log("Arch: armv7");
|
||||
if (fs.existsSync("./extra/healthcheck-armv7")) {
|
||||
fs.renameSync("./extra/healthcheck-armv7", "./extra/healthcheck");
|
||||
console.log("Already built in the host, skip.");
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log("prebuilt not found, it will be slow! You should execute `npm run build-healthcheck-armv7` before build.");
|
||||
}
|
||||
} else {
|
||||
if (fs.existsSync("./extra/healthcheck-armv7")) {
|
||||
fs.rmSync("./extra/healthcheck-armv7");
|
||||
}
|
||||
}
|
||||
|
||||
const output = childProcess.execSync("go build -x -o ./extra/healthcheck ./extra/healthcheck.go").toString("utf8");
|
||||
console.log(output);
|
||||
|
@@ -25,6 +25,10 @@ if (platform === "linux/amd64") {
|
||||
const file = fs.createWriteStream("cloudflared.deb");
|
||||
get("https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-" + arch + ".deb");
|
||||
|
||||
/**
|
||||
* Download specified file
|
||||
* @param {string} url URL to request
|
||||
*/
|
||||
function get(url) {
|
||||
http.get(url, function (res) {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
|
90
extra/healthcheck.go
Normal file
90
extra/healthcheck.go
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* If changed, have to run `npm run build-docker-builder-go`.
|
||||
* This script should be run after a period of time (180s), because the server may need some time to prepare.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isFreeBSD := runtime.GOOS == "freebsd"
|
||||
|
||||
// Is K8S + uptime-kuma as the container name
|
||||
// See #2083
|
||||
isK8s := strings.HasPrefix(os.Getenv("UPTIME_KUMA_PORT"), "tcp://")
|
||||
|
||||
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
client := http.Client{
|
||||
Timeout: 28 * time.Second,
|
||||
}
|
||||
|
||||
sslKey := os.Getenv("UPTIME_KUMA_SSL_KEY")
|
||||
if len(sslKey) == 0 {
|
||||
sslKey = os.Getenv("SSL_KEY")
|
||||
}
|
||||
|
||||
sslCert := os.Getenv("UPTIME_KUMA_SSL_CERT")
|
||||
if len(sslCert) == 0 {
|
||||
sslCert = os.Getenv("SSL_CERT")
|
||||
}
|
||||
|
||||
hostname := os.Getenv("UPTIME_KUMA_HOST")
|
||||
if len(hostname) == 0 && !isFreeBSD {
|
||||
hostname = os.Getenv("HOST")
|
||||
}
|
||||
if len(hostname) == 0 {
|
||||
hostname = "127.0.0.1"
|
||||
}
|
||||
|
||||
port := ""
|
||||
// UPTIME_KUMA_PORT is override by K8S unexpectedly,
|
||||
if !isK8s {
|
||||
port = os.Getenv("UPTIME_KUMA_PORT")
|
||||
}
|
||||
if len(port) == 0 {
|
||||
port = os.Getenv("PORT")
|
||||
}
|
||||
if len(port) == 0 {
|
||||
port = "3001"
|
||||
}
|
||||
|
||||
protocol := ""
|
||||
if len(sslKey) != 0 && len(sslCert) != 0 {
|
||||
protocol = "https"
|
||||
} else {
|
||||
protocol = "http"
|
||||
}
|
||||
|
||||
url := protocol + "://" + hostname + ":" + port
|
||||
|
||||
log.Println("Checking " + url)
|
||||
resp, err := client.Get(url)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
_, err = ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
log.Printf("Health Check OK [Res Code: %d]\n", resp.StatusCode)
|
||||
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* ⚠️ Deprecated: Changed to healthcheck.go, it will be deleted in the future.
|
||||
* This script should be run after a period of time (180s), because the server may need some time to prepare.
|
||||
*/
|
||||
const { FBSD } = require("../server/util-server");
|
||||
@@ -18,17 +19,17 @@ if (sslKey && sslCert) {
|
||||
|
||||
// If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available and the unspecified IPv4 address (0.0.0.0) otherwise.
|
||||
// Dual-stack support for (::)
|
||||
let hostname = process.env.UPTIME_KUMA_HOST;
|
||||
let hostname = process.env.UPTIME_KUMA_SERVICE_HOST || process.env.UPTIME_KUMA_HOST || "::";
|
||||
|
||||
// Also read HOST if not *BSD, as HOST is a system environment variable in FreeBSD
|
||||
if (!hostname && !FBSD) {
|
||||
hostname = process.env.HOST;
|
||||
}
|
||||
|
||||
const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || 3001);
|
||||
const port = parseInt(process.env.UPTIME_KUMA_SERVICE_PORT || process.env.UPTIME_KUMA_PORT || process.env.PORT || 3001);
|
||||
|
||||
let options = {
|
||||
host: hostname || "127.0.0.1",
|
||||
host: hostname,
|
||||
port: port,
|
||||
timeout: 28 * 1000,
|
||||
};
|
||||
|
@@ -1,11 +1,12 @@
|
||||
const pkg = require("../package.json");
|
||||
const fs = require("fs");
|
||||
const util = require("../src/util");
|
||||
const dayjs = require("dayjs");
|
||||
|
||||
util.polyfill();
|
||||
|
||||
const oldVersion = pkg.version;
|
||||
const newVersion = oldVersion + "-nightly-" + util.genSecret(8);
|
||||
const newVersion = oldVersion + "-nightly-" + dayjs().format("YYYYMMDDHHmmss");
|
||||
|
||||
console.log("Old Version: " + oldVersion);
|
||||
console.log("New Version: " + newVersion);
|
||||
|
@@ -43,6 +43,11 @@ const main = async () => {
|
||||
console.log("Finished.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Ask question of user
|
||||
* @param {string} question Question to ask
|
||||
* @returns {Promise<string>} Users response
|
||||
*/
|
||||
function question(question) {
|
||||
return new Promise((resolve) => {
|
||||
rl.question(question, (answer) => {
|
||||
|
@@ -53,6 +53,11 @@ const main = async () => {
|
||||
console.log("Finished.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Ask question of user
|
||||
* @param {string} question Question to ask
|
||||
* @returns {Promise<string>} Users response
|
||||
*/
|
||||
function question(question) {
|
||||
return new Promise((resolve) => {
|
||||
rl.question(question, (answer) => {
|
||||
|
@@ -135,6 +135,11 @@ server.listen({
|
||||
udp: 5300
|
||||
});
|
||||
|
||||
/**
|
||||
* Get human readable request type from request code
|
||||
* @param {number} code Request code to translate
|
||||
* @returns {string} Human readable request type
|
||||
*/
|
||||
function type(code) {
|
||||
for (let name in Packet.TYPE) {
|
||||
if (Packet.TYPE[name] === code) {
|
||||
|
@@ -11,6 +11,7 @@ class SimpleMqttServer {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/** Start the MQTT server */
|
||||
start() {
|
||||
this.server.listen(this.port, () => {
|
||||
console.log("server started and listening on port ", this.port);
|
||||
|
@@ -36,10 +36,8 @@ if (! exists) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the version number in package.json and commits it to git.
|
||||
* @param {string} version - The new version number
|
||||
*
|
||||
* Generated by Trelent
|
||||
* Commit updated files
|
||||
* @param {string} version Version to update to
|
||||
*/
|
||||
function commit(version) {
|
||||
let msg = "Update to " + version;
|
||||
@@ -53,16 +51,19 @@ function commit(version) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag with the specified version
|
||||
* @param {string} version Tag to create
|
||||
*/
|
||||
function tag(version) {
|
||||
let res = childProcess.spawnSync("git", [ "tag", version ]);
|
||||
console.log(res.stdout.toString().trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given version is already tagged in the git repository.
|
||||
* @param {string} version - The version to check for.
|
||||
*
|
||||
* Generated by Trelent
|
||||
* Check if a tag exists for the specified version
|
||||
* @param {string} version Version to check
|
||||
* @returns {boolean} Does the tag already exist
|
||||
*/
|
||||
function tagExists(version) {
|
||||
if (! version) {
|
||||
|
@@ -10,6 +10,10 @@ if (!newVersion) {
|
||||
|
||||
updateWiki(newVersion);
|
||||
|
||||
/**
|
||||
* Update the wiki with new version number
|
||||
* @param {string} newVersion Version to update to
|
||||
*/
|
||||
function updateWiki(newVersion) {
|
||||
const wikiDir = "./tmp/wiki";
|
||||
const howToUpdateFilename = "./tmp/wiki/🆙-How-to-Update.md";
|
||||
@@ -39,6 +43,10 @@ function updateWiki(newVersion) {
|
||||
safeDelete(wikiDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a directory exists and then delete it
|
||||
* @param {string} dir Directory to delete
|
||||
*/
|
||||
function safeDelete(dir) {
|
||||
if (fs.existsSync(dir)) {
|
||||
fs.rm(dir, {
|
||||
|
5625
package-lock.json
generated
5625
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uptime-kuma",
|
||||
"version": "1.19.0-beta.1",
|
||||
"version": "1.20.0-beta.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -31,6 +31,7 @@
|
||||
"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-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-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --push",
|
||||
"build-docker-alpine": "node ./extra/env2arg.js 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:$VERSION-alpine --target release . --push",
|
||||
"build-docker-debian": "node ./extra/env2arg.js 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:$VERSION -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:$VERSION-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",
|
||||
@@ -38,7 +39,7 @@
|
||||
"build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
|
||||
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test --target pr-test . --push",
|
||||
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
|
||||
"setup": "git checkout 1.18.5 && npm ci --production && npm run download-dist",
|
||||
"setup": "git checkout 1.19.6 && npm ci --production && npm run download-dist",
|
||||
"download-dist": "node extra/download-dist.js",
|
||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||
"reset-password": "node extra/reset-password.js",
|
||||
@@ -60,10 +61,13 @@
|
||||
"start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev",
|
||||
"cy:test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --e2e",
|
||||
"cy:run": "npx cypress run --browser chrome --headless --config-file ./config/cypress.config.js",
|
||||
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\""
|
||||
"cy:run:unit": "npx cypress run --browser chrome --headless --config-file ./config/cypress.frontend.config.js",
|
||||
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\"",
|
||||
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "~1.7.3",
|
||||
"@louislam/ping": "~0.4.2-mod.1",
|
||||
"@louislam/sqlite3": "15.1.2",
|
||||
"args-parser": "~1.3.0",
|
||||
"axios": "~0.27.0",
|
||||
@@ -80,18 +84,21 @@
|
||||
"compare-versions": "~3.6.0",
|
||||
"compression": "~1.7.4",
|
||||
"dayjs": "~1.11.5",
|
||||
"dotenv": "~16.0.3",
|
||||
"express": "~4.17.3",
|
||||
"express-basic-auth": "~1.2.1",
|
||||
"express-static-gzip": "~2.1.7",
|
||||
"form-data": "~4.0.0",
|
||||
"gamedig": "^4.0.5",
|
||||
"http-graceful-shutdown": "~3.1.7",
|
||||
"http-proxy-agent": "~5.0.0",
|
||||
"https-proxy-agent": "~5.0.1",
|
||||
"iconv-lite": "~0.6.3",
|
||||
"jsesc": "~3.0.2",
|
||||
"jsonwebtoken": "~8.5.1",
|
||||
"jsonwebtoken": "~9.0.0",
|
||||
"jwt-decode": "~3.1.2",
|
||||
"limiter": "~2.1.0",
|
||||
"mongodb": "~4.13.0",
|
||||
"mqtt": "~4.3.7",
|
||||
"mssql": "~8.1.4",
|
||||
"mysql2": "~2.3.3",
|
||||
@@ -105,7 +112,8 @@
|
||||
"prom-client": "~13.2.0",
|
||||
"prometheus-api-metrics": "~3.2.1",
|
||||
"protobufjs": "~7.1.1",
|
||||
"redbean-node": "0.1.4",
|
||||
"redbean-node": "~0.2.0",
|
||||
"redis": "~4.5.1",
|
||||
"socket.io": "~4.5.3",
|
||||
"socket.io-client": "~4.5.3",
|
||||
"socks-proxy-agent": "6.1.1",
|
||||
@@ -138,9 +146,11 @@
|
||||
"cypress": "^10.1.0",
|
||||
"delay": "^5.0.0",
|
||||
"dns2": "~2.0.1",
|
||||
"dompurify": "~2.4.3",
|
||||
"eslint": "~8.14.0",
|
||||
"eslint-plugin-vue": "~8.7.1",
|
||||
"favico.js": "~0.3.10",
|
||||
"marked": "~4.2.5",
|
||||
"jest": "~27.2.5",
|
||||
"postcss-html": "~1.5.0",
|
||||
"postcss-rtlcss": "~3.7.2",
|
||||
|
@@ -63,6 +63,12 @@ function myAuthorizer(username, password, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Use basic auth if auth is not disabled
|
||||
* @param {express.Request} req Express request object
|
||||
* @param {express.Response} res Express response object
|
||||
* @param {express.NextFunction} next
|
||||
*/
|
||||
exports.basicAuth = async function (req, res, next) {
|
||||
const middleware = basicAuth({
|
||||
authorizer: myAuthorizer,
|
||||
|
@@ -1,6 +1,8 @@
|
||||
const https = require("https");
|
||||
const http = require("http");
|
||||
const CacheableLookup = require("cacheable-lookup");
|
||||
const { Settings } = require("./settings");
|
||||
const { log } = require("../src/util");
|
||||
|
||||
class CacheableDnsHttpAgent {
|
||||
|
||||
@@ -9,14 +11,36 @@ class CacheableDnsHttpAgent {
|
||||
static httpAgentList = {};
|
||||
static httpsAgentList = {};
|
||||
|
||||
static enable = false;
|
||||
|
||||
/**
|
||||
* Register cacheable to global agents
|
||||
* Register/Disable cacheable to global agents
|
||||
*/
|
||||
static registerGlobalAgent() {
|
||||
this.cacheable.install(http.globalAgent);
|
||||
this.cacheable.install(https.globalAgent);
|
||||
static async update() {
|
||||
log.debug("CacheableDnsHttpAgent", "update");
|
||||
let isEnable = await Settings.get("dnsCache");
|
||||
|
||||
if (isEnable !== this.enable) {
|
||||
log.debug("CacheableDnsHttpAgent", "value changed");
|
||||
|
||||
if (isEnable) {
|
||||
log.debug("CacheableDnsHttpAgent", "enable");
|
||||
this.cacheable.install(http.globalAgent);
|
||||
this.cacheable.install(https.globalAgent);
|
||||
} else {
|
||||
log.debug("CacheableDnsHttpAgent", "disable");
|
||||
this.cacheable.uninstall(http.globalAgent);
|
||||
this.cacheable.uninstall(https.globalAgent);
|
||||
}
|
||||
}
|
||||
|
||||
this.enable = isEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach cacheable to HTTP agent
|
||||
* @param {http.Agent} agent Agent to install
|
||||
*/
|
||||
static install(agent) {
|
||||
this.cacheable.install(agent);
|
||||
}
|
||||
@@ -26,6 +50,10 @@ class CacheableDnsHttpAgent {
|
||||
* @return {https.Agent}
|
||||
*/
|
||||
static getHttpsAgent(agentOptions) {
|
||||
if (!this.enable) {
|
||||
return new https.Agent(agentOptions);
|
||||
}
|
||||
|
||||
let key = JSON.stringify(agentOptions);
|
||||
if (!(key in this.httpsAgentList)) {
|
||||
this.httpsAgentList[key] = new https.Agent(agentOptions);
|
||||
@@ -39,6 +67,10 @@ class CacheableDnsHttpAgent {
|
||||
* @return {https.Agents}
|
||||
*/
|
||||
static getHttpAgent(agentOptions) {
|
||||
if (!this.enable) {
|
||||
return new http.Agent(agentOptions);
|
||||
}
|
||||
|
||||
let key = JSON.stringify(agentOptions);
|
||||
if (!(key in this.httpAgentList)) {
|
||||
this.httpAgentList[key] = new http.Agent(agentOptions);
|
||||
|
@@ -4,13 +4,21 @@ const demoMode = args["demo"] || false;
|
||||
const badgeConstants = {
|
||||
naColor: "#999",
|
||||
defaultUpColor: "#66c20a",
|
||||
defaultWarnColor: "#eed202",
|
||||
defaultDownColor: "#c2290a",
|
||||
defaultPendingColor: "#f8a306",
|
||||
defaultMaintenanceColor: "#1747f5",
|
||||
defaultPingColor: "blue", // as defined by badge-maker / shields.io
|
||||
defaultStyle: "flat",
|
||||
defaultPingValueSuffix: "ms",
|
||||
defaultPingLabelSuffix: "h",
|
||||
defaultUptimeValueSuffix: "%",
|
||||
defaultUptimeLabelSuffix: "h",
|
||||
defaultCertExpValueSuffix: " days",
|
||||
defaultCertExpLabelSuffix: "h",
|
||||
// Values Come From Default Notification Times
|
||||
defaultCertExpireWarnDays: "14",
|
||||
defaultCertExpireDownDays: "7"
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
@@ -4,6 +4,7 @@ const { setSetting, setting } = require("./util-server");
|
||||
const { log, sleep } = require("../src/util");
|
||||
const dayjs = require("dayjs");
|
||||
const knex = require("knex");
|
||||
const { PluginsManager } = require("./plugins-manager");
|
||||
|
||||
/**
|
||||
* Database & App Data Folder
|
||||
@@ -65,7 +66,9 @@ class Database {
|
||||
"patch-grpc-monitor.sql": true,
|
||||
"patch-add-radius-monitor.sql": true,
|
||||
"patch-monitor-add-resend-interval.sql": true,
|
||||
"patch-ping-packet-size.sql": true,
|
||||
"patch-maintenance-table2.sql": true,
|
||||
"patch-add-gamedig-monitor.sql": true,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -83,6 +86,13 @@ class Database {
|
||||
static init(args) {
|
||||
// Data Directory (must be end with "/")
|
||||
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
|
||||
|
||||
// Plugin feature is working only if the dataDir = "./data";
|
||||
if (Database.dataDir !== "./data/") {
|
||||
log.warn("PLUGIN", "Warning: In order to enable plugin feature, you need to use the default data directory: ./data/");
|
||||
PluginsManager.disable = true;
|
||||
}
|
||||
|
||||
Database.path = Database.dataDir + "kuma.db";
|
||||
if (! fs.existsSync(Database.dataDir)) {
|
||||
fs.mkdirSync(Database.dataDir, { recursive: true });
|
||||
@@ -152,9 +162,6 @@ class Database {
|
||||
await R.exec("PRAGMA cache_size = -12000");
|
||||
await R.exec("PRAGMA auto_vacuum = FULL");
|
||||
|
||||
// Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write
|
||||
await R.exec("PRAGMA busy_timeout = 5000");
|
||||
|
||||
// This ensures that an operating system crash or power failure will not corrupt the database.
|
||||
// FULL synchronous is very safe, but it is also slower.
|
||||
// Read more: https://sqlite.org/pragma.html#pragma_synchronous
|
||||
|
24
server/git.js
Normal file
24
server/git.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const childProcess = require("child_process");
|
||||
|
||||
class Git {
|
||||
|
||||
static clone(repoURL, cwd, targetDir = ".") {
|
||||
let result = childProcess.spawnSync("git", [
|
||||
"clone",
|
||||
repoURL,
|
||||
targetDir,
|
||||
], {
|
||||
cwd: cwd,
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
throw new Error(result.stderr.toString("utf-8"));
|
||||
} else {
|
||||
return result.stdout.toString("utf-8") + result.stderr.toString("utf-8");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Git,
|
||||
};
|
@@ -32,6 +32,7 @@ const initBackgroundJobs = function (args) {
|
||||
return bree;
|
||||
};
|
||||
|
||||
/** Stop all background jobs if running */
|
||||
const stopBackgroundJobs = function () {
|
||||
if (bree) {
|
||||
bree.stop();
|
||||
|
@@ -25,15 +25,20 @@ const DEFAULT_KEEP_PERIOD = 180;
|
||||
parsedPeriod = DEFAULT_KEEP_PERIOD;
|
||||
}
|
||||
|
||||
log(`Clearing Data older than ${parsedPeriod} days...`);
|
||||
if (parsedPeriod < 1) {
|
||||
log(`Data deletion has been disabled as period is less than 1. Period is ${parsedPeriod} days.`);
|
||||
} else {
|
||||
|
||||
try {
|
||||
await R.exec(
|
||||
"DELETE FROM heartbeat WHERE time < DATETIME('now', '-' || ? || ' days') ",
|
||||
[ parsedPeriod ]
|
||||
);
|
||||
} catch (e) {
|
||||
log(`Failed to clear old data: ${e.message}`);
|
||||
log(`Clearing Data older than ${parsedPeriod} days...`);
|
||||
|
||||
try {
|
||||
await R.exec(
|
||||
"DELETE FROM heartbeat WHERE time < DATETIME('now', '-' || ? || ' days') ",
|
||||
[ parsedPeriod ]
|
||||
);
|
||||
} catch (e) {
|
||||
log(`Failed to clear old data: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
exit();
|
||||
|
@@ -112,6 +112,11 @@ class Maintenance extends BeanModel {
|
||||
return this.toPublicJSON(timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of weekdays that the maintenance is active for
|
||||
* Monday=1, Tuesday=2 etc.
|
||||
* @returns {number[]} Array of active weekdays
|
||||
*/
|
||||
getDayOfWeekList() {
|
||||
log.debug("timeslot", "List: " + this.weekdays);
|
||||
return JSON.parse(this.weekdays).sort(function (a, b) {
|
||||
@@ -119,12 +124,20 @@ class Maintenance extends BeanModel {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of days in month that maintenance is active for
|
||||
* @returns {number[]} Array of active days in month
|
||||
*/
|
||||
getDayOfMonthList() {
|
||||
return JSON.parse(this.days_of_month).sort(function (a, b) {
|
||||
return a - b;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start date and time for maintenance
|
||||
* @returns {dayjs.Dayjs} Start date and time
|
||||
*/
|
||||
getStartDateTime() {
|
||||
let startOfTheDay = dayjs.utc(this.start_date).format("HH:mm");
|
||||
log.debug("timeslot", "startOfTheDay: " + startOfTheDay);
|
||||
@@ -137,6 +150,10 @@ class Maintenance extends BeanModel {
|
||||
return dayjs.utc(this.start_date).add(startTimeSecond, "second");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the duraction of maintenance in seconds
|
||||
* @returns {number} Duration of maintenance
|
||||
*/
|
||||
getDuration() {
|
||||
let duration = dayjs.utc(this.end_time, "HH:mm").diff(dayjs.utc(this.start_time, "HH:mm"), "second");
|
||||
// Add 24hours if it is across day
|
||||
@@ -146,6 +163,12 @@ class Maintenance extends BeanModel {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert data from socket to bean
|
||||
* @param {Bean} bean Bean to fill in
|
||||
* @param {Object} obj Data to fill bean with
|
||||
* @returns {Bean} Filled bean
|
||||
*/
|
||||
static jsonToBean(bean, obj) {
|
||||
if (obj.id) {
|
||||
bean.id = obj.id;
|
||||
@@ -188,13 +211,13 @@ class Maintenance extends BeanModel {
|
||||
*/
|
||||
static getActiveMaintenanceSQLCondition() {
|
||||
return `
|
||||
|
||||
(maintenance_timeslot.start_date <= DATETIME('now')
|
||||
AND maintenance_timeslot.end_date >= DATETIME('now')
|
||||
AND maintenance.active = 1)
|
||||
OR
|
||||
(maintenance.strategy = 'manual' AND active = 1)
|
||||
|
||||
(
|
||||
(maintenance_timeslot.start_date <= DATETIME('now')
|
||||
AND maintenance_timeslot.end_date >= DATETIME('now')
|
||||
AND maintenance.active = 1)
|
||||
OR
|
||||
(maintenance.strategy = 'manual' AND active = 1)
|
||||
)
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -204,10 +227,12 @@ class Maintenance extends BeanModel {
|
||||
*/
|
||||
static getActiveAndFutureMaintenanceSQLCondition() {
|
||||
return `
|
||||
((maintenance_timeslot.end_date >= DATETIME('now')
|
||||
AND maintenance.active = 1)
|
||||
OR
|
||||
(maintenance.strategy = 'manual' AND active = 1))
|
||||
(
|
||||
((maintenance_timeslot.end_date >= DATETIME('now')
|
||||
AND maintenance.active = 1)
|
||||
OR
|
||||
(maintenance.strategy = 'manual' AND active = 1))
|
||||
)
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,11 @@ const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||
|
||||
class MaintenanceTimeslot extends BeanModel {
|
||||
|
||||
/**
|
||||
* Return an object that ready to parse to JSON for public
|
||||
* Only show necessary data to public
|
||||
* @returns {Object}
|
||||
*/
|
||||
async toPublicJSON() {
|
||||
const serverTimezoneOffset = UptimeKumaServer.getInstance().getTimezoneOffset();
|
||||
|
||||
@@ -21,6 +26,10 @@ class MaintenanceTimeslot extends BeanModel {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an object that ready to parse to JSON
|
||||
* @returns {Object}
|
||||
*/
|
||||
async toJSON() {
|
||||
return await this.toPublicJSON();
|
||||
}
|
||||
|
@@ -2,8 +2,10 @@ const https = require("https");
|
||||
const dayjs = require("dayjs");
|
||||
const axios = require("axios");
|
||||
const { Prometheus } = require("../prometheus");
|
||||
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger } = require("../../src/util");
|
||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery } = require("../util-server");
|
||||
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND } = require("../../src/util");
|
||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery,
|
||||
redisPingAsync, mongodbPing,
|
||||
} = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||
const { Notification } = require("../notification");
|
||||
@@ -15,6 +17,8 @@ const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||
const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent");
|
||||
const { DockerHost } = require("../docker");
|
||||
const Maintenance = require("./maintenance");
|
||||
const { UptimeCacheList } = require("../uptime-cache-list");
|
||||
const Gamedig = require("gamedig");
|
||||
|
||||
/**
|
||||
* status:
|
||||
@@ -35,7 +39,6 @@ class Monitor extends BeanModel {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
sendUrl: this.sendUrl,
|
||||
maintenance: await Monitor.isUnderMaintenance(this.id),
|
||||
};
|
||||
|
||||
if (this.sendUrl) {
|
||||
@@ -84,6 +87,7 @@ class Monitor extends BeanModel {
|
||||
expiryNotification: this.isEnabledExpiryNotification(),
|
||||
ignoreTls: this.getIgnoreTls(),
|
||||
upsideDown: this.isUpsideDown(),
|
||||
packetSize: this.packetSize,
|
||||
maxredirects: this.maxredirects,
|
||||
accepted_statuscodes: this.getAcceptedStatuscodes(),
|
||||
dns_resolve_type: this.dns_resolve_type,
|
||||
@@ -106,6 +110,7 @@ class Monitor extends BeanModel {
|
||||
grpcEnableTls: this.getGrpcEnableTls(),
|
||||
radiusCalledStationId: this.radiusCalledStationId,
|
||||
radiusCallingStationId: this.radiusCallingStationId,
|
||||
game: this.game,
|
||||
};
|
||||
|
||||
if (includeSensitiveData) {
|
||||
@@ -274,15 +279,11 @@ class Monitor extends BeanModel {
|
||||
...(this.body ? { data: JSON.parse(this.body) } : {}),
|
||||
timeout: this.interval * 1000 * 0.8,
|
||||
headers: {
|
||||
// Fix #2253
|
||||
// Read more: https://stackoverflow.com/questions/1759956/curl-error-18-transfer-closed-with-outstanding-read-data-remaining
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||
"User-Agent": "Uptime-Kuma/" + version,
|
||||
...(this.headers ? JSON.parse(this.headers) : {}),
|
||||
...(basicAuthHeader),
|
||||
},
|
||||
decompress: true,
|
||||
maxRedirects: this.maxredirects,
|
||||
validateStatus: (status) => {
|
||||
return checkStatusCode(status, this.getAcceptedStatuscodes());
|
||||
@@ -310,20 +311,8 @@ class Monitor extends BeanModel {
|
||||
log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`);
|
||||
log.debug("monitor", `[${this.name}] Axios Request`);
|
||||
|
||||
let res;
|
||||
if (this.auth_method === "ntlm") {
|
||||
options.httpsAgent.keepAlive = true;
|
||||
|
||||
res = await httpNtlm(options, {
|
||||
username: this.basic_auth_user,
|
||||
password: this.basic_auth_pass,
|
||||
domain: this.authDomain,
|
||||
workstation: this.authWorkstation ? this.authWorkstation : undefined
|
||||
});
|
||||
|
||||
} else {
|
||||
res = await axios.request(options);
|
||||
}
|
||||
// Make Request
|
||||
let res = await this.makeAxiosRequest(options);
|
||||
|
||||
bean.msg = `${res.status} - ${res.statusText}`;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
@@ -387,7 +376,7 @@ class Monitor extends BeanModel {
|
||||
bean.status = UP;
|
||||
|
||||
} else if (this.type === "ping") {
|
||||
bean.ping = await ping(this.hostname);
|
||||
bean.ping = await ping(this.hostname, this.packetSize);
|
||||
bean.msg = "";
|
||||
bean.status = UP;
|
||||
} else if (this.type === "dns") {
|
||||
@@ -497,25 +486,44 @@ class Monitor extends BeanModel {
|
||||
bean.msg = res.data.response.servers[0].name;
|
||||
|
||||
try {
|
||||
bean.ping = await ping(this.hostname);
|
||||
bean.ping = await ping(this.hostname, this.packetSize);
|
||||
} catch (_) { }
|
||||
} else {
|
||||
throw new Error("Server not found on Steam");
|
||||
}
|
||||
} else if (this.type === "gamedig") {
|
||||
try {
|
||||
const state = await Gamedig.query({
|
||||
type: this.game,
|
||||
host: this.hostname,
|
||||
port: this.port,
|
||||
givenPortOnly: true,
|
||||
});
|
||||
|
||||
bean.msg = state.name;
|
||||
bean.status = UP;
|
||||
bean.ping = state.ping;
|
||||
} catch (e) {
|
||||
throw new Error(e.message);
|
||||
}
|
||||
} else if (this.type === "docker") {
|
||||
log.debug(`[${this.name}] Prepare Options for Axios`);
|
||||
log.debug("monitor", `[${this.name}] Prepare Options for Axios`);
|
||||
|
||||
const dockerHost = await R.load("docker_host", this.docker_host);
|
||||
|
||||
const options = {
|
||||
url: `/containers/${this.docker_container}/json`,
|
||||
timeout: this.interval * 1000 * 0.8,
|
||||
headers: {
|
||||
"Accept": "*/*",
|
||||
"User-Agent": "Uptime-Kuma/" + version,
|
||||
},
|
||||
httpsAgent: new https.Agent({
|
||||
httpsAgent: CacheableDnsHttpAgent.getHttpsAgent({
|
||||
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
|
||||
rejectUnauthorized: ! this.getIgnoreTls(),
|
||||
rejectUnauthorized: !this.getIgnoreTls(),
|
||||
}),
|
||||
httpAgent: CacheableDnsHttpAgent.getHttpAgent({
|
||||
maxCachedSessions: 0,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -525,11 +533,13 @@ class Monitor extends BeanModel {
|
||||
options.baseURL = DockerHost.patchDockerURL(dockerHost._dockerDaemon);
|
||||
}
|
||||
|
||||
log.debug(`[${this.name}] Axios Request`);
|
||||
log.debug("monitor", `[${this.name}] Axios Request`);
|
||||
let res = await axios.request(options);
|
||||
if (res.data.State.Running) {
|
||||
bean.status = UP;
|
||||
bean.msg = "";
|
||||
bean.msg = res.data.State.Status;
|
||||
} else {
|
||||
throw Error("Container State is " + res.data.State.Status);
|
||||
}
|
||||
} else if (this.type === "mqtt") {
|
||||
bean.msg = await mqttAsync(this.hostname, this.mqttTopic, this.mqttSuccessMessage, {
|
||||
@@ -563,7 +573,7 @@ class Monitor extends BeanModel {
|
||||
log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`);
|
||||
let responseData = response.data;
|
||||
if (responseData.length > 50) {
|
||||
responseData = response.substring(0, 47) + "...";
|
||||
responseData = responseData.toString().substring(0, 47) + "...";
|
||||
}
|
||||
if (response.code !== 1) {
|
||||
bean.status = DOWN;
|
||||
@@ -594,6 +604,15 @@ class Monitor extends BeanModel {
|
||||
bean.msg = "";
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
} else if (this.type === "mongodb") {
|
||||
let startTime = dayjs().valueOf();
|
||||
|
||||
await mongodbPing(this.databaseConnectionString);
|
||||
|
||||
bean.msg = "";
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
|
||||
} else if (this.type === "radius") {
|
||||
let startTime = dayjs().valueOf();
|
||||
|
||||
@@ -630,9 +649,23 @@ class Monitor extends BeanModel {
|
||||
}
|
||||
}
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
} else if (this.type === "redis") {
|
||||
let startTime = dayjs().valueOf();
|
||||
|
||||
bean.msg = await redisPingAsync(this.databaseConnectionString);
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
|
||||
} else if (this.type in UptimeKumaServer.monitorTypeList) {
|
||||
let startTime = dayjs().valueOf();
|
||||
const monitorType = UptimeKumaServer.monitorTypeList[this.type];
|
||||
await monitorType.check(this, bean);
|
||||
if (!bean.ping) {
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
}
|
||||
|
||||
} else {
|
||||
bean.msg = "Unknown Monitor Type";
|
||||
bean.status = PENDING;
|
||||
throw new Error("Unknown Monitor Type");
|
||||
}
|
||||
|
||||
if (this.isUpsideDown()) {
|
||||
@@ -714,6 +747,7 @@ class Monitor extends BeanModel {
|
||||
}
|
||||
|
||||
log.debug("monitor", `[${this.name}] Send to socket`);
|
||||
UptimeCacheList.clearCache(this.id);
|
||||
io.to(this.user_id).emit("heartbeat", bean.toJSON());
|
||||
Monitor.sendStats(io, this.id, this.user_id);
|
||||
|
||||
@@ -760,6 +794,47 @@ class Monitor extends BeanModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request using axios
|
||||
* @param {Object} options Options for Axios
|
||||
* @param {boolean} finalCall Should this be the final call i.e
|
||||
* don't retry on faliure
|
||||
* @returns {Object} Axios response
|
||||
*/
|
||||
async makeAxiosRequest(options, finalCall = false) {
|
||||
try {
|
||||
let res;
|
||||
if (this.auth_method === "ntlm") {
|
||||
options.httpsAgent.keepAlive = true;
|
||||
|
||||
res = await httpNtlm(options, {
|
||||
username: this.basic_auth_user,
|
||||
password: this.basic_auth_pass,
|
||||
domain: this.authDomain,
|
||||
workstation: this.authWorkstation ? this.authWorkstation : undefined
|
||||
});
|
||||
|
||||
} else {
|
||||
res = await axios.request(options);
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
// Fix #2253
|
||||
// Read more: https://stackoverflow.com/questions/1759956/curl-error-18-transfer-closed-with-outstanding-read-data-remaining
|
||||
if (!finalCall && typeof e.message === "string" && e.message.includes("maxContentLength size of -1 exceeded")) {
|
||||
log.debug("monitor", "makeAxiosRequest with gzip");
|
||||
options.headers["Accept-Encoding"] = "gzip, deflate";
|
||||
return this.makeAxiosRequest(options, true);
|
||||
} else {
|
||||
if (typeof e.message === "string" && e.message.includes("maxContentLength size of -1 exceeded")) {
|
||||
e.message = "response timeout: incomplete response within a interval";
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop monitor */
|
||||
stop() {
|
||||
clearTimeout(this.heartbeatInterval);
|
||||
@@ -898,7 +973,15 @@ class Monitor extends BeanModel {
|
||||
* @param {number} duration Hours
|
||||
* @param {number} monitorID ID of monitor to calculate
|
||||
*/
|
||||
static async calcUptime(duration, monitorID) {
|
||||
static async calcUptime(duration, monitorID, forceNoCache = false) {
|
||||
|
||||
if (!forceNoCache) {
|
||||
let cachedUptime = UptimeCacheList.getUptime(monitorID, duration);
|
||||
if (cachedUptime != null) {
|
||||
return cachedUptime;
|
||||
}
|
||||
}
|
||||
|
||||
const timeLogger = new TimeLogger();
|
||||
|
||||
const startTime = R.isoDateTime(dayjs.utc().subtract(duration, "hour"));
|
||||
@@ -957,6 +1040,9 @@ class Monitor extends BeanModel {
|
||||
}
|
||||
}
|
||||
|
||||
// Cache
|
||||
UptimeCacheList.addUptime(monitorID, duration, uptime);
|
||||
|
||||
return uptime;
|
||||
}
|
||||
|
||||
@@ -1056,7 +1142,13 @@ class Monitor extends BeanModel {
|
||||
|
||||
for (let notification of notificationList) {
|
||||
try {
|
||||
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), bean.toJSON());
|
||||
// Prevent if the msg is undefined, notifications such as Discord cannot send out.
|
||||
const heartbeatJSON = bean.toJSON();
|
||||
if (!heartbeatJSON["msg"]) {
|
||||
heartbeatJSON["msg"] = "N/A";
|
||||
}
|
||||
|
||||
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), heartbeatJSON);
|
||||
} catch (e) {
|
||||
log.error("monitor", "Cannot send notification to " + notification.name);
|
||||
log.error("monitor", e);
|
||||
@@ -1163,7 +1255,7 @@ class Monitor extends BeanModel {
|
||||
*/
|
||||
static async getPreviousHeartbeat(monitorID) {
|
||||
return await R.getRow(`
|
||||
SELECT status, time FROM heartbeat
|
||||
SELECT ping, status, time FROM heartbeat
|
||||
WHERE id = (select MAX(id) from heartbeat where monitor_id = ?)
|
||||
`, [
|
||||
monitorID
|
||||
@@ -1189,6 +1281,16 @@ class Monitor extends BeanModel {
|
||||
LIMIT 1`, [ monitorID ]);
|
||||
return maintenance.count !== 0;
|
||||
}
|
||||
|
||||
/** Make sure monitor interval is between bounds */
|
||||
validate() {
|
||||
if (this.interval > MAX_INTERVAL_SECOND) {
|
||||
throw new Error(`Interval cannot be more than ${MAX_INTERVAL_SECOND} seconds`);
|
||||
}
|
||||
if (this.interval < MIN_INTERVAL_SECOND) {
|
||||
throw new Error(`Interval cannot be less than ${MIN_INTERVAL_SECOND} seconds`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Monitor;
|
||||
|
@@ -281,12 +281,14 @@ class StatusPage extends BeanModel {
|
||||
|
||||
let activeCondition = Maintenance.getActiveMaintenanceSQLCondition();
|
||||
let maintenanceBeanList = R.convertToBeans("maintenance", await R.getAll(`
|
||||
SELECT maintenance.*
|
||||
FROM maintenance, maintenance_status_page msp, maintenance_timeslot
|
||||
WHERE msp.maintenance_id = maintenance.id
|
||||
AND maintenance_timeslot.maintenance_id = maintenance.id
|
||||
AND msp.status_page_id = ?
|
||||
AND ${activeCondition}
|
||||
SELECT DISTINCT maintenance.*
|
||||
FROM maintenance
|
||||
JOIN maintenance_status_page
|
||||
ON maintenance_status_page.maintenance_id = maintenance.id
|
||||
AND maintenance_status_page.status_page_id = ?
|
||||
LEFT JOIN maintenance_timeslot
|
||||
ON maintenance_timeslot.maintenance_id = maintenance.id
|
||||
WHERE ${activeCondition}
|
||||
ORDER BY maintenance.end_date
|
||||
`, [ statusPageId ]));
|
||||
|
||||
|
20
server/modules/dayjs/plugin/timezone.d.ts
vendored
Normal file
20
server/modules/dayjs/plugin/timezone.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { PluginFunc, ConfigType } from 'dayjs'
|
||||
|
||||
declare const plugin: PluginFunc
|
||||
export = plugin
|
||||
|
||||
declare module 'dayjs' {
|
||||
interface Dayjs {
|
||||
tz(timezone?: string, keepLocalTime?: boolean): Dayjs
|
||||
offsetName(type?: 'short' | 'long'): string | undefined
|
||||
}
|
||||
|
||||
interface DayjsTimezone {
|
||||
(date: ConfigType, timezone?: string): Dayjs
|
||||
(date: ConfigType, format: string, timezone?: string): Dayjs
|
||||
guess(): string
|
||||
setDefault(timezone?: string): void
|
||||
}
|
||||
|
||||
const tz: DayjsTimezone
|
||||
}
|
115
server/modules/dayjs/plugin/timezone.js
Normal file
115
server/modules/dayjs/plugin/timezone.js
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Copy from node_modules/dayjs/plugin/timezone.js
|
||||
* Try to fix https://github.com/louislam/uptime-kuma/issues/2318
|
||||
* Source: https://github.com/iamkun/dayjs/tree/dev/src/plugin/utc
|
||||
* License: MIT
|
||||
*/
|
||||
!function (t, e) {
|
||||
// eslint-disable-next-line no-undef
|
||||
typeof exports == "object" && typeof module != "undefined" ? module.exports = e() : typeof define == "function" && define.amd ? define(e) : (t = typeof globalThis != "undefined" ? globalThis : t || self).dayjs_plugin_timezone = e();
|
||||
}(this, (function () {
|
||||
"use strict";
|
||||
let t = {
|
||||
year: 0,
|
||||
month: 1,
|
||||
day: 2,
|
||||
hour: 3,
|
||||
minute: 4,
|
||||
second: 5
|
||||
};
|
||||
let e = {};
|
||||
return function (n, i, o) {
|
||||
let r;
|
||||
let a = function (t, n, i) {
|
||||
void 0 === i && (i = {});
|
||||
let o = new Date(t);
|
||||
let r = function (t, n) {
|
||||
void 0 === n && (n = {});
|
||||
let i = n.timeZoneName || "short";
|
||||
let o = t + "|" + i;
|
||||
let r = e[o];
|
||||
return r || (r = new Intl.DateTimeFormat("en-US", {
|
||||
hour12: !1,
|
||||
timeZone: t,
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
timeZoneName: i
|
||||
}), e[o] = r), r;
|
||||
}(n, i);
|
||||
return r.formatToParts(o);
|
||||
};
|
||||
let u = function (e, n) {
|
||||
let i = a(e, n);
|
||||
let r = [];
|
||||
let u = 0;
|
||||
for (; u < i.length; u += 1) {
|
||||
let f = i[u];
|
||||
let s = f.type;
|
||||
let m = f.value;
|
||||
let c = t[s];
|
||||
c >= 0 && (r[c] = parseInt(m, 10));
|
||||
}
|
||||
let d = r[3];
|
||||
let l = d === 24 ? 0 : d;
|
||||
let v = r[0] + "-" + r[1] + "-" + r[2] + " " + l + ":" + r[4] + ":" + r[5] + ":000";
|
||||
let h = +e;
|
||||
return (o.utc(v).valueOf() - (h -= h % 1e3)) / 6e4;
|
||||
};
|
||||
let f = i.prototype;
|
||||
f.tz = function (t, e) {
|
||||
void 0 === t && (t = r);
|
||||
let n = this.utcOffset();
|
||||
let i = this.toDate();
|
||||
let a = i.toLocaleString("en-US", { timeZone: t }).replace("\u202f", " ");
|
||||
let u = Math.round((i - new Date(a)) / 1e3 / 60);
|
||||
let f = o(a).$set("millisecond", this.$ms).utcOffset(15 * -Math.round(i.getTimezoneOffset() / 15) - u, !0);
|
||||
if (e) {
|
||||
let s = f.utcOffset();
|
||||
f = f.add(n - s, "minute");
|
||||
}
|
||||
return f.$x.$timezone = t, f;
|
||||
}, f.offsetName = function (t) {
|
||||
let e = this.$x.$timezone || o.tz.guess();
|
||||
let n = a(this.valueOf(), e, { timeZoneName: t }).find((function (t) {
|
||||
return t.type.toLowerCase() === "timezonename";
|
||||
}));
|
||||
return n && n.value;
|
||||
};
|
||||
let s = f.startOf;
|
||||
f.startOf = function (t, e) {
|
||||
if (!this.$x || !this.$x.$timezone) {
|
||||
return s.call(this, t, e);
|
||||
}
|
||||
let n = o(this.format("YYYY-MM-DD HH:mm:ss:SSS"));
|
||||
return s.call(n, t, e).tz(this.$x.$timezone, !0);
|
||||
}, o.tz = function (t, e, n) {
|
||||
let i = n && e;
|
||||
let a = n || e || r;
|
||||
let f = u(+o(), a);
|
||||
if (typeof t != "string") {
|
||||
return o(t).tz(a);
|
||||
}
|
||||
let s = function (t, e, n) {
|
||||
let i = t - 60 * e * 1e3;
|
||||
let o = u(i, n);
|
||||
if (e === o) {
|
||||
return [ i, e ];
|
||||
}
|
||||
let r = u(i -= 60 * (o - e) * 1e3, n);
|
||||
return o === r ? [ i, o ] : [ t - 60 * Math.min(o, r) * 1e3, Math.max(o, r) ];
|
||||
}(o.utc(t, i).valueOf(), f, a);
|
||||
let m = s[0];
|
||||
let c = s[1];
|
||||
let d = o(m).utcOffset(c);
|
||||
return d.$x.$timezone = a, d;
|
||||
}, o.tz.guess = function () {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
}, o.tz.setDefault = function (t) {
|
||||
r = t;
|
||||
};
|
||||
};
|
||||
}));
|
19
server/monitor-types/monitor-type.js
Normal file
19
server/monitor-types/monitor-type.js
Normal file
@@ -0,0 +1,19 @@
|
||||
class MonitorType {
|
||||
|
||||
name = undefined;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Monitor} monitor
|
||||
* @param {Heartbeat} heartbeat
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async check(monitor, heartbeat) {
|
||||
throw new Error("You need to override check()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
MonitorType,
|
||||
};
|
@@ -8,7 +8,6 @@ class ClickSendSMS extends NotificationProvider {
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
let okMsg = "Sent Successfully.";
|
||||
try {
|
||||
console.log({ notification });
|
||||
let config = {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
@@ -64,7 +64,7 @@ class Discord extends NotificationProvider {
|
||||
},
|
||||
{
|
||||
name: "Error",
|
||||
value: heartbeatJSON["msg"],
|
||||
value: heartbeatJSON["msg"] == null ? "N/A" : heartbeatJSON["msg"],
|
||||
},
|
||||
],
|
||||
}],
|
||||
@@ -91,7 +91,7 @@ class Discord extends NotificationProvider {
|
||||
},
|
||||
{
|
||||
name: monitorJSON["type"] === "push" ? "Service Type" : "Service URL",
|
||||
value: monitorJSON["type"] === "push" ? "Heartbeat" : address.startsWith("http") ? "[Visit Service](" + address + ")" : address,
|
||||
value: monitorJSON["type"] === "push" ? "Heartbeat" : address,
|
||||
},
|
||||
{
|
||||
name: "Time (UTC)",
|
||||
|
31
server/notification-providers/kook.js
Normal file
31
server/notification-providers/kook.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
|
||||
class Kook extends NotificationProvider {
|
||||
|
||||
name = "Kook";
|
||||
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
let okMsg = "Sent Successfully.";
|
||||
let url = "https://www.kookapp.cn/api/v3/message/create";
|
||||
let data = {
|
||||
target_id: notification.kookGuildID,
|
||||
content: msg,
|
||||
};
|
||||
let config = {
|
||||
headers: {
|
||||
"Authorization": "Bot " + notification.kookBotToken,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
try {
|
||||
await axios.post(url, data, config);
|
||||
return okMsg;
|
||||
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Kook;
|
@@ -8,6 +8,14 @@ class PromoSMS extends NotificationProvider {
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
let okMsg = "Sent Successfully.";
|
||||
|
||||
if (notification.promosmsAllowLongSMS === undefined) {
|
||||
notification.promosmsAllowLongSMS = false;
|
||||
}
|
||||
|
||||
//TODO: Add option for enabling special characters. It will decrese message max length from 160 to 70 chars.
|
||||
//Lets remove non ascii char
|
||||
let cleanMsg = msg.replace(/[^\x00-\x7F]/g, "");
|
||||
|
||||
try {
|
||||
let config = {
|
||||
headers: {
|
||||
@@ -18,8 +26,9 @@ class PromoSMS extends NotificationProvider {
|
||||
};
|
||||
let data = {
|
||||
"recipients": [ notification.promosmsPhoneNumber ],
|
||||
//Lets remove non ascii char
|
||||
"text": msg.replace(/[^\x00-\x7F]/g, ""),
|
||||
//Trim message to maximum length of 1 SMS or 4 if we allowed long messages
|
||||
"text": notification.promosmsAllowLongSMS ? cleanMsg.substring(0, 639) : cleanMsg.substring(0, 159),
|
||||
"long-sms": notification.promosmsAllowLongSMS,
|
||||
"type": Number(notification.promosmsSMSType),
|
||||
"sender": notification.promosmsSenderName
|
||||
};
|
||||
|
@@ -10,7 +10,7 @@ class Pushover extends NotificationProvider {
|
||||
let pushoverlink = "https://api.pushover.net/1/messages.json";
|
||||
|
||||
let data = {
|
||||
"message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" + msg,
|
||||
"message": msg,
|
||||
"user": notification.pushoveruserkey,
|
||||
"token": notification.pushoverapptoken,
|
||||
"sound": notification.pushoversounds,
|
||||
|
@@ -21,6 +21,12 @@ class ServerChan extends NotificationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted title for message
|
||||
* @param {?Object} monitorJSON Monitor details (For Up/Down only)
|
||||
* @param {?Object} heartbeatJSON Heartbeat details (For Up/Down only)
|
||||
* @returns {string} Formatted title
|
||||
*/
|
||||
checkStatus(heartbeatJSON, monitorJSON) {
|
||||
let title = "UptimeKuma Message";
|
||||
if (heartbeatJSON != null && heartbeatJSON["status"] === UP) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { setSettings, setting } = require("../util-server");
|
||||
const { getMonitorRelativeURL } = require("../../src/util");
|
||||
const { getMonitorRelativeURL, UP } = require("../../src/util");
|
||||
|
||||
class Slack extends NotificationProvider {
|
||||
|
||||
@@ -46,24 +46,31 @@ class Slack extends NotificationProvider {
|
||||
"channel": notification.slackchannel,
|
||||
"username": notification.slackusername,
|
||||
"icon_emoji": notification.slackiconemo,
|
||||
"blocks": [{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "Uptime Kuma Alert",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"fields": [{
|
||||
"type": "mrkdwn",
|
||||
"text": "*Message*\n" + msg,
|
||||
},
|
||||
"attachments": [
|
||||
{
|
||||
"type": "mrkdwn",
|
||||
"text": "*Time (UTC)*\n" + time,
|
||||
}],
|
||||
}],
|
||||
"color": (heartbeatJSON["status"] === UP) ? "#2eb886" : "#e01e5a",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "Uptime Kuma Alert",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"fields": [{
|
||||
"type": "mrkdwn",
|
||||
"text": "*Message*\n" + msg,
|
||||
},
|
||||
{
|
||||
"type": "mrkdwn",
|
||||
"text": "*Time (UTC)*\n" + time,
|
||||
}],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
if (notification.slackbutton) {
|
||||
@@ -74,17 +81,19 @@ class Slack extends NotificationProvider {
|
||||
|
||||
// Button
|
||||
if (baseURL) {
|
||||
data.blocks.push({
|
||||
"type": "actions",
|
||||
"elements": [{
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "Visit Uptime Kuma",
|
||||
},
|
||||
"value": "Uptime-Kuma",
|
||||
"url": baseURL + getMonitorRelativeURL(monitorJSON.id),
|
||||
}],
|
||||
data.attachments.forEach(element => {
|
||||
element.blocks.push({
|
||||
"type": "actions",
|
||||
"elements": [{
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "Visit Uptime Kuma",
|
||||
},
|
||||
"value": "Uptime-Kuma",
|
||||
"url": baseURL + getMonitorRelativeURL(monitorJSON.id),
|
||||
}],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
113
server/notification-providers/splunk.js
Normal file
113
server/notification-providers/splunk.js
Normal file
@@ -0,0 +1,113 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
|
||||
const { setting } = require("../util-server");
|
||||
let successMessage = "Sent Successfully.";
|
||||
|
||||
class Splunk extends NotificationProvider {
|
||||
name = "Splunk";
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
try {
|
||||
if (heartbeatJSON == null) {
|
||||
const title = "Uptime Kuma Alert";
|
||||
const monitor = {
|
||||
type: "ping",
|
||||
url: "Uptime Kuma Test Button",
|
||||
};
|
||||
return this.postNotification(notification, title, msg, monitor, "trigger");
|
||||
}
|
||||
|
||||
if (heartbeatJSON.status === UP) {
|
||||
const title = "Uptime Kuma Monitor ✅ Up";
|
||||
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, "recovery");
|
||||
}
|
||||
|
||||
if (heartbeatJSON.status === DOWN) {
|
||||
const title = "Uptime Kuma Monitor 🔴 Down";
|
||||
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, "trigger");
|
||||
}
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if result is successful, result code should be in range 2xx
|
||||
* @param {Object} result Axios response object
|
||||
* @throws {Error} The status code is not in range 2xx
|
||||
*/
|
||||
checkResult(result) {
|
||||
if (result.status == null) {
|
||||
throw new Error("Splunk notification failed with invalid response!");
|
||||
}
|
||||
if (result.status < 200 || result.status >= 300) {
|
||||
throw new Error("Splunk notification failed with status code " + result.status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message
|
||||
* @param {BeanModel} notification Message title
|
||||
* @param {string} title Message title
|
||||
* @param {string} body Message
|
||||
* @param {Object} monitorInfo Monitor details (For Up/Down only)
|
||||
* @param {?string} eventAction Action event for PagerDuty (trigger, acknowledge, resolve)
|
||||
* @returns {string}
|
||||
*/
|
||||
async postNotification(notification, title, body, monitorInfo, eventAction = "trigger") {
|
||||
|
||||
let monitorUrl;
|
||||
if (monitorInfo.type === "port") {
|
||||
monitorUrl = monitorInfo.hostname;
|
||||
if (monitorInfo.port) {
|
||||
monitorUrl += ":" + monitorInfo.port;
|
||||
}
|
||||
} else if (monitorInfo.hostname != null) {
|
||||
monitorUrl = monitorInfo.hostname;
|
||||
} else {
|
||||
monitorUrl = monitorInfo.url;
|
||||
}
|
||||
|
||||
if (eventAction === "recovery") {
|
||||
if (notification.splunkAutoResolve === "0") {
|
||||
return "No action required";
|
||||
}
|
||||
eventAction = notification.splunkAutoResolve;
|
||||
} else {
|
||||
eventAction = notification.splunkSeverity;
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: "POST",
|
||||
url: notification.splunkRestURL,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: {
|
||||
message_type: eventAction,
|
||||
state_message: `[${title}] [${monitorUrl}] ${body}`,
|
||||
entity_display_name: "Uptime Kuma Alert: " + monitorInfo.name,
|
||||
routing_key: notification.pagerdutyIntegrationKey,
|
||||
entity_id: "Uptime Kuma/" + monitorInfo.id,
|
||||
}
|
||||
};
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
if (baseURL && monitorInfo) {
|
||||
options.client = "Uptime Kuma";
|
||||
options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id);
|
||||
}
|
||||
|
||||
let result = await axios.request(options);
|
||||
this.checkResult(result);
|
||||
if (result.statusText != null) {
|
||||
return "Splunk notification succeed: " + result.statusText;
|
||||
}
|
||||
|
||||
return successMessage;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Splunk;
|
116
server/notification-providers/zoho-cliq.js
Normal file
116
server/notification-providers/zoho-cliq.js
Normal file
@@ -0,0 +1,116 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { DOWN, UP } = require("../../src/util");
|
||||
|
||||
class ZohoCliq extends NotificationProvider {
|
||||
|
||||
name = "ZohoCliq";
|
||||
|
||||
/**
|
||||
* Generate the message to send
|
||||
* @param {const} status The status constant
|
||||
* @param {string} monitorName Name of monitor
|
||||
* @returns {string}
|
||||
*/
|
||||
_statusMessageFactory = (status, monitorName) => {
|
||||
if (status === DOWN) {
|
||||
return `🔴 Application [${monitorName}] went down\n`;
|
||||
} else if (status === UP) {
|
||||
return `✅ Application [${monitorName}] is back online\n`;
|
||||
}
|
||||
return "Notification\n";
|
||||
};
|
||||
|
||||
/**
|
||||
* Send the notification
|
||||
* @param {string} webhookUrl URL to send the request to
|
||||
* @param {Array} payload Payload generated by _notificationPayloadFactory
|
||||
*/
|
||||
_sendNotification = async (webhookUrl, payload) => {
|
||||
await axios.post(webhookUrl, { text: payload.join("\n") });
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate payload for notification
|
||||
* @param {const} status The status of the monitor
|
||||
* @param {string} monitorMessage Message to send
|
||||
* @param {string} monitorName Name of monitor affected
|
||||
* @param {string} monitorUrl URL of monitor affected
|
||||
* @returns {Array}
|
||||
*/
|
||||
_notificationPayloadFactory = ({
|
||||
status,
|
||||
monitorMessage,
|
||||
monitorName,
|
||||
monitorUrl,
|
||||
}) => {
|
||||
const payload = [];
|
||||
payload.push("### Uptime Kuma\n");
|
||||
payload.push(this._statusMessageFactory(status, monitorName));
|
||||
payload.push(`*Description:* ${monitorMessage}`);
|
||||
|
||||
if (monitorName) {
|
||||
payload.push(`*Monitor:* ${monitorName}`);
|
||||
}
|
||||
|
||||
if (monitorUrl && monitorUrl !== "https://") {
|
||||
payload.push(`*URL:* [${monitorUrl}](${monitorUrl})`);
|
||||
}
|
||||
|
||||
return payload;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a general notification
|
||||
* @param {string} webhookUrl URL to send request to
|
||||
* @param {string} msg Message to send
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
_handleGeneralNotification = (webhookUrl, msg) => {
|
||||
const payload = this._notificationPayloadFactory({
|
||||
monitorMessage: msg
|
||||
});
|
||||
|
||||
return this._sendNotification(webhookUrl, payload);
|
||||
};
|
||||
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
let okMsg = "Sent Successfully.";
|
||||
|
||||
try {
|
||||
if (heartbeatJSON == null) {
|
||||
await this._handleGeneralNotification(notification.webhookUrl, msg);
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
let url;
|
||||
switch (monitorJSON["type"]) {
|
||||
case "http":
|
||||
case "keywork":
|
||||
url = monitorJSON["url"];
|
||||
break;
|
||||
case "docker":
|
||||
url = monitorJSON["docker_host"];
|
||||
break;
|
||||
default:
|
||||
url = monitorJSON["hostname"];
|
||||
break;
|
||||
}
|
||||
|
||||
const payload = this._notificationPayloadFactory({
|
||||
monitorMessage: heartbeatJSON.msg,
|
||||
monitorName: monitorJSON.name,
|
||||
monitorUrl: url,
|
||||
status: heartbeatJSON.status
|
||||
});
|
||||
|
||||
await this._sendNotification(notification.webhookUrl, payload);
|
||||
return okMsg;
|
||||
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ZohoCliq;
|
@@ -14,6 +14,7 @@ const GoogleChat = require("./notification-providers/google-chat");
|
||||
const Gorush = require("./notification-providers/gorush");
|
||||
const Gotify = require("./notification-providers/gotify");
|
||||
const HomeAssistant = require("./notification-providers/home-assistant");
|
||||
const Kook = require("./notification-providers/kook");
|
||||
const Line = require("./notification-providers/line");
|
||||
const LineNotify = require("./notification-providers/linenotify");
|
||||
const LunaSea = require("./notification-providers/lunasea");
|
||||
@@ -39,11 +40,13 @@ const Stackfield = require("./notification-providers/stackfield");
|
||||
const Teams = require("./notification-providers/teams");
|
||||
const TechulusPush = require("./notification-providers/techulus-push");
|
||||
const Telegram = require("./notification-providers/telegram");
|
||||
const Splunk = require("./notification-providers/splunk");
|
||||
const Webhook = require("./notification-providers/webhook");
|
||||
const WeCom = require("./notification-providers/wecom");
|
||||
const GoAlert = require("./notification-providers/goalert");
|
||||
const SMSManager = require("./notification-providers/smsmanager");
|
||||
const ServerChan = require("./notification-providers/serverchan");
|
||||
const ZohoCliq = require("./notification-providers/zoho-cliq");
|
||||
|
||||
class Notification {
|
||||
|
||||
@@ -70,6 +73,7 @@ class Notification {
|
||||
new Gorush(),
|
||||
new Gotify(),
|
||||
new HomeAssistant(),
|
||||
new Kook(),
|
||||
new Line(),
|
||||
new LineNotify(),
|
||||
new LunaSea(),
|
||||
@@ -97,9 +101,11 @@ class Notification {
|
||||
new Teams(),
|
||||
new TechulusPush(),
|
||||
new Telegram(),
|
||||
new Splunk(),
|
||||
new Webhook(),
|
||||
new WeCom(),
|
||||
new GoAlert(),
|
||||
new ZohoCliq()
|
||||
];
|
||||
|
||||
for (let item of list) {
|
||||
|
@@ -1,199 +0,0 @@
|
||||
// https://github.com/ben-bradley/ping-lite/blob/master/ping-lite.js
|
||||
// Fixed on Windows
|
||||
const net = require("net");
|
||||
const spawn = require("child_process").spawn;
|
||||
const events = require("events");
|
||||
const fs = require("fs");
|
||||
const util = require("./util-server");
|
||||
|
||||
module.exports = Ping;
|
||||
|
||||
/**
|
||||
* Constructor for ping class
|
||||
* @param {string} host Host to ping
|
||||
* @param {object} [options] Options for the ping command
|
||||
* @param {array|string} [options.args] - Arguments to pass to the ping command
|
||||
*/
|
||||
function Ping(host, options) {
|
||||
if (!host) {
|
||||
throw new Error("You must specify a host to ping!");
|
||||
}
|
||||
|
||||
this._host = host;
|
||||
this._options = options = (options || {});
|
||||
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
const timeout = 10;
|
||||
|
||||
if (util.WIN) {
|
||||
this._bin = "c:/windows/system32/ping.exe";
|
||||
this._args = (options.args) ? options.args : [ "-n", "1", "-w", timeout * 1000, host ];
|
||||
this._regmatch = /[><=]([0-9.]+?)ms/;
|
||||
|
||||
} else if (util.LIN) {
|
||||
this._bin = "/bin/ping";
|
||||
|
||||
const defaultArgs = [ "-n", "-w", timeout, "-c", "1", host ];
|
||||
|
||||
if (net.isIPv6(host) || options.ipv6) {
|
||||
defaultArgs.unshift("-6");
|
||||
}
|
||||
|
||||
this._args = (options.args) ? options.args : defaultArgs;
|
||||
this._regmatch = /=([0-9.]+?) ms/;
|
||||
|
||||
} else if (util.MAC) {
|
||||
|
||||
if (net.isIPv6(host) || options.ipv6) {
|
||||
this._bin = "/sbin/ping6";
|
||||
} else {
|
||||
this._bin = "/sbin/ping";
|
||||
}
|
||||
|
||||
this._args = (options.args) ? options.args : [ "-n", "-t", timeout, "-c", "1", host ];
|
||||
this._regmatch = /=([0-9.]+?) ms/;
|
||||
|
||||
} else if (util.BSD) {
|
||||
this._bin = "/sbin/ping";
|
||||
|
||||
const defaultArgs = [ "-n", "-t", timeout, "-c", "1", host ];
|
||||
|
||||
if (net.isIPv6(host) || options.ipv6) {
|
||||
defaultArgs.unshift("-6");
|
||||
}
|
||||
|
||||
this._args = (options.args) ? options.args : defaultArgs;
|
||||
this._regmatch = /=([0-9.]+?) ms/;
|
||||
|
||||
} else {
|
||||
throw new Error("Could not detect your ping binary.");
|
||||
}
|
||||
|
||||
if (!fs.existsSync(this._bin)) {
|
||||
throw new Error("Could not detect " + this._bin + " on your system");
|
||||
}
|
||||
|
||||
this._i = 0;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Ping.prototype.__proto__ = events.EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Callback for send
|
||||
* @callback pingCB
|
||||
* @param {any} err Any error encountered
|
||||
* @param {number} ms Ping time in ms
|
||||
*/
|
||||
|
||||
/**
|
||||
* Send a ping
|
||||
* @param {pingCB} callback Callback to call with results
|
||||
*/
|
||||
Ping.prototype.send = function (callback) {
|
||||
let self = this;
|
||||
callback = callback || function (err, ms) {
|
||||
if (err) {
|
||||
return self.emit("error", err);
|
||||
}
|
||||
return self.emit("result", ms);
|
||||
};
|
||||
|
||||
let _ended;
|
||||
let _exited;
|
||||
let _errored;
|
||||
|
||||
this._ping = spawn(this._bin, this._args, { windowsHide: true }); // spawn the binary
|
||||
|
||||
this._ping.on("error", function (err) { // handle binary errors
|
||||
_errored = true;
|
||||
callback(err);
|
||||
});
|
||||
|
||||
this._ping.stdout.on("data", function (data) { // log stdout
|
||||
if (util.WIN) {
|
||||
data = convertOutput(data);
|
||||
}
|
||||
this._stdout = (this._stdout || "") + data;
|
||||
});
|
||||
|
||||
this._ping.stdout.on("end", function () {
|
||||
_ended = true;
|
||||
if (_exited && !_errored) {
|
||||
onEnd.call(self._ping);
|
||||
}
|
||||
});
|
||||
|
||||
this._ping.stderr.on("data", function (data) { // log stderr
|
||||
if (util.WIN) {
|
||||
data = convertOutput(data);
|
||||
}
|
||||
this._stderr = (this._stderr || "") + data;
|
||||
});
|
||||
|
||||
this._ping.on("exit", function (code) { // handle complete
|
||||
_exited = true;
|
||||
if (_ended && !_errored) {
|
||||
onEnd.call(self._ping);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {Function} callback
|
||||
*
|
||||
* Generated by Trelent
|
||||
*/
|
||||
function onEnd() {
|
||||
let stdout = this.stdout._stdout;
|
||||
let stderr = this.stderr._stderr;
|
||||
let ms;
|
||||
|
||||
if (stderr) {
|
||||
return callback(new Error(stderr));
|
||||
}
|
||||
|
||||
if (!stdout) {
|
||||
return callback(new Error("No stdout detected"));
|
||||
}
|
||||
|
||||
ms = stdout.match(self._regmatch); // parse out the ##ms response
|
||||
ms = (ms && ms[1]) ? Number(ms[1]) : ms;
|
||||
|
||||
callback(null, ms, stdout);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ping every interval
|
||||
* @param {pingCB} callback Callback to call with results
|
||||
*/
|
||||
Ping.prototype.start = function (callback) {
|
||||
let self = this;
|
||||
this._i = setInterval(function () {
|
||||
self.send(callback);
|
||||
}, (self._options.interval || 5000));
|
||||
self.send(callback);
|
||||
};
|
||||
|
||||
/** Stop sending pings */
|
||||
Ping.prototype.stop = function () {
|
||||
clearInterval(this._i);
|
||||
};
|
||||
|
||||
/**
|
||||
* Try to convert to UTF-8 for Windows, as the ping's output on Windows is not UTF-8 and could be in other languages
|
||||
* Thank @pemassi
|
||||
* https://github.com/louislam/uptime-kuma/issues/570#issuecomment-941984094
|
||||
* @param {any} data
|
||||
* @returns {string}
|
||||
*/
|
||||
function convertOutput(data) {
|
||||
if (util.WIN) {
|
||||
if (data) {
|
||||
return util.convertToUTF8(data);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
13
server/plugin.js
Normal file
13
server/plugin.js
Normal file
@@ -0,0 +1,13 @@
|
||||
class Plugin {
|
||||
async load() {
|
||||
|
||||
}
|
||||
|
||||
async unload() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Plugin,
|
||||
};
|
256
server/plugins-manager.js
Normal file
256
server/plugins-manager.js
Normal file
@@ -0,0 +1,256 @@
|
||||
const fs = require("fs");
|
||||
const { log } = require("../src/util");
|
||||
const path = require("path");
|
||||
const axios = require("axios");
|
||||
const { Git } = require("./git");
|
||||
const childProcess = require("child_process");
|
||||
|
||||
class PluginsManager {
|
||||
|
||||
static disable = false;
|
||||
|
||||
/**
|
||||
* Plugin List
|
||||
* @type {PluginWrapper[]}
|
||||
*/
|
||||
pluginList = [];
|
||||
|
||||
/**
|
||||
* Plugins Dir
|
||||
*/
|
||||
pluginsDir;
|
||||
|
||||
server;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {UptimeKumaServer} server
|
||||
*/
|
||||
constructor(server) {
|
||||
this.server = server;
|
||||
|
||||
if (!PluginsManager.disable) {
|
||||
this.pluginsDir = "./data/plugins/";
|
||||
|
||||
if (! fs.existsSync(this.pluginsDir)) {
|
||||
fs.mkdirSync(this.pluginsDir, { recursive: true });
|
||||
}
|
||||
|
||||
log.debug("plugin", "Scanning plugin directory");
|
||||
let list = fs.readdirSync(this.pluginsDir);
|
||||
|
||||
this.pluginList = [];
|
||||
for (let item of list) {
|
||||
this.loadPlugin(item);
|
||||
}
|
||||
|
||||
} else {
|
||||
log.warn("PLUGIN", "Skip scanning plugin directory");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a Plugin
|
||||
*/
|
||||
async loadPlugin(name) {
|
||||
log.info("plugin", "Load " + name);
|
||||
let plugin = new PluginWrapper(this.server, this.pluginsDir + name);
|
||||
|
||||
try {
|
||||
await plugin.load();
|
||||
this.pluginList.push(plugin);
|
||||
} catch (e) {
|
||||
log.error("plugin", "Failed to load plugin: " + this.pluginsDir + name);
|
||||
log.error("plugin", "Reason: " + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a Plugin
|
||||
* @param {string} repoURL Git repo url
|
||||
* @param {string} name Directory name, also known as plugin unique name
|
||||
*/
|
||||
downloadPlugin(repoURL, name) {
|
||||
if (fs.existsSync(this.pluginsDir + name)) {
|
||||
log.info("plugin", "Plugin folder already exists? Removing...");
|
||||
fs.rmSync(this.pluginsDir + name, {
|
||||
recursive: true
|
||||
});
|
||||
}
|
||||
log.info("plugin", "Installing plugin: " + name + " " + repoURL);
|
||||
let result = Git.clone(repoURL, this.pluginsDir, name);
|
||||
log.info("plugin", "Install result: " + result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a plugin
|
||||
* @param {string} name
|
||||
*/
|
||||
async removePlugin(name) {
|
||||
log.info("plugin", "Removing plugin: " + name);
|
||||
for (let plugin of this.pluginList) {
|
||||
if (plugin.info.name === name) {
|
||||
await plugin.unload();
|
||||
|
||||
// Delete the plugin directory
|
||||
fs.rmSync(this.pluginsDir + name, {
|
||||
recursive: true
|
||||
});
|
||||
|
||||
this.pluginList.splice(this.pluginList.indexOf(plugin), 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
log.warn("plugin", "Plugin not found: " + name);
|
||||
throw new Error("Plugin not found: " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Update a plugin
|
||||
* Only available for plugins which were downloaded from the official list
|
||||
* @param pluginID
|
||||
*/
|
||||
updatePlugin(pluginID) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin list from server + local installed plugin list
|
||||
* Item will be merged if the `name` is the same.
|
||||
* @returns {Promise<[]>}
|
||||
*/
|
||||
async fetchPluginList() {
|
||||
let remotePluginList;
|
||||
try {
|
||||
const res = await axios.get("https://uptime.kuma.pet/c/plugins.json");
|
||||
remotePluginList = res.data.pluginList;
|
||||
} catch (e) {
|
||||
log.error("plugin", "Failed to fetch plugin list: " + e.message);
|
||||
remotePluginList = [];
|
||||
}
|
||||
|
||||
for (let plugin of this.pluginList) {
|
||||
let find = false;
|
||||
// Try to merge
|
||||
for (let remotePlugin of remotePluginList) {
|
||||
if (remotePlugin.name === plugin.info.name) {
|
||||
find = true;
|
||||
remotePlugin.installed = true;
|
||||
remotePlugin.name = plugin.info.name;
|
||||
remotePlugin.fullName = plugin.info.fullName;
|
||||
remotePlugin.description = plugin.info.description;
|
||||
remotePlugin.version = plugin.info.version;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Local plugin
|
||||
if (!find) {
|
||||
plugin.info.local = true;
|
||||
remotePluginList.push(plugin.info);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort Installed first, then sort by name
|
||||
return remotePluginList.sort((a, b) => {
|
||||
if (a.installed === b.installed) {
|
||||
if (a.fullName < b.fullName) {
|
||||
return -1;
|
||||
}
|
||||
if (a.fullName > b.fullName) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else if (a.installed) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class PluginWrapper {
|
||||
|
||||
server = undefined;
|
||||
pluginDir = undefined;
|
||||
|
||||
/**
|
||||
* Must be an `new-able` class.
|
||||
* @type {function}
|
||||
*/
|
||||
pluginClass = undefined;
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {Plugin}
|
||||
*/
|
||||
object = undefined;
|
||||
info = {};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {UptimeKumaServer} server
|
||||
* @param {string} pluginDir
|
||||
*/
|
||||
constructor(server, pluginDir) {
|
||||
this.server = server;
|
||||
this.pluginDir = pluginDir;
|
||||
}
|
||||
|
||||
async load() {
|
||||
let indexFile = this.pluginDir + "/index.js";
|
||||
let packageJSON = this.pluginDir + "/package.json";
|
||||
|
||||
log.info("plugin", "Installing dependencies");
|
||||
|
||||
if (fs.existsSync(indexFile)) {
|
||||
// Install dependencies
|
||||
let result = childProcess.spawnSync("npm", [ "install" ], {
|
||||
cwd: this.pluginDir,
|
||||
env: {
|
||||
...process.env,
|
||||
PLAYWRIGHT_BROWSERS_PATH: "../../browsers", // Special handling for read-browser-monitor
|
||||
}
|
||||
});
|
||||
|
||||
if (result.stdout) {
|
||||
log.info("plugin", "Install dependencies result: " + result.stdout.toString("utf-8"));
|
||||
} else {
|
||||
log.warn("plugin", "Install dependencies result: no output");
|
||||
}
|
||||
|
||||
this.pluginClass = require(path.join(process.cwd(), indexFile));
|
||||
|
||||
let pluginClassType = typeof this.pluginClass;
|
||||
|
||||
if (pluginClassType === "function") {
|
||||
this.object = new this.pluginClass(this.server);
|
||||
await this.object.load();
|
||||
} else {
|
||||
throw new Error("Invalid plugin, it does not export a class");
|
||||
}
|
||||
|
||||
if (fs.existsSync(packageJSON)) {
|
||||
this.info = require(path.join(process.cwd(), packageJSON));
|
||||
} else {
|
||||
this.info.fullName = this.pluginDir;
|
||||
this.info.name = "[unknown]";
|
||||
this.info.version = "[unknown-version]";
|
||||
}
|
||||
|
||||
this.info.installed = true;
|
||||
log.info("plugin", `${this.info.fullName} v${this.info.version} loaded`);
|
||||
}
|
||||
}
|
||||
|
||||
async unload() {
|
||||
await this.object.unload();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PluginsManager,
|
||||
PluginWrapper
|
||||
};
|
@@ -99,6 +99,7 @@ class Prometheus {
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove monitor from prometheus */
|
||||
remove() {
|
||||
try {
|
||||
monitorCertDaysRemaining.remove(this.monitorLabelValues);
|
||||
|
@@ -4,7 +4,7 @@ const { R } = require("redbean-node");
|
||||
const apicache = require("../modules/apicache");
|
||||
const Monitor = require("../model/monitor");
|
||||
const dayjs = require("dayjs");
|
||||
const { UP, MAINTENANCE, DOWN, flipStatus, log } = require("../../src/util");
|
||||
const { UP, MAINTENANCE, DOWN, PENDING, flipStatus, log } = require("../../src/util");
|
||||
const StatusPage = require("../model/status_page");
|
||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||
const { makeBadge } = require("badge-maker");
|
||||
@@ -111,8 +111,12 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
|
||||
label,
|
||||
upLabel = "Up",
|
||||
downLabel = "Down",
|
||||
pendingLabel = "Pending",
|
||||
maintenanceLabel = "Maintenance",
|
||||
upColor = badgeConstants.defaultUpColor,
|
||||
downColor = badgeConstants.defaultDownColor,
|
||||
pendingColor = badgeConstants.defaultPendingColor,
|
||||
maintenanceColor = badgeConstants.defaultMaintenanceColor,
|
||||
style = badgeConstants.defaultStyle,
|
||||
value, // for demo purpose only
|
||||
} = request.query;
|
||||
@@ -139,11 +143,30 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
} else {
|
||||
const heartbeat = await Monitor.getPreviousHeartbeat(requestedMonitorId);
|
||||
const state = overrideValue !== undefined ? overrideValue : heartbeat.status === 1;
|
||||
const state = overrideValue !== undefined ? overrideValue : heartbeat.status;
|
||||
|
||||
badgeValues.label = label ? label : "";
|
||||
badgeValues.color = state ? upColor : downColor;
|
||||
badgeValues.message = label ?? state ? upLabel : downLabel;
|
||||
badgeValues.label = label ?? "Status";
|
||||
switch (state) {
|
||||
case DOWN:
|
||||
badgeValues.color = downColor;
|
||||
badgeValues.message = downLabel;
|
||||
break;
|
||||
case UP:
|
||||
badgeValues.color = upColor;
|
||||
badgeValues.message = upLabel;
|
||||
break;
|
||||
case PENDING:
|
||||
badgeValues.color = pendingColor;
|
||||
badgeValues.message = pendingLabel;
|
||||
break;
|
||||
case MAINTENANCE:
|
||||
badgeValues.color = maintenanceColor;
|
||||
badgeValues.message = maintenanceLabel;
|
||||
break;
|
||||
default:
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
badgeValues.message = "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
// build the svg based on given values
|
||||
@@ -189,7 +212,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
|
||||
const badgeValues = { style };
|
||||
|
||||
if (!publicMonitor) {
|
||||
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
|
||||
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
|
||||
badgeValues.message = "N/A";
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
} else {
|
||||
@@ -205,8 +228,11 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
|
||||
badgeValues.color = color ?? percentageToColor(uptime);
|
||||
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||
badgeValues.labelColor = labelColor ?? "";
|
||||
// build a lable string. If a custom label is given, override the default one (requestedDuration)
|
||||
badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
|
||||
// build a label string. If a custom label is given, override the default one (requestedDuration)
|
||||
badgeValues.label = filterAndJoin([
|
||||
labelPrefix,
|
||||
label ?? `Uptime (${requestedDuration}${labelSuffix})`,
|
||||
]);
|
||||
badgeValues.message = filterAndJoin([ prefix, `${cleanUptime * 100}`, suffix ]);
|
||||
}
|
||||
|
||||
@@ -267,7 +293,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
|
||||
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||
badgeValues.labelColor = labelColor ?? "";
|
||||
// build a lable string. If a custom label is given, override the default one (requestedDuration)
|
||||
badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
|
||||
badgeValues.label = filterAndJoin([ labelPrefix, label ?? `Avg. Ping (${requestedDuration}${labelSuffix})` ]);
|
||||
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
|
||||
}
|
||||
|
||||
@@ -281,4 +307,237 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/api/badge/:id/avg-response/:duration?", cache("5 minutes"), async (request, response) => {
|
||||
allowAllOrigin(response);
|
||||
|
||||
const {
|
||||
label,
|
||||
labelPrefix,
|
||||
labelSuffix,
|
||||
prefix,
|
||||
suffix = badgeConstants.defaultPingValueSuffix,
|
||||
color = badgeConstants.defaultPingColor,
|
||||
labelColor,
|
||||
style = badgeConstants.defaultStyle,
|
||||
value, // for demo purpose only
|
||||
} = request.query;
|
||||
|
||||
try {
|
||||
const requestedMonitorId = parseInt(request.params.id, 10);
|
||||
|
||||
// Default duration is 24 (h) if not defined in queryParam, limited to 720h (30d)
|
||||
const requestedDuration = Math.min(
|
||||
request.params.duration
|
||||
? parseInt(request.params.duration, 10)
|
||||
: 24,
|
||||
720
|
||||
);
|
||||
const overrideValue = value && parseFloat(value);
|
||||
|
||||
const publicAvgPing = parseInt(await R.getCell(`
|
||||
SELECT AVG(ping) FROM monitor_group, \`group\`, heartbeat
|
||||
WHERE monitor_group.group_id = \`group\`.id
|
||||
AND heartbeat.time > DATETIME('now', ? || ' hours')
|
||||
AND heartbeat.ping IS NOT NULL
|
||||
AND public = 1
|
||||
AND heartbeat.monitor_id = ?
|
||||
`,
|
||||
[ -requestedDuration, requestedMonitorId ]
|
||||
));
|
||||
|
||||
const badgeValues = { style };
|
||||
|
||||
if (!publicAvgPing) {
|
||||
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
|
||||
|
||||
badgeValues.message = "N/A";
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
} else {
|
||||
const avgPing = parseInt(overrideValue ?? publicAvgPing);
|
||||
|
||||
badgeValues.color = color;
|
||||
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||
badgeValues.labelColor = labelColor ?? "";
|
||||
// build a label string. If a custom label is given, override the default one (requestedDuration)
|
||||
badgeValues.label = filterAndJoin([
|
||||
labelPrefix,
|
||||
label ?? `Avg. Response (${requestedDuration}h)`,
|
||||
labelSuffix,
|
||||
]);
|
||||
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
|
||||
}
|
||||
|
||||
// build the SVG based on given values
|
||||
const svg = makeBadge(badgeValues);
|
||||
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/api/badge/:id/cert-exp", cache("5 minutes"), async (request, response) => {
|
||||
allowAllOrigin(response);
|
||||
|
||||
const date = request.query.date;
|
||||
|
||||
const {
|
||||
label,
|
||||
labelPrefix,
|
||||
labelSuffix,
|
||||
prefix,
|
||||
suffix = date ? "" : badgeConstants.defaultCertExpValueSuffix,
|
||||
upColor = badgeConstants.defaultUpColor,
|
||||
warnColor = badgeConstants.defaultWarnColor,
|
||||
downColor = badgeConstants.defaultDownColor,
|
||||
warnDays = badgeConstants.defaultCertExpireWarnDays,
|
||||
downDays = badgeConstants.defaultCertExpireDownDays,
|
||||
labelColor,
|
||||
style = badgeConstants.defaultStyle,
|
||||
value, // for demo purpose only
|
||||
} = request.query;
|
||||
|
||||
try {
|
||||
const requestedMonitorId = parseInt(request.params.id, 10);
|
||||
|
||||
const overrideValue = value && parseFloat(value);
|
||||
|
||||
let publicMonitor = await R.getRow(`
|
||||
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
||||
WHERE monitor_group.group_id = \`group\`.id
|
||||
AND monitor_group.monitor_id = ?
|
||||
AND public = 1
|
||||
`,
|
||||
[ requestedMonitorId ]
|
||||
);
|
||||
|
||||
const badgeValues = { style };
|
||||
|
||||
if (!publicMonitor) {
|
||||
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
|
||||
|
||||
badgeValues.message = "N/A";
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
} else {
|
||||
const tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
|
||||
requestedMonitorId,
|
||||
]);
|
||||
|
||||
if (!tlsInfoBean) {
|
||||
// return a "No/Bad Cert" badge in naColor (grey), if no cert saved (does not save bad certs?)
|
||||
badgeValues.message = "No/Bad Cert";
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
} else {
|
||||
const tlsInfo = JSON.parse(tlsInfoBean.info_json);
|
||||
|
||||
if (!tlsInfo.valid) {
|
||||
// return a "Bad Cert" badge in naColor (grey), when cert is not valid
|
||||
badgeValues.message = "Bad Cert";
|
||||
badgeValues.color = badgeConstants.downColor;
|
||||
} else {
|
||||
const daysRemaining = parseInt(overrideValue ?? tlsInfo.certInfo.daysRemaining);
|
||||
|
||||
if (daysRemaining > warnDays) {
|
||||
badgeValues.color = upColor;
|
||||
} else if (daysRemaining > downDays) {
|
||||
badgeValues.color = warnColor;
|
||||
} else {
|
||||
badgeValues.color = downColor;
|
||||
}
|
||||
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||
badgeValues.labelColor = labelColor ?? "";
|
||||
// build a label string. If a custom label is given, override the default one
|
||||
badgeValues.label = filterAndJoin([
|
||||
labelPrefix,
|
||||
label ?? "Cert Exp.",
|
||||
labelSuffix,
|
||||
]);
|
||||
badgeValues.message = filterAndJoin([ prefix, date ? tlsInfo.certInfo.validTo : daysRemaining, suffix ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build the SVG based on given values
|
||||
const svg = makeBadge(badgeValues);
|
||||
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/api/badge/:id/response", cache("5 minutes"), async (request, response) => {
|
||||
allowAllOrigin(response);
|
||||
|
||||
const {
|
||||
label,
|
||||
labelPrefix,
|
||||
labelSuffix,
|
||||
prefix,
|
||||
suffix = badgeConstants.defaultPingValueSuffix,
|
||||
color = badgeConstants.defaultPingColor,
|
||||
labelColor,
|
||||
style = badgeConstants.defaultStyle,
|
||||
value, // for demo purpose only
|
||||
} = request.query;
|
||||
|
||||
try {
|
||||
const requestedMonitorId = parseInt(request.params.id, 10);
|
||||
|
||||
const overrideValue = value && parseFloat(value);
|
||||
|
||||
let publicMonitor = await R.getRow(`
|
||||
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
||||
WHERE monitor_group.group_id = \`group\`.id
|
||||
AND monitor_group.monitor_id = ?
|
||||
AND public = 1
|
||||
`,
|
||||
[ requestedMonitorId ]
|
||||
);
|
||||
|
||||
const badgeValues = { style };
|
||||
|
||||
if (!publicMonitor) {
|
||||
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
|
||||
|
||||
badgeValues.message = "N/A";
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
} else {
|
||||
const heartbeat = await Monitor.getPreviousHeartbeat(
|
||||
requestedMonitorId
|
||||
);
|
||||
|
||||
if (!heartbeat.ping) {
|
||||
// return a "N/A" badge in naColor (grey), if previous heartbeat has no ping
|
||||
|
||||
badgeValues.message = "N/A";
|
||||
badgeValues.color = badgeConstants.naColor;
|
||||
} else {
|
||||
const ping = parseInt(overrideValue ?? heartbeat.ping);
|
||||
|
||||
badgeValues.color = color;
|
||||
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||
badgeValues.labelColor = labelColor ?? "";
|
||||
// build a label string. If a custom label is given, override the default one
|
||||
badgeValues.label = filterAndJoin([
|
||||
labelPrefix,
|
||||
label ?? "Response",
|
||||
labelSuffix,
|
||||
]);
|
||||
badgeValues.message = filterAndJoin([ prefix, ping, suffix ]);
|
||||
}
|
||||
}
|
||||
|
||||
// build the SVG based on given values
|
||||
const svg = makeBadge(badgeValues);
|
||||
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
@@ -8,9 +8,12 @@ console.log("Welcome to Uptime Kuma");
|
||||
// As the log function need to use dayjs, it should be very top
|
||||
const dayjs = require("dayjs");
|
||||
dayjs.extend(require("dayjs/plugin/utc"));
|
||||
dayjs.extend(require("dayjs/plugin/timezone"));
|
||||
dayjs.extend(require("./modules/dayjs/plugin/timezone"));
|
||||
dayjs.extend(require("dayjs/plugin/customParseFormat"));
|
||||
|
||||
// Load environment variables from `.env`
|
||||
require("dotenv").config();
|
||||
|
||||
// Check Node.js Version
|
||||
const nodeVersion = parseInt(process.versions.node.split(".")[0]);
|
||||
const requiredVersion = 14;
|
||||
@@ -135,7 +138,10 @@ const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudfl
|
||||
const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler");
|
||||
const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler");
|
||||
const { maintenanceSocketHandler } = require("./socket-handlers/maintenance-socket-handler");
|
||||
const { generalSocketHandler } = require("./socket-handlers/general-socket-handler");
|
||||
const { Settings } = require("./settings");
|
||||
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
|
||||
const { pluginsHandler } = require("./socket-handlers/plugins-handler");
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
@@ -164,7 +170,7 @@ let needSetup = false;
|
||||
Database.init(args);
|
||||
await initDatabase(testMode);
|
||||
await server.initAfterDatabaseReady();
|
||||
|
||||
server.loadPlugins();
|
||||
server.entryPage = await Settings.get("entryPage");
|
||||
await StatusPage.loadDomainMappingList();
|
||||
|
||||
@@ -572,7 +578,6 @@ let needSetup = false;
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: error.message,
|
||||
@@ -632,6 +637,9 @@ let needSetup = false;
|
||||
|
||||
bean.import(monitor);
|
||||
bean.user_id = socket.userID;
|
||||
|
||||
bean.validate();
|
||||
|
||||
await R.store(bean);
|
||||
|
||||
await updateMonitorNotification(bean.id, notificationIDList);
|
||||
@@ -684,12 +692,14 @@ let needSetup = false;
|
||||
bean.retryInterval = monitor.retryInterval;
|
||||
bean.resendInterval = monitor.resendInterval;
|
||||
bean.hostname = monitor.hostname;
|
||||
bean.game = monitor.game;
|
||||
bean.maxretries = monitor.maxretries;
|
||||
bean.port = parseInt(monitor.port);
|
||||
bean.keyword = monitor.keyword;
|
||||
bean.ignoreTls = monitor.ignoreTls;
|
||||
bean.expiryNotification = monitor.expiryNotification;
|
||||
bean.upsideDown = monitor.upsideDown;
|
||||
bean.packetSize = monitor.packetSize;
|
||||
bean.maxredirects = monitor.maxredirects;
|
||||
bean.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes);
|
||||
bean.dns_resolve_type = monitor.dns_resolve_type;
|
||||
@@ -709,6 +719,7 @@ let needSetup = false;
|
||||
bean.authDomain = monitor.authDomain;
|
||||
bean.grpcUrl = monitor.grpcUrl;
|
||||
bean.grpcProtobuf = monitor.grpcProtobuf;
|
||||
bean.grpcServiceName = monitor.grpcServiceName;
|
||||
bean.grpcMethod = monitor.grpcMethod;
|
||||
bean.grpcBody = monitor.grpcBody;
|
||||
bean.grpcMetadata = monitor.grpcMetadata;
|
||||
@@ -719,6 +730,8 @@ let needSetup = false;
|
||||
bean.radiusCallingStationId = monitor.radiusCallingStationId;
|
||||
bean.radiusSecret = monitor.radiusSecret;
|
||||
|
||||
bean.validate();
|
||||
|
||||
await R.store(bean);
|
||||
|
||||
await updateMonitorNotification(bean.id, monitor.notificationIDList);
|
||||
@@ -933,13 +946,21 @@ let needSetup = false;
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
let bean = await R.findOne("monitor", " id = ? ", [ tag.id ]);
|
||||
let bean = await R.findOne("tag", " id = ? ", [ tag.id ]);
|
||||
if (bean == null) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: "Tag not found",
|
||||
});
|
||||
return;
|
||||
}
|
||||
bean.name = tag.name;
|
||||
bean.color = tag.color;
|
||||
await R.store(bean);
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Saved",
|
||||
tag: await bean.toJSON(),
|
||||
});
|
||||
|
||||
@@ -1109,6 +1130,8 @@ let needSetup = false;
|
||||
await setSettings("general", data);
|
||||
server.entryPage = data.entryPage;
|
||||
|
||||
await CacheableDnsHttpAgent.update();
|
||||
|
||||
// Also need to apply timezone globally
|
||||
if (data.serverTimezone) {
|
||||
await server.setTimezone(data.serverTimezone);
|
||||
@@ -1480,6 +1503,8 @@ let needSetup = false;
|
||||
proxySocketHandler(socket);
|
||||
dockerSocketHandler(socket);
|
||||
maintenanceSocketHandler(socket);
|
||||
generalSocketHandler(socket, server);
|
||||
pluginsHandler(socket, server);
|
||||
|
||||
log.debug("server", "added all socket handlers");
|
||||
|
||||
@@ -1602,6 +1627,13 @@ async function afterLogin(socket, user) {
|
||||
for (let monitorID in monitorList) {
|
||||
await Monitor.sendStats(io, monitorID, user.id);
|
||||
}
|
||||
|
||||
// Set server timezone from client browser if not set
|
||||
// It should be run once only
|
||||
if (! await Settings.get("initServerTimezone")) {
|
||||
log.debug("server", "emit initServerTimezone");
|
||||
socket.emit("initServerTimezone");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1740,6 +1772,7 @@ async function shutdownFunction(signal) {
|
||||
|
||||
stopBackgroundJobs();
|
||||
await cloudflaredStop();
|
||||
Settings.stopCacheCleaner();
|
||||
}
|
||||
|
||||
/** Final function called before application exits */
|
||||
|
@@ -158,6 +158,13 @@ class Settings {
|
||||
delete Settings.cacheList[key];
|
||||
}
|
||||
}
|
||||
|
||||
static stopCacheCleaner() {
|
||||
if (Settings.cacheCleaner) {
|
||||
clearInterval(Settings.cacheCleaner);
|
||||
Settings.cacheCleaner = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
const { checkLogin, setSetting, setting, doubleCheckPassword } = require("../util-server");
|
||||
const { CloudflaredTunnel } = require("node-cloudflared-tunnel");
|
||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||
const { log } = require("../../src/util");
|
||||
const io = UptimeKumaServer.getInstance().io;
|
||||
|
||||
const prefix = "cloudflared_";
|
||||
@@ -107,7 +108,7 @@ module.exports.autoStart = async (token) => {
|
||||
|
||||
/** Stop cloudflared */
|
||||
module.exports.stop = async () => {
|
||||
console.log("Stop cloudflared");
|
||||
log.info("cloudflared", "Stop cloudflared");
|
||||
if (cloudflared) {
|
||||
cloudflared.stop();
|
||||
}
|
||||
|
51
server/socket-handlers/general-socket-handler.js
Normal file
51
server/socket-handlers/general-socket-handler.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const { log } = require("../../src/util");
|
||||
const { Settings } = require("../settings");
|
||||
const { sendInfo } = require("../client");
|
||||
const { checkLogin } = require("../util-server");
|
||||
const GameResolver = require("gamedig/lib/GameResolver");
|
||||
|
||||
let gameResolver = new GameResolver();
|
||||
let gameList = null;
|
||||
|
||||
/**
|
||||
* Get a game list via GameDig
|
||||
* @returns {any[]}
|
||||
*/
|
||||
function getGameList() {
|
||||
if (!gameList) {
|
||||
gameList = gameResolver._readGames().games.sort((a, b) => {
|
||||
if ( a.pretty < b.pretty ) {
|
||||
return -1;
|
||||
}
|
||||
if ( a.pretty > b.pretty ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
return gameList;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.generalSocketHandler = (socket, server) => {
|
||||
|
||||
socket.on("initServerTimezone", async (timezone) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
log.debug("generalSocketHandler", "Timezone: " + timezone);
|
||||
await Settings.set("initServerTimezone", true);
|
||||
await server.setTimezone(timezone);
|
||||
await sendInfo(socket);
|
||||
} catch (e) {
|
||||
log.warn("initServerTimezone", e.message);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("getGameList", async (callback) => {
|
||||
callback({
|
||||
ok: true,
|
||||
gameList: getGameList(),
|
||||
});
|
||||
});
|
||||
|
||||
};
|
@@ -244,6 +244,8 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||
socket.userID,
|
||||
]);
|
||||
|
||||
apicache.clear();
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Deleted Successfully.",
|
||||
@@ -269,6 +271,8 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||
maintenanceID,
|
||||
]);
|
||||
|
||||
apicache.clear();
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Paused Successfully.",
|
||||
@@ -294,6 +298,8 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||
maintenanceID,
|
||||
]);
|
||||
|
||||
apicache.clear();
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Resume Successfully",
|
||||
|
69
server/socket-handlers/plugins-handler.js
Normal file
69
server/socket-handlers/plugins-handler.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const { checkLogin } = require("../util-server");
|
||||
const { PluginsManager } = require("../plugins-manager");
|
||||
const { log } = require("../../src/util.js");
|
||||
|
||||
/**
|
||||
* Handlers for plugins
|
||||
* @param {Socket} socket Socket.io instance
|
||||
* @param {UptimeKumaServer} server
|
||||
*/
|
||||
module.exports.pluginsHandler = (socket, server) => {
|
||||
|
||||
const pluginManager = server.getPluginManager();
|
||||
|
||||
// Get Plugin List
|
||||
socket.on("getPluginList", async (callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
log.debug("plugin", "PluginManager.disable: " + PluginsManager.disable);
|
||||
|
||||
if (PluginsManager.disable) {
|
||||
throw new Error("Plugin Disabled: In order to enable plugin feature, you need to use the default data directory: ./data/");
|
||||
}
|
||||
|
||||
let pluginList = await pluginManager.fetchPluginList();
|
||||
callback({
|
||||
ok: true,
|
||||
pluginList,
|
||||
});
|
||||
} catch (error) {
|
||||
log.warn("plugin", "Error: " + error.message);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("installPlugin", async (repoURL, name, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
pluginManager.downloadPlugin(repoURL, name);
|
||||
await pluginManager.loadPlugin(name);
|
||||
callback({
|
||||
ok: true,
|
||||
});
|
||||
} catch (error) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("uninstallPlugin", async (name, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
await pluginManager.removePlugin(name);
|
||||
callback({
|
||||
ok: true,
|
||||
});
|
||||
} catch (error) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
49
server/uptime-cache-list.js
Normal file
49
server/uptime-cache-list.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const { log } = require("../src/util");
|
||||
class UptimeCacheList {
|
||||
/**
|
||||
* list[monitorID][duration]
|
||||
*/
|
||||
static list = {};
|
||||
|
||||
/**
|
||||
* Get the uptime for a specific period
|
||||
* @param {number} monitorID
|
||||
* @param {number} duration
|
||||
* @return {number}
|
||||
*/
|
||||
static getUptime(monitorID, duration) {
|
||||
if (UptimeCacheList.list[monitorID] && UptimeCacheList.list[monitorID][duration]) {
|
||||
log.debug("UptimeCacheList", "getUptime: " + monitorID + " " + duration);
|
||||
return UptimeCacheList.list[monitorID][duration];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add uptime for specified monitor
|
||||
* @param {number} monitorID
|
||||
* @param {number} duration
|
||||
* @param {number} uptime Uptime to add
|
||||
*/
|
||||
static addUptime(monitorID, duration, uptime) {
|
||||
log.debug("UptimeCacheList", "addUptime: " + monitorID + " " + duration);
|
||||
if (!UptimeCacheList.list[monitorID]) {
|
||||
UptimeCacheList.list[monitorID] = {};
|
||||
}
|
||||
UptimeCacheList.list[monitorID][duration] = uptime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache for specified monitor
|
||||
* @param {number} monitorID
|
||||
*/
|
||||
static clearCache(monitorID) {
|
||||
log.debug("UptimeCacheList", "clearCache: " + monitorID);
|
||||
delete UptimeCacheList.list[monitorID];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
UptimeCacheList,
|
||||
};
|
@@ -10,6 +10,7 @@ const util = require("util");
|
||||
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
|
||||
const { Settings } = require("./settings");
|
||||
const dayjs = require("dayjs");
|
||||
const { PluginsManager } = require("./plugins-manager");
|
||||
// DO NOT IMPORT HERE IF THE MODULES USED `UptimeKumaServer.getInstance()`
|
||||
|
||||
/**
|
||||
@@ -48,6 +49,20 @@ class UptimeKumaServer {
|
||||
|
||||
generateMaintenanceTimeslotsInterval = undefined;
|
||||
|
||||
/**
|
||||
* Plugins Manager
|
||||
* @type {PluginsManager}
|
||||
*/
|
||||
pluginsManager = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {{}}
|
||||
*/
|
||||
static monitorTypeList = {
|
||||
|
||||
};
|
||||
|
||||
static getInstance(args) {
|
||||
if (UptimeKumaServer.instance == null) {
|
||||
UptimeKumaServer.instance = new UptimeKumaServer(args);
|
||||
@@ -83,12 +98,13 @@ class UptimeKumaServer {
|
||||
}
|
||||
}
|
||||
|
||||
CacheableDnsHttpAgent.registerGlobalAgent();
|
||||
|
||||
this.io = new Server(this.httpServer);
|
||||
}
|
||||
|
||||
/** Initialise app after the database has been set up */
|
||||
async initAfterDatabaseReady() {
|
||||
await CacheableDnsHttpAgent.update();
|
||||
|
||||
process.env.TZ = await this.getTimezone();
|
||||
dayjs.tz.setDefault(process.env.TZ);
|
||||
log.debug("DEBUG", "Timezone: " + process.env.TZ);
|
||||
@@ -98,6 +114,11 @@ class UptimeKumaServer {
|
||||
this.generateMaintenanceTimeslotsInterval = setInterval(this.generateMaintenanceTimeslots, 60 * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send list of monitors to client
|
||||
* @param {Socket} socket
|
||||
* @returns {Object} List of monitors
|
||||
*/
|
||||
async sendMonitorList(socket) {
|
||||
let list = await this.getMonitorJSONList(socket.userID);
|
||||
this.io.to(socket.userID).emit("monitorList", list);
|
||||
@@ -134,6 +155,11 @@ class UptimeKumaServer {
|
||||
return await this.sendMaintenanceListByUserID(socket.userID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send list of maintenances to user
|
||||
* @param {number} userID
|
||||
* @returns {Object}
|
||||
*/
|
||||
async sendMaintenanceListByUserID(userID) {
|
||||
let list = await this.getMaintenanceJSONList(userID);
|
||||
this.io.to(userID).emit("maintenanceList", list);
|
||||
@@ -185,6 +211,11 @@ class UptimeKumaServer {
|
||||
errorLogStream.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP of the client connected to the socket
|
||||
* @param {Socket} socket
|
||||
* @returns {string}
|
||||
*/
|
||||
async getClientIP(socket) {
|
||||
let clientIP = socket.client.conn.remoteAddress;
|
||||
|
||||
@@ -203,6 +234,12 @@ class UptimeKumaServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the current server timezone
|
||||
* If this fails, fall back to environment variables and then make a
|
||||
* guess.
|
||||
* @returns {string}
|
||||
*/
|
||||
async getTimezone() {
|
||||
let timezone = await Settings.get("serverTimezone");
|
||||
if (timezone) {
|
||||
@@ -214,16 +251,25 @@ class UptimeKumaServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current offset
|
||||
* @returns {string}
|
||||
*/
|
||||
getTimezoneOffset() {
|
||||
return dayjs().format("Z");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current server timezone and environment variables
|
||||
* @param {string} timezone
|
||||
*/
|
||||
async setTimezone(timezone) {
|
||||
await Settings.set("serverTimezone", timezone, "general");
|
||||
process.env.TZ = timezone;
|
||||
dayjs.tz.setDefault(timezone);
|
||||
}
|
||||
|
||||
/** Load the timeslots for maintenance */
|
||||
async generateMaintenanceTimeslots() {
|
||||
|
||||
let list = await R.find("maintenance_timeslot", " generated_next = 0 AND start_date <= DATETIME('now') ");
|
||||
@@ -237,9 +283,50 @@ class UptimeKumaServer {
|
||||
|
||||
}
|
||||
|
||||
/** Stop the server */
|
||||
async stop() {
|
||||
clearTimeout(this.generateMaintenanceTimeslotsInterval);
|
||||
}
|
||||
|
||||
loadPlugins() {
|
||||
this.pluginsManager = new PluginsManager(this);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {PluginsManager}
|
||||
*/
|
||||
getPluginManager() {
|
||||
return this.pluginsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {MonitorType} monitorType
|
||||
*/
|
||||
addMonitorType(monitorType) {
|
||||
if (monitorType instanceof MonitorType && monitorType.name) {
|
||||
if (monitorType.name in UptimeKumaServer.monitorTypeList) {
|
||||
log.error("", "Conflict Monitor Type name");
|
||||
}
|
||||
UptimeKumaServer.monitorTypeList[monitorType.name] = monitorType;
|
||||
} else {
|
||||
log.error("", "Invalid Monitor Type: " + monitorType.name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {MonitorType} monitorType
|
||||
*/
|
||||
removeMonitorType(monitorType) {
|
||||
if (UptimeKumaServer.monitorTypeList[monitorType.name] === monitorType) {
|
||||
delete UptimeKumaServer.monitorTypeList[monitorType.name];
|
||||
} else {
|
||||
log.error("", "Remove MonitorType failed: " + monitorType.name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -248,3 +335,4 @@ module.exports = {
|
||||
|
||||
// Must be at the end
|
||||
const MaintenanceTimeslot = require("./model/maintenance_timeslot");
|
||||
const { MonitorType } = require("./monitor-types/monitor-type");
|
||||
|
@@ -1,5 +1,5 @@
|
||||
const tcpp = require("tcp-ping");
|
||||
const Ping = require("./ping-lite");
|
||||
const ping = require("@louislam/ping");
|
||||
const { R } = require("redbean-node");
|
||||
const { log, genSecret } = require("../src/util");
|
||||
const passwordHash = require("./password-hash");
|
||||
@@ -14,11 +14,13 @@ const mssql = require("mssql");
|
||||
const { Client } = require("pg");
|
||||
const postgresConParse = require("pg-connection-string").parse;
|
||||
const mysql = require("mysql2");
|
||||
const { MongoClient } = require("mongodb");
|
||||
const { NtlmClient } = require("axios-ntlm");
|
||||
const { Settings } = require("./settings");
|
||||
const grpc = require("@grpc/grpc-js");
|
||||
const protojs = require("protobufjs");
|
||||
const radiusClient = require("node-radius-client");
|
||||
const redis = require("redis");
|
||||
const {
|
||||
dictionaries: {
|
||||
rfc2865: { file, attributes },
|
||||
@@ -26,12 +28,7 @@ const {
|
||||
} = require("node-radius-utils");
|
||||
const dayjs = require("dayjs");
|
||||
|
||||
// From ping-lite
|
||||
exports.WIN = /^win/.test(process.platform);
|
||||
exports.LIN = /^linux/.test(process.platform);
|
||||
exports.MAC = /^darwin/.test(process.platform);
|
||||
exports.FBSD = /^freebsd/.test(process.platform);
|
||||
exports.BSD = /bsd$/.test(process.platform);
|
||||
const isWindows = process.platform === /^win/.test(process.platform);
|
||||
|
||||
/**
|
||||
* Init or reset JWT secret
|
||||
@@ -82,15 +79,16 @@ exports.tcping = function (hostname, port) {
|
||||
/**
|
||||
* Ping the specified machine
|
||||
* @param {string} hostname Hostname / address of machine
|
||||
* @param {number} [size=56] Size of packet to send
|
||||
* @returns {Promise<number>} Time for ping in ms rounded to nearest integer
|
||||
*/
|
||||
exports.ping = async (hostname) => {
|
||||
exports.ping = async (hostname, size = 56) => {
|
||||
try {
|
||||
return await exports.pingAsync(hostname);
|
||||
return await exports.pingAsync(hostname, false, size);
|
||||
} catch (e) {
|
||||
// If the host cannot be resolved, try again with ipv6
|
||||
if (e.message.includes("service not known")) {
|
||||
return await exports.pingAsync(hostname, true);
|
||||
return await exports.pingAsync(hostname, true, size);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
@@ -101,22 +99,29 @@ exports.ping = async (hostname) => {
|
||||
* Ping the specified machine
|
||||
* @param {string} hostname Hostname / address of machine to ping
|
||||
* @param {boolean} ipv6 Should IPv6 be used?
|
||||
* @param {number} [size = 56] Size of ping packet to send
|
||||
* @returns {Promise<number>} Time for ping in ms rounded to nearest integer
|
||||
*/
|
||||
exports.pingAsync = function (hostname, ipv6 = false) {
|
||||
exports.pingAsync = function (hostname, ipv6 = false, size = 56) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ping = new Ping(hostname, {
|
||||
ipv6
|
||||
});
|
||||
|
||||
ping.send(function (err, ms, stdout) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else if (ms === null) {
|
||||
reject(new Error(stdout));
|
||||
ping.promise.probe(hostname, {
|
||||
v6: ipv6,
|
||||
min_reply: 1,
|
||||
deadline: 10,
|
||||
packetSize: size,
|
||||
}).then((res) => {
|
||||
// If ping failed, it will set field to unknown
|
||||
if (res.alive) {
|
||||
resolve(res.time);
|
||||
} else {
|
||||
resolve(Math.round(ms));
|
||||
if (isWindows) {
|
||||
reject(new Error(exports.convertToUTF8(res.output)));
|
||||
} else {
|
||||
reject(new Error(res.output));
|
||||
}
|
||||
}
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -135,7 +140,7 @@ exports.mqttAsync = function (hostname, topic, okMessage, options = {}) {
|
||||
const { port, username, password, interval = 20 } = options;
|
||||
|
||||
// Adds MQTT protocol to the hostname if not already present
|
||||
if (!/^(?:http|mqtt)s?:\/\//.test(hostname)) {
|
||||
if (!/^(?:http|mqtt|ws)s?:\/\//.test(hostname)) {
|
||||
hostname = "mqtt://" + hostname;
|
||||
}
|
||||
|
||||
@@ -145,10 +150,11 @@ exports.mqttAsync = function (hostname, topic, okMessage, options = {}) {
|
||||
reject(new Error("Timeout"));
|
||||
}, interval * 1000 * 0.8);
|
||||
|
||||
log.debug("mqtt", "MQTT connecting");
|
||||
const mqttUrl = `${hostname}:${port}`;
|
||||
|
||||
let client = mqtt.connect(hostname, {
|
||||
port,
|
||||
log.debug("mqtt", `MQTT connecting to ${mqttUrl}`);
|
||||
|
||||
let client = mqtt.connect(mqttUrl, {
|
||||
username,
|
||||
password
|
||||
});
|
||||
@@ -248,19 +254,19 @@ exports.dnsResolve = function (hostname, resolverServer, resolverPort, rrtype) {
|
||||
* @param {string} query The query to validate the database with
|
||||
* @returns {Promise<(string[]|Object[]|Object)>}
|
||||
*/
|
||||
exports.mssqlQuery = function (connectionString, query) {
|
||||
return new Promise((resolve, reject) => {
|
||||
mssql.connect(connectionString).then(pool => {
|
||||
return pool.request()
|
||||
.query(query);
|
||||
}).then(result => {
|
||||
resolve(result);
|
||||
}).catch(err => {
|
||||
reject(err);
|
||||
}).finally(() => {
|
||||
mssql.close();
|
||||
});
|
||||
});
|
||||
exports.mssqlQuery = async function (connectionString, query) {
|
||||
let pool;
|
||||
try {
|
||||
pool = new mssql.ConnectionPool(connectionString);
|
||||
await pool.connect();
|
||||
await pool.request().query(query);
|
||||
pool.close();
|
||||
} catch (e) {
|
||||
if (pool) {
|
||||
pool.close();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -280,18 +286,23 @@ exports.postgresQuery = function (connectionString, query) {
|
||||
|
||||
const client = new Client({ connectionString });
|
||||
|
||||
client.connect();
|
||||
|
||||
return client.query(query)
|
||||
.then(res => {
|
||||
resolve(res);
|
||||
})
|
||||
.catch(err => {
|
||||
client.connect((err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
})
|
||||
.finally(() => {
|
||||
client.end();
|
||||
});
|
||||
} else {
|
||||
// Connected here
|
||||
client.query(query, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
client.end();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -317,6 +328,23 @@ exports.mysqlQuery = function (connectionString, query) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Connect to and Ping a MongoDB database
|
||||
* @param {string} connectionString The database connection string
|
||||
* @returns {Promise<(string[]|Object[]|Object)>}
|
||||
*/
|
||||
exports.mongodbPing = async function (connectionString) {
|
||||
let client = await MongoClient.connect(connectionString);
|
||||
let dbPing = await client.db().command({ ping: 1 });
|
||||
await client.close();
|
||||
|
||||
if (dbPing["ok"] === 1) {
|
||||
return "UP";
|
||||
} else {
|
||||
throw Error("failed");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Query radius server
|
||||
* @param {string} hostname Hostname of radius server
|
||||
@@ -354,6 +382,30 @@ exports.radius = function (
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Redis server ping
|
||||
* @param {string} dsn The redis connection string
|
||||
*/
|
||||
exports.redisPingAsync = function (dsn) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = redis.createClient({
|
||||
url: dsn,
|
||||
});
|
||||
client.on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
client.connect().then(() => {
|
||||
client.ping().then((res, err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve value of setting based on key
|
||||
* @param {string} key Key of setting to retrieve
|
||||
@@ -470,6 +522,10 @@ const parseCertificateInfo = function (info) {
|
||||
* @returns {Object} Object containing certificate information
|
||||
*/
|
||||
exports.checkCertificate = function (res) {
|
||||
if (!res.request.res.socket) {
|
||||
throw new Error("No socket found");
|
||||
}
|
||||
|
||||
const info = res.request.res.socket.getPeerCertificate(true);
|
||||
const valid = res.request.res.socket.authorized || false;
|
||||
|
||||
@@ -774,22 +830,31 @@ module.exports.grpcQuery = async (options) => {
|
||||
cb);
|
||||
}, false, false);
|
||||
return new Promise((resolve, _) => {
|
||||
return grpcService[`${grpcMethod}`](JSON.parse(grpcBody), function (err, response) {
|
||||
const responseData = JSON.stringify(response);
|
||||
if (err) {
|
||||
return resolve({
|
||||
code: err.code,
|
||||
errorMessage: err.details,
|
||||
data: ""
|
||||
});
|
||||
} else {
|
||||
log.debug("monitor:", `gRPC response: ${response}`);
|
||||
return resolve({
|
||||
code: 1,
|
||||
errorMessage: "",
|
||||
data: responseData
|
||||
});
|
||||
}
|
||||
});
|
||||
try {
|
||||
return grpcService[`${grpcMethod}`](JSON.parse(grpcBody), function (err, response) {
|
||||
const responseData = JSON.stringify(response);
|
||||
if (err) {
|
||||
return resolve({
|
||||
code: err.code,
|
||||
errorMessage: err.details,
|
||||
data: ""
|
||||
});
|
||||
} else {
|
||||
log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`);
|
||||
return resolve({
|
||||
code: 1,
|
||||
errorMessage: "",
|
||||
data: responseData
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
return resolve({
|
||||
code: -1,
|
||||
errorMessage: `Error ${err}. Please review your gRPC configuration option. The service name must not include package name value, and the method name must follow camelCase format`,
|
||||
data: ""
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
@@ -35,6 +35,11 @@ textarea.form-control {
|
||||
color: $maintenance !important;
|
||||
}
|
||||
|
||||
.incident a,
|
||||
.bg-maintenance a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
border-radius: 0.75rem;
|
||||
|
||||
@@ -248,6 +253,11 @@ optgroup {
|
||||
}
|
||||
}
|
||||
|
||||
.incident a,
|
||||
.bg-maintenance a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-control:focus,
|
||||
.form-select,
|
||||
|
@@ -2,4 +2,8 @@ html[lang='fa'] {
|
||||
#app {
|
||||
font-family: 'IRANSans', 'Iranian Sans','B Nazanin', 'Tahoma', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul.multiselect__content {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ export default {
|
||||
emits: [ "added" ],
|
||||
data() {
|
||||
return {
|
||||
model: null,
|
||||
modal: null,
|
||||
processing: false,
|
||||
id: null,
|
||||
connectionTypes: [ "socket", "tcp" ],
|
||||
@@ -91,11 +91,16 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
|
||||
/** Confirm deletion of docker host */
|
||||
deleteConfirm() {
|
||||
this.modal.hide();
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show specified docker host
|
||||
* @param {number} dockerHostID
|
||||
*/
|
||||
show(dockerHostID) {
|
||||
if (dockerHostID) {
|
||||
let found = false;
|
||||
@@ -126,6 +131,7 @@ export default {
|
||||
this.modal.show();
|
||||
},
|
||||
|
||||
/** Add docker host */
|
||||
submit() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("addDockerHost", this.dockerHost, this.id, (res) => {
|
||||
@@ -144,6 +150,7 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Test the docker host */
|
||||
test() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("testDockerHost", this.dockerHost, (res) => {
|
||||
@@ -152,6 +159,7 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** Delete this docker host */
|
||||
deleteDockerHost() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("deleteDockerHost", this.id, (res) => {
|
||||
|
@@ -213,7 +213,7 @@ export default {
|
||||
transition: all ease-in-out 0.1s;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
102
src/components/PluginItem.vue
Normal file
102
src/components/PluginItem.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div v-if="! (!plugin.installed && plugin.local)" class="plugin-item pt-4 pb-2">
|
||||
<div class="info">
|
||||
<h5>{{ plugin.fullName }}</h5>
|
||||
<p class="description">
|
||||
{{ plugin.description }}
|
||||
</p>
|
||||
<span class="version">{{ $t("Version") }}: {{ plugin.version }} <a v-if="plugin.repo" :href="plugin.repo" target="_blank">Repo</a></span>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button v-if="status === 'installing'" class="btn btn-primary" disabled>{{ $t("installing") }}</button>
|
||||
<button v-else-if="status === 'uninstalling'" class="btn btn-danger" disabled>{{ $t("uninstalling") }}</button>
|
||||
<button v-else-if="plugin.installed || status === 'installed'" class="btn btn-danger" @click="deleteConfirm">{{ $t("uninstall") }}</button>
|
||||
<button v-else class="btn btn-primary" @click="install">{{ $t("install") }}</button>
|
||||
</div>
|
||||
|
||||
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="uninstall">
|
||||
{{ $t("confirmUninstallPlugin") }}
|
||||
</Confirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Confirm from "./Confirm.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Confirm,
|
||||
},
|
||||
props: {
|
||||
plugin: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
status: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Show confirmation for deleting a tag
|
||||
*/
|
||||
deleteConfirm() {
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
install() {
|
||||
this.status = "installing";
|
||||
|
||||
this.$root.getSocket().emit("installPlugin", this.plugin.repo, this.plugin.name, (res) => {
|
||||
if (res.ok) {
|
||||
this.status = "";
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.plugin.installed = true;
|
||||
} else {
|
||||
this.$root.toastRes(res);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
uninstall() {
|
||||
this.status = "uninstalling";
|
||||
|
||||
this.$root.getSocket().emit("uninstallPlugin", this.plugin.name, (res) => {
|
||||
if (res.ok) {
|
||||
this.status = "";
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.plugin.installed = false;
|
||||
} else {
|
||||
this.$root.toastRes(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../assets/vars.scss";
|
||||
|
||||
.plugin-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
|
||||
.info {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 13px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.version {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -41,7 +41,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
displayText() {
|
||||
if (this.item.value === "") {
|
||||
if (this.item.value === "" || this.item.value === undefined) {
|
||||
return this.item.name;
|
||||
} else {
|
||||
return `${this.item.name}: ${this.item.value}`;
|
||||
|
376
src/components/TagEditDialog.vue
Normal file
376
src/components/TagEditDialog.vue
Normal file
@@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<form @submit.prevent="submit">
|
||||
<div ref="modal" class="modal fade" tabindex="-1" data-bs-backdrop="static">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ $t("Edit Tag") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="tag-name" class="form-label">{{ $t("Name") }}</label>
|
||||
<input id="tag-name" v-model="tag.name" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="tag-color" class="form-label">{{ $t("color") }}</label>
|
||||
<div class="d-flex">
|
||||
<div class="col-8 pe-1">
|
||||
<vue-multiselect
|
||||
v-model="selectedColor"
|
||||
:options="colorOptions"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('color')"
|
||||
track-by="color"
|
||||
label="name"
|
||||
select-label=""
|
||||
deselect-label=""
|
||||
>
|
||||
<template #option="{ option }">
|
||||
<div
|
||||
class="mx-2 py-1 px-3 rounded d-inline-flex"
|
||||
style="height: 24px; color: white;"
|
||||
:style="{ backgroundColor: option.color + ' !important' }"
|
||||
>
|
||||
<span>{{ option.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #singleLabel="{ option }">
|
||||
<div
|
||||
class="py-1 px-3 rounded d-inline-flex"
|
||||
style="height: 24px; color: white;"
|
||||
:style="{ backgroundColor: option.color + ' !important' }"
|
||||
>
|
||||
<span>{{ option.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</vue-multiselect>
|
||||
</div>
|
||||
<div class="col-4 ps-1">
|
||||
<input id="tag-color-hex" v-model="tag.color" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="tag-monitors" class="form-label">{{ $tc("Monitor", selectedMonitors.length) }}</label>
|
||||
<div class="tag-monitors-list">
|
||||
<router-link v-for="monitor in selectedMonitors" :key="monitor.id" class="d-flex align-items-center justify-content-between text-decoration-none tag-monitors-list-row py-2 px-3" :to="monitorURL(monitor.id)" @click="modal.hide()">
|
||||
<span>{{ monitor.name }}</span>
|
||||
<button type="button" class="btn-rm-monitor btn btn-outline-danger ms-2 py-1" @click.stop.prevent="removeMonitor(monitor.id)">
|
||||
<font-awesome-icon class="" icon="times" />
|
||||
</button>
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="allMonitorList.length > 0" class="pt-3 px-3">
|
||||
<label class="form-label">{{ $t("Add a monitor") }}:</label>
|
||||
<select v-model="selectedAddMonitor" class="form-control">
|
||||
<option v-for="monitor in allMonitorList" :key="monitor.id" :value="monitor">{{ monitor.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button v-if="tag" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm">
|
||||
{{ $t("Delete") }}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="processing">
|
||||
<div v-if="processing" class="spinner-border spinner-border-sm me-1"></div>
|
||||
{{ $t("Save") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteTag">
|
||||
{{ $t("confirmDeleteTagMsg") }}
|
||||
</Confirm>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Modal } from "bootstrap";
|
||||
import Confirm from "./Confirm.vue";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import { colorOptions } from "../util-frontend";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { getMonitorRelativeURL } from "../util.ts";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VueMultiselect,
|
||||
Confirm,
|
||||
},
|
||||
props: {
|
||||
updated: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modal: null,
|
||||
processing: false,
|
||||
selectedColor: {
|
||||
name: null,
|
||||
color: null,
|
||||
},
|
||||
tag: {
|
||||
id: null,
|
||||
name: "",
|
||||
color: "",
|
||||
// Do not set default value here, please scroll to show()
|
||||
},
|
||||
monitors: [],
|
||||
removingMonitor: [],
|
||||
addingMonitor: [],
|
||||
selectedAddMonitor: null,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
colorOptions() {
|
||||
if (!colorOptions(this).find(option => option.color === this.tag.color)) {
|
||||
return colorOptions(this).concat(
|
||||
{
|
||||
name: "custom",
|
||||
color: this.tag.color
|
||||
});
|
||||
} else {
|
||||
return colorOptions(this);
|
||||
}
|
||||
},
|
||||
selectedMonitors() {
|
||||
return this.monitors
|
||||
.concat(Object.values(this.$root.monitorList).filter(monitor => this.addingMonitor.includes(monitor.id)))
|
||||
.filter(monitor => !this.removingMonitor.includes(monitor.id));
|
||||
},
|
||||
allMonitorList() {
|
||||
return Object.values(this.$root.monitorList).filter(monitor => !this.selectedMonitors.includes(monitor));
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
// Set color option to "Custom" when a unknown color is entered
|
||||
"tag.color"(to, from) {
|
||||
if (colorOptions(this).find(x => x.color === to) == null) {
|
||||
this.selectedColor.name = this.$t("Custom");
|
||||
this.selectedColor.color = to;
|
||||
}
|
||||
},
|
||||
selectedColor(to, from) {
|
||||
if (to != null) {
|
||||
this.tag.color = to.color;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Selected a monitor and add to the list.
|
||||
*/
|
||||
selectedAddMonitor(monitor) {
|
||||
if (monitor) {
|
||||
if (this.removingMonitor.includes(monitor.id)) {
|
||||
this.removingMonitor = this.removingMonitor.filter(id => id !== monitor.id);
|
||||
} else {
|
||||
this.addingMonitor.push(monitor.id);
|
||||
}
|
||||
this.selectedAddMonitor = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.modal = new Modal(this.$refs.modal);
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Show confirmation for deleting a tag
|
||||
*/
|
||||
deleteConfirm() {
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Load tag information for display in the edit dialog
|
||||
* @param {Object} tag tag object to edit
|
||||
* @returns {void}
|
||||
*/
|
||||
show(tag) {
|
||||
if (tag) {
|
||||
this.selectedColor = this.colorOptions.find(x => x.color === tag.color) ?? {
|
||||
name: this.$t("Custom"),
|
||||
color: tag.color
|
||||
};
|
||||
this.tag.id = tag.id;
|
||||
this.tag.name = tag.name;
|
||||
this.tag.color = tag.color;
|
||||
this.monitors = this.monitorsByTag(tag.id);
|
||||
this.removingMonitor = [];
|
||||
this.addingMonitor = [];
|
||||
this.selectedAddMonitor = null;
|
||||
}
|
||||
|
||||
this.modal.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Submit tag and monitorTag changes to server
|
||||
* @returns {void}
|
||||
*/
|
||||
async submit() {
|
||||
this.processing = true;
|
||||
let editResult = true;
|
||||
|
||||
for (let addId of this.addingMonitor) {
|
||||
await this.addMonitorTagAsync(this.tag.id, addId, "").then((res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
editResult = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (let removeId of this.removingMonitor) {
|
||||
this.monitors.find(monitor => monitor.id === removeId)?.tags.forEach(async (monitorTag) => {
|
||||
await this.deleteMonitorTagAsync(this.tag.id, removeId, monitorTag.value).then((res) => {
|
||||
if (!res.ok) {
|
||||
toast.error(res.msg);
|
||||
editResult = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.$root.getSocket().emit("editTag", this.tag, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
|
||||
if (res.ok && editResult) {
|
||||
this.updated();
|
||||
this.modal.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete the editing tag from server
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteTag() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("deleteTag", this.tag.id, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
|
||||
if (res.ok) {
|
||||
this.updated();
|
||||
this.modal.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a monitor from the monitors list locally
|
||||
* @param {number} id id of the tag to remove
|
||||
* @returns {void}
|
||||
*/
|
||||
removeMonitor(id) {
|
||||
if (this.addingMonitor.includes(id)) {
|
||||
this.addingMonitor = this.addingMonitor.filter(x => x !== id);
|
||||
} else {
|
||||
this.removingMonitor.push(id);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get monitors which has a specific tag locally
|
||||
* @param {number} tagId id of the tag to filter
|
||||
* @returns {Object[]} list of monitors which has a specific tag
|
||||
*/
|
||||
monitorsByTag(tagId) {
|
||||
return Object.values(this.$root.monitorList).filter((monitor) => {
|
||||
return monitor.tags.find(monitorTag => monitorTag.tag_id === tagId);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get URL of monitor
|
||||
* @param {number} id ID of monitor
|
||||
* @returns {string} Relative URL of monitor
|
||||
*/
|
||||
monitorURL(id) {
|
||||
return getMonitorRelativeURL(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a tag to a monitor asynchronously
|
||||
* @param {number} tagId ID of tag to add
|
||||
* @param {number} monitorId ID of monitor to add tag to
|
||||
* @param {string} value Value of tag
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
addMonitorTagAsync(tagId, monitorId, value) {
|
||||
return new Promise((resolve) => {
|
||||
this.$root.getSocket().emit("addMonitorTag", tagId, monitorId, value, resolve);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Delete a tag from a monitor asynchronously
|
||||
* @param {number} tagId ID of tag to remove
|
||||
* @param {number} monitorId ID of monitor to remove tag from
|
||||
* @param {string} value Value of tag
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
deleteMonitorTagAsync(tagId, monitorId, value) {
|
||||
return new Promise((resolve) => {
|
||||
this.$root.getSocket().emit("deleteMonitorTag", tagId, monitorId, value, resolve);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../assets/vars.scss";
|
||||
|
||||
.dark {
|
||||
.modal-dialog .form-text, .modal-dialog p {
|
||||
color: $dark-font-color;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-rm-monitor {
|
||||
padding-left: 11px;
|
||||
padding-right: 11px;
|
||||
}
|
||||
|
||||
.tag-monitors-list {
|
||||
max-height: 40vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.tag-monitors-list .tag-monitors-list-row {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
|
||||
|
||||
.dark & {
|
||||
border-bottom: 1px solid $dark-border-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $highlight-white;
|
||||
}
|
||||
|
||||
.dark &:hover {
|
||||
background-color: $dark-bg2;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
@@ -130,6 +130,7 @@
|
||||
import { Modal } from "bootstrap";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { colorOptions } from "../util-frontend";
|
||||
import Tag from "../components/Tag.vue";
|
||||
const toast = useToast();
|
||||
|
||||
@@ -176,24 +177,7 @@ export default {
|
||||
return this.preSelectedTags.concat(this.newTags).filter(tag => !this.deleteTags.find(monitorTag => monitorTag.id === tag.id));
|
||||
},
|
||||
colorOptions() {
|
||||
return [
|
||||
{ name: this.$t("Gray"),
|
||||
color: "#4B5563" },
|
||||
{ name: this.$t("Red"),
|
||||
color: "#DC2626" },
|
||||
{ name: this.$t("Orange"),
|
||||
color: "#D97706" },
|
||||
{ name: this.$t("Green"),
|
||||
color: "#059669" },
|
||||
{ name: this.$t("Blue"),
|
||||
color: "#2563EB" },
|
||||
{ name: this.$t("Indigo"),
|
||||
color: "#4F46E5" },
|
||||
{ name: this.$t("Purple"),
|
||||
color: "#7C3AED" },
|
||||
{ name: this.$t("Pink"),
|
||||
color: "#DB2777" },
|
||||
];
|
||||
return colorOptions(this);
|
||||
},
|
||||
validateDraftTag() {
|
||||
let nameInvalid = false;
|
||||
@@ -204,7 +188,7 @@ export default {
|
||||
nameInvalid = false;
|
||||
valueInvalid = false;
|
||||
invalid = false;
|
||||
} else if (this.existingTags.filter(tag => tag.name === this.newDraftTag.name).length > 0) {
|
||||
} else if (this.existingTags.filter(tag => tag.name === this.newDraftTag.name).length > 0 && this.newDraftTag.select == null) {
|
||||
// Try to create new tag with existing name
|
||||
nameInvalid = true;
|
||||
invalid = true;
|
||||
|
@@ -1,8 +1,10 @@
|
||||
<template>
|
||||
<span :class="className" :title="24 + $t('-hour')">{{ uptime }}</span>
|
||||
<span :class="className" :title="title">{{ uptime }}</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DOWN, MAINTENANCE, PENDING, UP } from "../util.ts";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
/** Monitor this represents */
|
||||
@@ -24,7 +26,6 @@ export default {
|
||||
|
||||
computed: {
|
||||
uptime() {
|
||||
|
||||
if (this.type === "maintenance") {
|
||||
return this.$t("statusMaintenance");
|
||||
}
|
||||
@@ -32,26 +33,32 @@ export default {
|
||||
let key = this.monitor.id + "_" + this.type;
|
||||
|
||||
if (this.$root.uptimeList[key] !== undefined) {
|
||||
return Math.round(this.$root.uptimeList[key] * 10000) / 100 + "%";
|
||||
let result = Math.round(this.$root.uptimeList[key] * 10000) / 100;
|
||||
// Only perform sanity check on status page. See louislam/uptime-kuma#2628
|
||||
if (this.$route.path.startsWith("/status") && result > 100) {
|
||||
return "100%";
|
||||
} else {
|
||||
return result + "%";
|
||||
}
|
||||
}
|
||||
|
||||
return this.$t("notAvailableShort");
|
||||
},
|
||||
|
||||
color() {
|
||||
if (this.type === "maintenance" || this.monitor.maintenance) {
|
||||
if (this.lastHeartBeat.status === MAINTENANCE) {
|
||||
return "maintenance";
|
||||
}
|
||||
|
||||
if (this.lastHeartBeat.status === 0) {
|
||||
if (this.lastHeartBeat.status === DOWN) {
|
||||
return "danger";
|
||||
}
|
||||
|
||||
if (this.lastHeartBeat.status === 1) {
|
||||
if (this.lastHeartBeat.status === UP) {
|
||||
return "primary";
|
||||
}
|
||||
|
||||
if (this.lastHeartBeat.status === 2) {
|
||||
if (this.lastHeartBeat.status === PENDING) {
|
||||
return "warning";
|
||||
}
|
||||
|
||||
@@ -75,6 +82,14 @@ export default {
|
||||
|
||||
return "";
|
||||
},
|
||||
|
||||
title() {
|
||||
if (this.type === "720") {
|
||||
return `30${this.$t("-day")}`;
|
||||
}
|
||||
|
||||
return `24${this.$t("-hour")}`;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
36
src/components/notifications/Kook.vue
Normal file
36
src/components/notifications/Kook.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="kook-bot-token" class="form-label">{{ $t("Bot Token") }}</label>
|
||||
<HiddenInput id="kook-bot-token" v-model="$parent.notification.kookBotToken" :required="true" autocomplete="new-password"></HiddenInput>
|
||||
<i18n-t tag="div" keypath="wayToGetKookBotToken" class="form-text">
|
||||
<a href="https://developer.kookapp.cn/bot" target="_blank">https://developer.kookapp.cn/bot</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="kook-guild-id" class="form-label">{{ $t("Guild ID") }}</label>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<input id="kook-guild-id" v-model="$parent.notification.kookGuildID" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="form-text">
|
||||
<p style="margin-top: 8px;">
|
||||
{{ $t("wayToGetKookGuildID") }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
|
||||
<a href="https://developer.kookapp.cn" target="_blank">https://developer.kookapp.cn</a>
|
||||
</i18n-t>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
}
|
||||
};
|
||||
</script>
|
@@ -26,6 +26,10 @@
|
||||
<label for="promosms-sender-name" class="form-label">{{ $t("promosmsSMSSender") }}</label>
|
||||
<input id="promosms-sender-name" v-model="$parent.notification.promosmsSenderName" type="text" minlength="3" maxlength="11" class="form-control">
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input id="promosms-allow-long" v-model="$parent.notification.promosmsAllowLongSMS" type="checkbox" class="form-check-input">
|
||||
<label for="promosms-allow-long" class="form-label">{{ $t("promosmsAllowLongSMS") }}</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="smsmanager-key" class="form-label">API Key</label>
|
||||
<label for="smsmanager-key" class="form-label">{{ $t("API Key") }}</label>
|
||||
<div class="form-text">
|
||||
{{ $t("SMSManager API Docs") }}
|
||||
<a href="https://smsmanager.cz/api/http#send" target="_blank">{{ $t("here") }}</a>
|
||||
@@ -17,9 +17,9 @@
|
||||
<div class="mb-3">
|
||||
<label for="smsmanager-messageType" class="form-label">{{ $t("Gateway Type") }}</label>
|
||||
<select id="smsmanager-messageType" v-model="$parent.notification.messageType" class="form-select">
|
||||
<option value="economy">Economy</option>
|
||||
<option value="lowcost">Lowcost</option>
|
||||
<option value="high" selected>High</option>
|
||||
<option value="economy">{{ $t("Economy") }}</option>
|
||||
<option value="lowcost">{{ $t("Lowcost") }}</option>
|
||||
<option value="high" selected>{{ $t("High") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
|
32
src/components/notifications/Splunk.vue
Normal file
32
src/components/notifications/Splunk.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="splunk-rest-url" class="form-label">{{ $t("Splunk Rest URL") }}</label>
|
||||
<HiddenInput id="splunk-rest-url" v-model="$parent.notification.splunkRestURL" :required="true" autocomplete="false"></HiddenInput>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="splunk-severity" class="form-label">{{ $t("Severity") }}</label>
|
||||
<select id="splunk-severity" v-model="$parent.notification.splunkSeverity" class="form-select">
|
||||
<option value="INFO">{{ $t("info") }}</option>
|
||||
<option value="WARNING">{{ $t("warning") }}</option>
|
||||
<option value="CRITICAL" selected="selected">{{ $t("critical") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="splunk-resolve" class="form-label">{{ $t("Auto resolve or acknowledged") }}</label>
|
||||
<select id="splunk-resolve" v-model="$parent.notification.splunkAutoResolve" class="form-select">
|
||||
<option value="0" selected="selected">{{ $t("do nothing") }}</option>
|
||||
<option value="ACKNOWLEDGEMENT">{{ $t("auto acknowledged") }}</option>
|
||||
<option value="RECOVERY">{{ $t("auto resolve") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
},
|
||||
};
|
||||
</script>
|
@@ -42,6 +42,11 @@ export default {
|
||||
HiddenInput,
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Get the URL for telegram updates
|
||||
* @param {string} [mode=masked] Should the token be masked?
|
||||
* @returns {string} formatted URL
|
||||
*/
|
||||
telegramGetUpdatesURL(mode = "masked") {
|
||||
let token = `<${this.$t("YOUR BOT TOKEN HERE")}>`;
|
||||
|
||||
@@ -55,6 +60,8 @@ export default {
|
||||
|
||||
return `https://api.telegram.org/bot${token}/getUpdates`;
|
||||
},
|
||||
|
||||
/** Get the telegram chat ID */
|
||||
async autoGetTelegramChatID() {
|
||||
try {
|
||||
let res = await axios.get(this.telegramGetUpdatesURL("withToken"));
|
||||
|
18
src/components/notifications/ZohoCliq.vue
Normal file
18
src/components/notifications/ZohoCliq.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="zcliq-webhookurl" class="form-label">{{ $t("Webhook URL") }}</label>
|
||||
<input
|
||||
id="zcliq-webhookurl"
|
||||
v-model="$parent.notification.webhookUrl"
|
||||
type="text"
|
||||
class="form-control"
|
||||
required
|
||||
/>
|
||||
<i18n-t tag="div" keypath="wayToGetZohoCliqURL" class="form-text">
|
||||
<a
|
||||
href="https://www.zoho.com/cliq/help/platform/webhook-tokens.html"
|
||||
target="_blank"
|
||||
>{{ $t("here") }}</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</template>
|
@@ -12,6 +12,7 @@ import GoogleChat from "./GoogleChat.vue";
|
||||
import Gorush from "./Gorush.vue";
|
||||
import Gotify from "./Gotify.vue";
|
||||
import HomeAssistant from "./HomeAssistant.vue";
|
||||
import Kook from "./Kook.vue";
|
||||
import Line from "./Line.vue";
|
||||
import LineNotify from "./LineNotify.vue";
|
||||
import LunaSea from "./LunaSea.vue";
|
||||
@@ -42,6 +43,8 @@ import Telegram from "./Telegram.vue";
|
||||
import Webhook from "./Webhook.vue";
|
||||
import WeCom from "./WeCom.vue";
|
||||
import GoAlert from "./GoAlert.vue";
|
||||
import ZohoCliq from "./ZohoCliq.vue";
|
||||
import Splunk from "./Splunk.vue";
|
||||
|
||||
/**
|
||||
* Manage all notification form.
|
||||
@@ -63,6 +66,7 @@ const NotificationFormList = {
|
||||
"gorush": Gorush,
|
||||
"gotify": Gotify,
|
||||
"HomeAssistant": HomeAssistant,
|
||||
"Kook": Kook,
|
||||
"line": Line,
|
||||
"LineNotify": LineNotify,
|
||||
"lunasea": LunaSea,
|
||||
@@ -89,10 +93,12 @@ const NotificationFormList = {
|
||||
"stackfield": Stackfield,
|
||||
"teams": Teams,
|
||||
"telegram": Telegram,
|
||||
"Splunk": Splunk,
|
||||
"webhook": Webhook,
|
||||
"WeCom": WeCom,
|
||||
"GoAlert": GoAlert,
|
||||
"ServerChan": ServerChan,
|
||||
"ZohoCliq": ZohoCliq
|
||||
};
|
||||
|
||||
export default NotificationFormList;
|
||||
|
@@ -49,7 +49,7 @@
|
||||
v-model="settings.searchEngineIndex"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="flexRadioDefault"
|
||||
name="searchEngineIndex"
|
||||
:value="true"
|
||||
required
|
||||
/>
|
||||
@@ -63,7 +63,7 @@
|
||||
v-model="settings.searchEngineIndex"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="flexRadioDefault"
|
||||
name="searchEngineIndex"
|
||||
:value="false"
|
||||
required
|
||||
/>
|
||||
@@ -150,6 +150,46 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DNS Cache -->
|
||||
<div class="mb-4">
|
||||
<label class="form-label">
|
||||
{{ $t("Enable DNS Cache") }}
|
||||
<div class="form-text">
|
||||
⚠️ {{ $t("dnsCacheDescription") }}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<div class="form-check">
|
||||
<input
|
||||
id="dnsCacheEnable"
|
||||
v-model="settings.dnsCache"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="dnsCache"
|
||||
:value="true"
|
||||
required
|
||||
/>
|
||||
<label class="form-check-label" for="dnsCacheEnable">
|
||||
{{ $t("Enable") }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input
|
||||
id="dnsCacheDisable"
|
||||
v-model="settings.dnsCache"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="dnsCache"
|
||||
:value="false"
|
||||
required
|
||||
/>
|
||||
<label class="form-check-label" for="dnsCacheDisable">
|
||||
{{ $t("Disable") }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Save Button -->
|
||||
<div>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
|
@@ -7,6 +7,7 @@
|
||||
settings.keepDataPeriodDays,
|
||||
])
|
||||
}}
|
||||
{{ $t("infiniteRetention") }}
|
||||
</label>
|
||||
<input
|
||||
id="keepDataPeriodDays"
|
||||
@@ -14,9 +15,12 @@
|
||||
type="number"
|
||||
class="form-control"
|
||||
required
|
||||
min="1"
|
||||
min="0"
|
||||
step="1"
|
||||
/>
|
||||
<div v-if="settings.keepDataPeriodDays < 0" class="form-text">
|
||||
{{ $t("dataRetentionTimeError") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-4">
|
||||
<button class="btn btn-primary" type="button" @click="saveSettings()">
|
||||
|
57
src/components/settings/Plugins.vue
Normal file
57
src/components/settings/Plugins.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="mt-3">{{ remotePluginListMsg }}</div>
|
||||
<PluginItem v-for="plugin in remotePluginList" :key="plugin.id" :plugin="plugin" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PluginItem from "../PluginItem.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PluginItem
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
remotePluginList: [],
|
||||
remotePluginListMsg: "",
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginList() {
|
||||
return this.$parent.$parent.$parent.pluginList;
|
||||
},
|
||||
settings() {
|
||||
return this.$parent.$parent.$parent.settings;
|
||||
},
|
||||
saveSettings() {
|
||||
return this.$parent.$parent.$parent.saveSettings;
|
||||
},
|
||||
settingsLoaded() {
|
||||
return this.$parent.$parent.$parent.settingsLoaded;
|
||||
},
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
this.loadList();
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadList() {
|
||||
this.remotePluginListMsg = this.$t("Loading") + "...";
|
||||
|
||||
this.$root.getSocket().emit("getPluginList", (res) => {
|
||||
if (res.ok) {
|
||||
this.remotePluginList = res.pluginList;
|
||||
this.remotePluginListMsg = "";
|
||||
} else {
|
||||
this.remotePluginListMsg = this.$t("loadingError") + " " + res.msg;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
@@ -191,6 +191,7 @@ export default {
|
||||
location.reload();
|
||||
},
|
||||
|
||||
/** Show confirmation dialog for disable auth */
|
||||
confirmDisableAuth() {
|
||||
this.$refs.confirmDisableAuth.show();
|
||||
},
|
||||
|
171
src/components/settings/Tags.vue
Normal file
171
src/components/settings/Tags.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="tags-list my-3">
|
||||
<div v-for="(tag, index) in tagsList" :key="tag.id" class="d-flex align-items-center mx-4 py-1 tags-list-row" :disabled="processing" @click="editTag(index)">
|
||||
<div class="col-5 ps-1">
|
||||
<Tag :item="tag" />
|
||||
</div>
|
||||
<div class="col-5 px-1">
|
||||
<div>{{ monitorsByTag(tag.id).length }} {{ $tc("Monitor", monitorsByTag(tag.id).length) }}</div>
|
||||
</div>
|
||||
<div class="col-2 pe-3 d-flex justify-content-end">
|
||||
<button type="button" class="btn ms-2 py-1">
|
||||
<font-awesome-icon class="" icon="edit" />
|
||||
</button>
|
||||
<button type="button" class="btn-rm-tag btn btn-outline-danger ms-2 py-1" :disabled="processing" @click.stop="deleteConfirm(index)">
|
||||
<font-awesome-icon class="" icon="trash" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TagEditDialog ref="tagEditDialog" :updated="tagsUpdated" />
|
||||
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteTag">
|
||||
{{ $t("confirmDeleteTagMsg") }}
|
||||
</Confirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useToast } from "vue-toastification";
|
||||
import TagEditDialog from "../../components/TagEditDialog.vue";
|
||||
import Tag from "../Tag.vue";
|
||||
import Confirm from "../Confirm.vue";
|
||||
const toast = useToast();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Confirm,
|
||||
TagEditDialog,
|
||||
Tag,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
processing: false,
|
||||
tagsList: null,
|
||||
deletingTag: null,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
settings() {
|
||||
return this.$parent.$parent.$parent.settings;
|
||||
},
|
||||
saveSettings() {
|
||||
return this.$parent.$parent.$parent.saveSettings;
|
||||
},
|
||||
settingsLoaded() {
|
||||
return this.$parent.$parent.$parent.settingsLoaded;
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getExistingTags();
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Reflect tag changes in the UI by fetching data. Callback for the edit tag dialog.
|
||||
* @returns {void}
|
||||
*/
|
||||
tagsUpdated() {
|
||||
this.getExistingTags();
|
||||
this.$root.getMonitorList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get list of tags from server
|
||||
* @returns {void}
|
||||
*/
|
||||
getExistingTags() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("getTags", (res) => {
|
||||
this.processing = false;
|
||||
if (res.ok) {
|
||||
this.tagsList = res.tags;
|
||||
} else {
|
||||
toast.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show confirmation for deleting a tag
|
||||
* @param {number} index index of the tag to delete in the local tagsList
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteConfirm(index) {
|
||||
this.deletingTag = this.tagsList[index];
|
||||
this.$refs.confirmDelete.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show dialog for editing a tag
|
||||
* @param {number} index index of the tag to edit in the local tagsList
|
||||
* @returns {void}
|
||||
*/
|
||||
editTag(index) {
|
||||
this.$refs.tagEditDialog.show(this.tagsList[index]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete the tag "deletingTag" from server
|
||||
* @returns {void}
|
||||
*/
|
||||
deleteTag() {
|
||||
this.processing = true;
|
||||
this.$root.getSocket().emit("deleteTag", this.deletingTag.id, (res) => {
|
||||
this.$root.toastRes(res);
|
||||
this.processing = false;
|
||||
|
||||
if (res.ok) {
|
||||
this.tagsUpdated();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get monitors which has a specific tag locally
|
||||
* @param {number} tagId id of the tag to filter
|
||||
* @returns {Object[]} list of monitors which has a specific tag
|
||||
*/
|
||||
monitorsByTag(tagId) {
|
||||
return Object.values(this.$root.monitorList).filter((monitor) => {
|
||||
return monitor.tags.find(monitorTag => monitorTag.tag_id === tagId);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../assets/vars.scss";
|
||||
|
||||
.btn-rm-tag {
|
||||
padding-left: 11px;
|
||||
padding-right: 11px;
|
||||
}
|
||||
|
||||
.tags-list .tags-list-row {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
|
||||
|
||||
.dark & {
|
||||
border-bottom: 1px solid $dark-border-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $highlight-white;
|
||||
}
|
||||
|
||||
.dark &:hover {
|
||||
background-color: $dark-bg2;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-list .tags-list-row:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
</style>
|
@@ -1,11 +1,13 @@
|
||||
import { createI18n } from "vue-i18n/dist/vue-i18n.esm-browser.prod.js";
|
||||
import en from "./languages/en";
|
||||
import en from "./lang/en.json";
|
||||
|
||||
const languageList = {
|
||||
"ar-SY": "العربية",
|
||||
"cs-CZ": "Čeština",
|
||||
"zh-HK": "繁體中文 (香港)",
|
||||
"bg-BG": "Български",
|
||||
"de-DE": "Deutsch (Deutschland)",
|
||||
"de-CH": "Deutsch (Schweiz)",
|
||||
"nl-NL": "Nederlands",
|
||||
"nb-NO": "Norsk",
|
||||
"es-ES": "Español",
|
||||
@@ -35,6 +37,7 @@ const languageList = {
|
||||
"uk-UA": "Український",
|
||||
"th-TH": "ไทย",
|
||||
"el-GR": "Ελληνικά",
|
||||
"yue": "繁體中文 (廣東話 / 粵語)",
|
||||
};
|
||||
|
||||
let messages = {
|
||||
@@ -47,7 +50,7 @@ for (let lang in languageList) {
|
||||
};
|
||||
}
|
||||
|
||||
const rtlLangs = [ "fa" ];
|
||||
const rtlLangs = [ "fa", "ar-SY" ];
|
||||
|
||||
export const currentLocale = () => localStorage.locale
|
||||
|| languageList[navigator.language] && navigator.language
|
||||
|
@@ -44,6 +44,7 @@ import {
|
||||
faWrench,
|
||||
faHeartbeat,
|
||||
faFilter,
|
||||
faInfoCircle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
library.add(
|
||||
@@ -88,6 +89,7 @@ library.add(
|
||||
faWrench,
|
||||
faHeartbeat,
|
||||
faFilter,
|
||||
faInfoCircle,
|
||||
);
|
||||
|
||||
export { FontAwesomeIcon };
|
||||
|
18
src/lang/README.md
Normal file
18
src/lang/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# How to translate
|
||||
|
||||
(2023-01-24 Updated)
|
||||
|
||||
1. Go to [https://weblate.kuma.pet](https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/)
|
||||
2. Register an account on Weblate
|
||||
3. Make sure your GitHub email is matched with Weblate's account, so that it could show you as a contributor on GitHub
|
||||
4. Choose your language on Weblate and start translating.
|
||||
|
||||
# How to add a new language in the dropdown
|
||||
|
||||
1. Add your language at https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/
|
||||
2. Find the language code (You can find it at the end of the URL)
|
||||
3. Go to https://github.com/louislam/uptime-kuma/blob/master/src/i18n.js and click `Edit` icon
|
||||
4. Add your language at the end of `languageList`, format: `"zh-TW": "繁體中文 (台灣)",`
|
||||
5. Commit and make a pull request for me to approve
|
||||
|
||||
If you do not have programming skills, let me know in [the issues section](https://github.com/louislam/uptime-kuma/issues). I will assist you. 😏
|
684
src/lang/ar-SY.json
Normal file
684
src/lang/ar-SY.json
Normal file
@@ -0,0 +1,684 @@
|
||||
{
|
||||
"languageName": "العربية",
|
||||
"checkEverySecond": "تحقق من كل {0} ثانية",
|
||||
"retryCheckEverySecond": "أعد محاولة كل {0} ثانية",
|
||||
"resendEveryXTimes": "إعادة تقديم كل {0} مرات",
|
||||
"resendDisabled": "إعادة الالتزام بالتعطيل",
|
||||
"retriesDescription": "الحد الأقصى لإعادة المحاولة قبل تمييز الخدمة على أنها لأسفل وإرسال إشعار",
|
||||
"ignoreTLSError": "تجاهل خطأ TLS/SSL لمواقع HTTPS",
|
||||
"upsideDownModeDescription": "اقلب الحالة رأسًا على عقب. إذا كانت الخدمة قابلة للوصول إلى أسفل.",
|
||||
"maxRedirectDescription": "الحد الأقصى لعدد إعادة التوجيه لمتابعة. ضبط على 0 لتعطيل إعادة التوجيه.",
|
||||
"enableGRPCTls": "السماح لإرسال طلب GRPC مع اتصال TLS",
|
||||
"grpcMethodDescription": "يتم تحويل اسم الطريقة إلى تنسيق Cammelcase مثل Sayhello Check وما إلى ذلك.",
|
||||
"acceptedStatusCodesDescription": "حدد رموز الحالة التي تعتبر استجابة ناجحة.",
|
||||
"Maintenance": "صيانة",
|
||||
"statusMaintenance": "صيانة",
|
||||
"Schedule maintenance": "جدولة الصيانة",
|
||||
"Affected Monitors": "الشاشات المتأثرة",
|
||||
"Pick Affected Monitors...": "اختيار الشاشات المتأثرة ...",
|
||||
"Start of maintenance": "بداية الصيانة",
|
||||
"All Status Pages": "جميع صفحات الحالة",
|
||||
"Select status pages...": "حدد صفحات الحالة ...",
|
||||
"recurringIntervalMessage": "ركض مرة واحدة كل يوم | قم بالتشغيل مرة واحدة كل يوم {0}",
|
||||
"affectedMonitorsDescription": "حدد المراقبين المتأثرة بالصيانة الحالية",
|
||||
"affectedStatusPages": "إظهار رسالة الصيانة هذه على صفحات الحالة المحددة",
|
||||
"atLeastOneMonitor": "حدد شاشة واحدة على الأقل من المتأثرين",
|
||||
"passwordNotMatchMsg": "كلمة المرور المتكررة لا تتطابق.",
|
||||
"notificationDescription": "يجب تعيين الإخطارات إلى شاشة للعمل.",
|
||||
"keywordDescription": "ابحث في الكلمة الرئيسية في استجابة HTML العادية أو JSON. البحث حساس للحالة.",
|
||||
"pauseDashboardHome": "وقفة",
|
||||
"deleteMonitorMsg": "هل أنت متأكد من حذف هذا الشاشة؟",
|
||||
"deleteMaintenanceMsg": "هل أنت متأكد من حذف هذه الصيانة؟",
|
||||
"deleteNotificationMsg": "هل أنت متأكد من حذف هذا الإشعار لجميع الشاشات؟",
|
||||
"dnsPortDescription": "منفذ خادم DNS. الافتراضيات إلى 53. يمكنك تغيير المنفذ في أي وقت.",
|
||||
"resolverserverDescription": "CloudFlare هو الخادم الافتراضي. يمكنك تغيير خادم المحوّل في أي وقت.",
|
||||
"rrtypeDescription": "حدد نوع RR الذي تريد مراقبته",
|
||||
"pauseMonitorMsg": "هل أنت متأكد من أن تتوقف مؤقتًا؟",
|
||||
"enableDefaultNotificationDescription": "سيتم تمكين هذا الإشعار افتراضيًا للشاشات الجديدة. لا يزال بإمكانك تعطيل الإخطار بشكل منفصل لكل شاشة.",
|
||||
"clearEventsMsg": "هل أنت متأكد من حذف جميع الأحداث لهذا الشاشة؟",
|
||||
"clearHeartbeatsMsg": "هل أنت متأكد من حذف جميع دقات القلب لهذا الشاشة؟",
|
||||
"confirmClearStatisticsMsg": "هل أنت متأكد من أنك تريد حذف جميع الإحصائيات؟",
|
||||
"importHandleDescription": "اختر 'تخطي موجود' إذا كنت تريد تخطي كل شاشة أو إشعار بنفس الاسم. 'الكتابة فوق' سوف يحذف كل شاشة وإخطار موجود.",
|
||||
"confirmImportMsg": "هل أنت متأكد من أنك تريد استيراد النسخ الاحتياطي؟ يرجى التحقق من أنك حددت خيار الاستيراد الصحيح.",
|
||||
"twoFAVerifyLabel": "الرجاء إدخال الرمز المميز الخاص بك للتحقق من 2FA",
|
||||
"tokenValidSettingsMsg": "الرمز المميز صالح! يمكنك الآن حفظ إعدادات 2FA.",
|
||||
"confirmEnableTwoFAMsg": "هل أنت متأكد من أنك تريد تمكين 2FA؟",
|
||||
"confirmDisableTwoFAMsg": "هل أنت متأكد من أنك تريد تعطيل 2FA؟",
|
||||
"Settings": "إعدادات",
|
||||
"Dashboard": "لوحة التحكم",
|
||||
"New Update": "تحديث جديد",
|
||||
"Language": "لغة",
|
||||
"Appearance": "مظهر",
|
||||
"Theme": "سمة",
|
||||
"General": "عام",
|
||||
"Primary Base URL": "عنوان URL الأساسي",
|
||||
"Version": "الإصدار",
|
||||
"Check Update On GitHub": "تحقق من التحديث على GitHub",
|
||||
"List": "قائمة",
|
||||
"Add": "يضيف",
|
||||
"Add New Monitor": "أضف شاشة جديدة",
|
||||
"Quick Stats": "إحصائيات سريعة",
|
||||
"Up": "فوق",
|
||||
"Down": "أسفل",
|
||||
"Pending": "قيد الانتظار",
|
||||
"Unknown": "غير معرّف",
|
||||
"Pause": "إيقاف مؤقت",
|
||||
"Name": "الاسم",
|
||||
"Status": "الحالة",
|
||||
"DateTime": "الوقت والتاريخ",
|
||||
"Message": "الرسالة",
|
||||
"No important events": "لا توجد أحداث مهمة",
|
||||
"Resume": "استمرار",
|
||||
"Edit": "تعديل",
|
||||
"Delete": "حذف",
|
||||
"Current": "حالي",
|
||||
"Uptime": "مدة التشغيل",
|
||||
"Cert Exp.": "تصدير الشهادة",
|
||||
"Monitor": "مراقب | مراقبات",
|
||||
"day": "يوم | أيام",
|
||||
"-day": "-يوم",
|
||||
"hour": "ساعة",
|
||||
"-hour": "-ساعة",
|
||||
"Response": "استجاية",
|
||||
"Ping": "بينغ",
|
||||
"Monitor Type": "نوع المراقب",
|
||||
"Keyword": "كلمة مفتاحية",
|
||||
"Friendly Name": "اسم معروف",
|
||||
"URL": "عنوان URL",
|
||||
"Hostname": "اسم المضيف",
|
||||
"Port": "المنفذ",
|
||||
"Heartbeat Interval": "فاصل نبضات القلب",
|
||||
"Retries": "يحاول مجدداً",
|
||||
"Heartbeat Retry Interval": "الفاصل الزمني لإعادة محاكمة نبضات القلب",
|
||||
"Resend Notification if Down X times consequently": "إعادة تقديم الإخطار إذا انخفض x مرات بالتالي",
|
||||
"Advanced": "متقدم",
|
||||
"Upside Down Mode": "وضع أسفل أسفل",
|
||||
"Max. Redirects": "الأعلى. إعادة التوجيه",
|
||||
"Accepted Status Codes": "رموز الحالة المقبولة",
|
||||
"Push URL": "دفع عنوان URL",
|
||||
"needPushEvery": "يجب عليك استدعاء عنوان URL هذا كل ثانية.",
|
||||
"pushOptionalParams": "المعلمات الاختيارية",
|
||||
"Save": "يحفظ",
|
||||
"Notifications": "إشعارات",
|
||||
"Not available, please setup.": "غير متوفر من فضلك الإعداد.",
|
||||
"Setup Notification": "إشعار الإعداد",
|
||||
"Light": "نور",
|
||||
"Dark": "داكن",
|
||||
"Auto": "آلي",
|
||||
"Theme - Heartbeat Bar": "موضوع - بار نبضات",
|
||||
"Normal": "طبيعي",
|
||||
"Bottom": "الأسفل",
|
||||
"None": "لا أحد",
|
||||
"Timezone": "وحدة زمنية",
|
||||
"Search Engine Visibility": "محرك بحث الرؤية",
|
||||
"Allow indexing": "السماح الفهرسة",
|
||||
"Discourage search engines from indexing site": "تثبيط محركات البحث من موقع الفهرسة",
|
||||
"Change Password": "غير كلمة السر",
|
||||
"Current Password": "كلمة المرور الحالي",
|
||||
"New Password": "كلمة سر جديدة",
|
||||
"Repeat New Password": "كرر كلمة المرور الجديدة",
|
||||
"Update Password": "تطوير كلمة السر",
|
||||
"Disable Auth": "تعطيل المصادقة",
|
||||
"Enable Auth": "تمكين المصادقة",
|
||||
"disableauth.message1": "هل أنت متأكد من أن <strong> تعطيل المصادقة </strong>؟",
|
||||
"disableauth.message2": "تم تصميمه للسيناريوهات <strong> حيث تنوي تنفيذ مصادقة الطرف الثالث </strong> أمام كوما في وقت التشغيل مثل CloudFlare Access Authelia أو آليات المصادقة الأخرى.",
|
||||
"Please use this option carefully!": "الرجاء استخدام هذا الخيار بعناية!",
|
||||
"Logout": "تسجيل خروج",
|
||||
"Leave": "غادر",
|
||||
"I understand, please disable": "أنا أفهم من فضلك تعطيل",
|
||||
"Confirm": "يتأكد",
|
||||
"Yes": "نعم",
|
||||
"No": "رقم",
|
||||
"Username": "اسم المستخدم",
|
||||
"Password": "كلمة المرور",
|
||||
"Remember me": "تذكرنى",
|
||||
"Login": "تسجيل الدخول",
|
||||
"No Monitors, please": "لا شاشات من فضلك",
|
||||
"add one": "أضف واحدا",
|
||||
"Notification Type": "نوع إعلام",
|
||||
"Email": "بريد إلكتروني",
|
||||
"Test": "امتحان",
|
||||
"Certificate Info": "معلومات الشهادة",
|
||||
"Resolver Server": "خادم Resolver",
|
||||
"Resource Record Type": "نوع سجل الموارد",
|
||||
"Last Result": "اخر نتيجة",
|
||||
"Create your admin account": "إنشاء حساب المسؤول الخاص بك",
|
||||
"Repeat Password": "اعد كلمة السر",
|
||||
"Import Backup": "استيراد النسخ الاحتياطي",
|
||||
"Export Backup": "النسخ الاحتياطي تصدير",
|
||||
"Export": "يصدّر",
|
||||
"Import": "يستورد",
|
||||
"respTime": "resp. الوقت (MS)",
|
||||
"notAvailableShort": "ن/أ",
|
||||
"Default enabled": "التمكين الافتراضي",
|
||||
"Apply on all existing monitors": "تنطبق على جميع الشاشات الحالية",
|
||||
"Create": "خلق",
|
||||
"Clear Data": "امسح البيانات",
|
||||
"Events": "الأحداث",
|
||||
"Heartbeats": "نبضات القلب",
|
||||
"Auto Get": "الحصول على السيارات",
|
||||
"backupDescription": "يمكنك النسخ الاحتياطي لجميع الشاشات والإشعارات في ملف JSON.",
|
||||
"backupDescription2": "ملحوظة",
|
||||
"backupDescription3": "يتم تضمين البيانات الحساسة مثل الرموز الإخطار في ملف التصدير ؛ يرجى تخزين التصدير بشكل آمن.",
|
||||
"alertNoFile": "الرجاء تحديد ملف للاستيراد.",
|
||||
"alertWrongFileType": "الرجاء تحديد ملف JSON.",
|
||||
"Clear all statistics": "مسح جميع الإحصاءات",
|
||||
"Skip existing": "تخطي الموجود",
|
||||
"Overwrite": "الكتابة فوق",
|
||||
"Options": "خيارات",
|
||||
"Keep both": "احتفظ بكليهما",
|
||||
"Verify Token": "تحقق من الرمز المميز",
|
||||
"Setup 2FA": "الإعداد 2FA",
|
||||
"Enable 2FA": "تمكين 2FA",
|
||||
"Disable 2FA": "تعطيل 2FA",
|
||||
"2FA Settings": "2FA إعدادات",
|
||||
"Two Factor Authentication": "توثيق ذو عاملين",
|
||||
"Active": "نشيط",
|
||||
"Inactive": "غير نشط",
|
||||
"Token": "رمز",
|
||||
"Show URI": "أظهر URI",
|
||||
"Tags": "العلامات",
|
||||
"Add New below or Select...": "أضف جديدًا أدناه أو حدد ...",
|
||||
"Tag with this name already exist.": "علامة مع هذا الاسم موجود بالفعل.",
|
||||
"Tag with this value already exist.": "علامة مع هذه القيمة موجودة بالفعل.",
|
||||
"color": "اللون",
|
||||
"value (optional)": "القيمة (اختياري)",
|
||||
"Gray": "رمادي",
|
||||
"Red": "أحمر",
|
||||
"Orange": "البرتقالي",
|
||||
"Green": "لون أخضر",
|
||||
"Blue": "أزرق",
|
||||
"Indigo": "النيلي",
|
||||
"Purple": "نفسجي",
|
||||
"Pink": "لون القرنفل",
|
||||
"Custom": "العادة",
|
||||
"Search...": "يبحث...",
|
||||
"Avg. Ping": "متوسط. بينغ",
|
||||
"Avg. Response": "متوسط. إجابة",
|
||||
"Entry Page": "صفحة الدخول",
|
||||
"statusPageNothing": "لا شيء هنا الرجاء إضافة مجموعة أو شاشة.",
|
||||
"No Services": "لا توجد خدمات",
|
||||
"All Systems Operational": "جميع الأنظمة التشغيلية",
|
||||
"Partially Degraded Service": "الخدمة المتدهورة جزئيا",
|
||||
"Degraded Service": "خدمة متدهورة",
|
||||
"Add Group": "أضف مجموعة",
|
||||
"Add a monitor": "إضافة شاشة",
|
||||
"Edit Status Page": "تحرير صفحة الحالة",
|
||||
"Go to Dashboard": "الذهاب إلى لوحة القيادة",
|
||||
"Status Page": "صفحة الحالة",
|
||||
"Status Pages": "صفحات الحالة",
|
||||
"defaultNotificationName": "تنبيه {الإخطار} ({number})",
|
||||
"here": "هنا",
|
||||
"Required": "مطلوب",
|
||||
"telegram": "برقية",
|
||||
"ZohoCliq": "Zohocliq",
|
||||
"Bot Token": "رمز الروبوت",
|
||||
"wayToGetTelegramToken": "يمكنك الحصول على رمز من {0}.",
|
||||
"Chat ID": "معرف الدردشة",
|
||||
"supportTelegramChatID": "دعم الدردشة المباشرة / معرف الدردشة للقناة",
|
||||
"wayToGetTelegramChatID": "يمكنك الحصول على معرف الدردشة الخاص بك عن طريق إرسال رسالة إلى الروبوت والانتقال إلى عنوان URL هذا لعرض Chat_id",
|
||||
"YOUR BOT TOKEN HERE": "رمز الروبوت الخاص بك هنا",
|
||||
"chatIDNotFound": "لم يتم العثور على معرف الدردشة ؛ الرجاء إرسال رسالة إلى هذا الروبوت أولاً",
|
||||
"webhook": "webhook",
|
||||
"Post URL": "بعد عنوان URL",
|
||||
"Content Type": "نوع المحتوى",
|
||||
"webhookJsonDesc": "{0} مفيد لأي خوادم HTTP الحديثة مثل Express.js",
|
||||
"webhookFormDataDesc": "{multipart} مفيد لـ PHP. سيحتاج JSON إلى تحليل {decodefunction}",
|
||||
"webhookAdditionalHeadersTitle": "رؤوس إضافية",
|
||||
"webhookAdditionalHeadersDesc": "يحدد رؤوس إضافية مرسلة مع webhook.",
|
||||
"smtp": "البريد الإلكتروني (SMTP)",
|
||||
"secureOptionNone": "لا شيء / startTls (25 587)",
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
"Ignore TLS Error": "تجاهل خطأ TLS",
|
||||
"From Email": "من البريد الإلكترونى",
|
||||
"emailCustomSubject": "موضوع مخصص",
|
||||
"To Email": "للبريد الإلكتروني",
|
||||
"smtpCC": "نسخة",
|
||||
"smtpBCC": "BCC",
|
||||
"discord": "خلاف",
|
||||
"Discord Webhook URL": "Discord Webhook URL",
|
||||
"wayToGetDiscordURL": "يمكنك الحصول على هذا عن طريق الانتقال إلى إعدادات الخادم -> التكامل -> إنشاء WebHook",
|
||||
"Bot Display Name": "اسم عرض الروبوت",
|
||||
"Prefix Custom Message": "بادئة رسالة مخصصة",
|
||||
"Hello @everyone is...": "مرحبًا {'@'} الجميع ...",
|
||||
"teams": "فرق Microsoft",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"wayToGetTeamsURL": "يمكنك معرفة كيفية إنشاء عنوان URL webhook {0}.",
|
||||
"wayToGetZohoCliqURL": "يمكنك معرفة كيفية إنشاء عنوان URL webhook {0}.",
|
||||
"signal": "الإشارة",
|
||||
"Number": "رقم",
|
||||
"Recipients": "المستلمين",
|
||||
"needSignalAPI": "تحتاج إلى وجود عميل إشارة مع REST API.",
|
||||
"wayToCheckSignalURL": "يمكنك التحقق من عنوان URL هذا لعرض كيفية إعداد واحد",
|
||||
"signalImportant": "مهم",
|
||||
"gotify": "gotify",
|
||||
"Application Token": "رمز التطبيق",
|
||||
"Server URL": "عنوان URL الخادم",
|
||||
"Priority": "أولوية",
|
||||
"slack": "تثاقل",
|
||||
"Icon Emoji": "أيقونة الرموز التعبيرية",
|
||||
"Channel Name": "اسم القناة",
|
||||
"Uptime Kuma URL": "UPTIME KUMA URL",
|
||||
"aboutWebhooks": "مزيد من المعلومات حول Webhooks ON",
|
||||
"aboutChannelName": "أدخل اسم القناة في حقل اسم القناة {0} إذا كنت تريد تجاوز قناة WebHook. السابق",
|
||||
"aboutKumaURL": "إذا تركت حقل URL في وقت التشغيل KUMA فارغًا ، فسيتم افتراضيًا إلى صفحة GitHub Project.",
|
||||
"emojiCheatSheet": "ورقة الغش في الرموز التعبيرية",
|
||||
"rocket.chat": "صاروخ",
|
||||
"pushover": "مهمة سهلة",
|
||||
"pushy": "انتهازي",
|
||||
"PushByTechulus": "دفع بواسطة Techulus",
|
||||
"octopush": "أوكتوبوش",
|
||||
"promosms": "الترويجيات",
|
||||
"clicksendsms": "نقرات SMS",
|
||||
"lunasea": "لوناسيا",
|
||||
"apprise": "إبلاغ (دعم 50+ خدمات الإخطار)",
|
||||
"GoogleChat": "دردشة Google",
|
||||
"pushbullet": "حماس",
|
||||
"Kook": "كووك",
|
||||
"wayToGetKookBotToken": "قم بإنشاء تطبيق واحصل على رمز الروبوت الخاص بك على {0}",
|
||||
"wayToGetKookGuildID": "قم بتشغيل 'وضع المطور' في إعداد Kook وانقر بزر الماوس الأيمن على النقابة للحصول على معرفه",
|
||||
"Guild ID": "معرف النقابة",
|
||||
"line": "خط",
|
||||
"mattermost": "المادة",
|
||||
"User Key": "مفتاح المستخدم",
|
||||
"Device": "جهاز",
|
||||
"Message Title": "عنوان الرسالة",
|
||||
"Notification Sound": "صوت الإشعار",
|
||||
"More info on": "مزيد من المعلومات حول",
|
||||
"pushoverDesc1": "أولوية الطوارئ (2) لها مهلة افتراضية 30 ثانية بين إعادة المحاولة وستنتهي صلاحيتها بعد ساعة واحدة.",
|
||||
"pushoverDesc2": "إذا كنت ترغب في إرسال إشعارات إلى أجهزة مختلفة ، قم بملء حقل الجهاز.",
|
||||
"SMS Type": "نوع الرسائل القصيرة",
|
||||
"octopushTypePremium": "قسط (سريع - موصى به للتنبيه)",
|
||||
"octopushTypeLowCost": "التكلفة المنخفضة (بطيئة - تم حظرها أحيانًا بواسطة المشغل)",
|
||||
"checkPrice": "تحقق من الأسعار {0}",
|
||||
"apiCredentials": "بيانات اعتماد API",
|
||||
"octopushLegacyHint": "هل تستخدم الإصدار القديم من Octopush (2011-2020) أو الإصدار الجديد؟",
|
||||
"Check octopush prices": "تحقق من أسعار Octopush {0}.",
|
||||
"octopushPhoneNumber": "رقم الهاتف (تنسيق intl على سبيل المثال",
|
||||
"octopushSMSSender": "اسم مرسل الرسائل القصيرة",
|
||||
"LunaSea Device ID": "معرف جهاز Lunasea",
|
||||
"Apprise URL": "إبلاغ عنوان URL",
|
||||
"Example": "مثال",
|
||||
"Read more:": "{0} :قراءة المزيد",
|
||||
"Status:": "{0} :حالة",
|
||||
"Read more": "قراءة المزيد",
|
||||
"appriseInstalled": "تم تثبيت Prosise.",
|
||||
"appriseNotInstalled": "الإبرام غير مثبت. {0}",
|
||||
"Access Token": "رمز وصول",
|
||||
"Channel access token": "قناة الوصول إلى الرمز",
|
||||
"Line Developers Console": "تحكم المطورين",
|
||||
"lineDevConsoleTo": "وحدة المطورين Line Console - {0}",
|
||||
"Basic Settings": "الإعدادات الأساسية",
|
||||
"User ID": "معرف المستخدم",
|
||||
"Messaging API": "واجهة برمجة تطبيقات المراسلة",
|
||||
"wayToGetLineChannelToken": "قم أولاً بالوصول إلى {0} إنشاء مزود وقناة (واجهة برمجة تطبيقات المراسلة) ، ثم يمكنك الحصول على رمز الوصول إلى القناة ومعرف المستخدم من عناصر القائمة المذكورة أعلاه.",
|
||||
"Icon URL": "url url icon",
|
||||
"aboutIconURL": "يمكنك توفير رابط لصورة في \"Icon URL\" لتجاوز صورة الملف الشخصي الافتراضي. لن يتم استخدامه إذا تم تعيين رمز رمز رمز.",
|
||||
"aboutMattermostChannelName": "يمكنك تجاوز القناة الافتراضية التي تنشرها WebHook من خلال إدخال اسم القناة في \"Channel Name\" الحقل. يجب تمكين هذا في إعدادات Webhook Mattern. السابق",
|
||||
"matrix": "مصفوفة",
|
||||
"promosmsTypeEco": "SMS Eco - رخيصة ولكن بطيئة وغالبًا ما تكون محملة. يقتصر فقط على المستفيدين البولنديين.",
|
||||
"promosmsTypeFlash": "SMS Flash - سيتم عرض الرسالة تلقائيًا على جهاز المستلم. يقتصر فقط على المستفيدين البولنديين.",
|
||||
"promosmsTypeFull": "SMS Full - Tier Premium SMS يمكنك استخدام اسم المرسل الخاص بك (تحتاج إلى تسجيل الاسم أولاً). موثوقة للتنبيهات.",
|
||||
"promosmsTypeSpeed": "سرعة الرسائل القصيرة - أولوية قصوى في النظام. سريع وموثوق للغاية ولكنه مكلف (حوالي مرتين من الرسائل القصيرة السعر الكامل).",
|
||||
"promosmsPhoneNumber": "رقم الهاتف (للمستلم البولندي ، يمكنك تخطي رموز المنطقة)",
|
||||
"promosmsSMSSender": "اسم مرسل الرسائل القصيرة",
|
||||
"promosmsAllowLongSMS": "السماح الرسائل القصيرة الطويلة",
|
||||
"Feishu WebHookUrl": "Feishu Webhookurl",
|
||||
"matrixHomeserverURL": "عنوان URL HomeServer (مع HTTP (S)",
|
||||
"Internal Room Id": "معرف الغرفة الداخلية",
|
||||
"matrixDesc1": "يمكنك العثور على معرف الغرفة الداخلي من خلال البحث في القسم المتقدم من إعدادات الغرفة في عميل Matrix الخاص بك. يجب أن تبدو مثل! QMDRCPUIFLWSFJXYE6",
|
||||
"matrixDesc2": "يوصى بشدة بإنشاء مستخدم جديد ولا تستخدم رمز الوصول إلى مستخدم Matrix الخاص بك لأنه سيتيح الوصول الكامل إلى حسابك وجميع الغرف التي انضمت إليها. بدلاً من ذلك ، قم بإنشاء مستخدم جديد ودعوته فقط إلى الغرفة التي تريد تلقيها الإشعار فيها. يمكنك الحصول على رمز الوصول عن طريق تشغيل {0}",
|
||||
"Method": "طريقة",
|
||||
"Body": "الجسم",
|
||||
"Headers": "الرؤوس",
|
||||
"PushUrl": "دفع عنوان URL",
|
||||
"HeadersInvalidFormat": "رؤوس الطلبات غير صالحة JSON",
|
||||
"BodyInvalidFormat": "هيئة الطلب غير صالحة JSON",
|
||||
"Monitor History": "مراقبة التاريخ",
|
||||
"clearDataOlderThan": "الحفاظ على بيانات سجل المراقبة للأيام {0}.",
|
||||
"PasswordsDoNotMatch": "كلمة المرور غير مطابقة.",
|
||||
"records": "السجلات",
|
||||
"One record": "سجل واحد",
|
||||
"steamApiKeyDescription": "لمراقبة خادم لعبة Steam ، تحتاج إلى مفتاح Steam Web-API. يمكنك تسجيل مفتاح API الخاص بك هنا",
|
||||
"Current User": "المستخدم الحالي",
|
||||
"topic": "عنوان",
|
||||
"topicExplanation": "موضوع MQTT لرصد",
|
||||
"successMessage": "نجاح رسالة",
|
||||
"successMessageExplanation": "رسالة MQTT التي ستعتبر نجاحًا",
|
||||
"recent": "الأخيرة",
|
||||
"Done": "فعله",
|
||||
"Info": "معلومات",
|
||||
"Security": "حماية",
|
||||
"Steam API Key": "مفتاح API Steam",
|
||||
"Shrink Database": "تقلص قاعدة البيانات",
|
||||
"Pick a RR-Type...": "اختر نوع RR ...",
|
||||
"Pick Accepted Status Codes...": "اختيار رموز الحالة المقبولة ...",
|
||||
"Default": "تقصير",
|
||||
"HTTP Options": "خيارات HTTP",
|
||||
"Create Incident": "إنشاء حادث",
|
||||
"Title": "لقب",
|
||||
"Content": "المحتوى",
|
||||
"Style": "أسلوب",
|
||||
"info": "معلومات",
|
||||
"warning": "تحذير",
|
||||
"danger": "خطر",
|
||||
"error": "خطأ",
|
||||
"critical": "شديد الأهمية",
|
||||
"primary": "الأولية",
|
||||
"light": "نور",
|
||||
"dark": "ظلام",
|
||||
"Post": "بريد",
|
||||
"Please input title and content": "الرجاء إدخال العنوان والمحتوى",
|
||||
"Created": "مخلوق",
|
||||
"Last Updated": "التحديث الاخير",
|
||||
"Unpin": "إلغاء",
|
||||
"Switch to Light Theme": "التبديل إلى موضوع الضوء",
|
||||
"Switch to Dark Theme": "التبديل إلى موضوع الظلام",
|
||||
"Show Tags": "أضهر العلامات",
|
||||
"Hide Tags": "إخفاء العلامات",
|
||||
"Description": "وصف",
|
||||
"No monitors available.": "لا شاشات المتاحة.",
|
||||
"Add one": "أضف واحدا",
|
||||
"No Monitors": "لا شاشات",
|
||||
"Untitled Group": "مجموعة بلا عنوان",
|
||||
"Services": "خدمات",
|
||||
"Discard": "تجاهل",
|
||||
"Cancel": "يلغي",
|
||||
"Powered by": "مشغل بواسطة",
|
||||
"shrinkDatabaseDescription": "تشغيل فراغ قاعدة البيانات لـ SQLite. إذا تم إنشاء قاعدة البيانات الخاصة بك بعد تمكين 1.10.0 AUTO_VACUUM بالفعل ولا يلزم هذا الإجراء.",
|
||||
"serwersms": "Serwersms.pl",
|
||||
"serwersmsAPIUser": "اسم مستخدم API (بما في ذلك بادئة WebAPI_)",
|
||||
"serwersmsAPIPassword": "كلمة مرور API",
|
||||
"serwersmsPhoneNumber": "رقم الهاتف",
|
||||
"serwersmsSenderName": "اسم مرسل الرسائل القصيرة (مسجل عبر بوابة العملاء)",
|
||||
"smseagle": "smseagle",
|
||||
"smseagleTo": "أرقام الهواتف)",
|
||||
"smseagleGroup": "اسم مجموعة كتب الهاتف (S)",
|
||||
"smseagleContact": "كتاب الاتصال اسم (S)",
|
||||
"smseagleRecipientType": "نوع المستلم",
|
||||
"smseagleRecipient": "المتلقي (المتلقيين) (يجب فصل المتعددة مع فاصلة)",
|
||||
"smseagleToken": "API وصول الرمز المميز",
|
||||
"smseagleUrl": "عنوان URL لجهاز SMSEGLE الخاص بك",
|
||||
"smseagleEncoding": "إرسال Unicode",
|
||||
"smseaglePriority": "أولوية الرسالة (0-9 افتراضي = 0)",
|
||||
"stackfield": "Stackfield",
|
||||
"Customize": "يعدل أو يكيف",
|
||||
"Custom Footer": "تذييل مخصص",
|
||||
"Custom CSS": "لغة تنسيق ويب حسب الطلب",
|
||||
"smtpDkimSettings": "إعدادات DKIM",
|
||||
"smtpDkimDesc": "يرجى الرجوع إلى Nodemailer dkim {0} للاستخدام.",
|
||||
"documentation": "توثيق",
|
||||
"smtpDkimDomain": "اسم النطاق",
|
||||
"smtpDkimKeySelector": "المحدد الرئيسي",
|
||||
"smtpDkimPrivateKey": "مفتاح سري",
|
||||
"smtpDkimHashAlgo": "خوارزمية التجزئة (اختياري)",
|
||||
"smtpDkimheaderFieldNames": "مفاتيح الرأس للتوقيع (اختياري)",
|
||||
"smtpDkimskipFields": "مفاتيح الرأس لا توقيع (اختياري)",
|
||||
"wayToGetPagerDutyKey": "يمكنك الحصول على هذا عن طريق الانتقال إلى الخدمة -> دليل الخدمة -> (حدد خدمة) -> تكامل -> إضافة التكامل. هنا يمكنك البحث عن \"Events API V2\". مزيد من المعلومات {0}",
|
||||
"Integration Key": "مفتاح التكامل",
|
||||
"Integration URL": "URL تكامل",
|
||||
"Auto resolve or acknowledged": "حل السيارات أو الاعتراف به",
|
||||
"do nothing": "لا تفعل شيئا",
|
||||
"auto acknowledged": "اعترف السيارات",
|
||||
"auto resolve": "عزم السيارات",
|
||||
"gorush": "جورش",
|
||||
"alerta": "أليتا",
|
||||
"alertaApiEndpoint": "نقطة نهاية API",
|
||||
"alertaEnvironment": "بيئة",
|
||||
"alertaApiKey": "مفتاح API",
|
||||
"alertaAlertState": "حالة التنبيه",
|
||||
"alertaRecoverState": "استعادة الدولة",
|
||||
"deleteStatusPageMsg": "هل أنت متأكد من حذف صفحة الحالة هذه؟",
|
||||
"Proxies": "وكلاء",
|
||||
"default": "تقصير",
|
||||
"enabled": "تمكين",
|
||||
"setAsDefault": "تعيين كافتراضي",
|
||||
"deleteProxyMsg": "هل أنت متأكد من حذف هذا الوكيل لجميع الشاشات؟",
|
||||
"proxyDescription": "يجب تعيين الوكلاء إلى شاشة للعمل.",
|
||||
"enableProxyDescription": "لن يؤثر هذا الوكيل على طلبات الشاشة حتى يتم تنشيطه. يمكنك التحكم مؤقتًا في تعطيل الوكيل من جميع الشاشات حسب حالة التنشيط.",
|
||||
"setAsDefaultProxyDescription": "سيتم تمكين هذا الوكيل افتراضيًا للشاشات الجديدة. لا يزال بإمكانك تعطيل الوكيل بشكل منفصل لكل شاشة.",
|
||||
"Certificate Chain": "سلسلة الشهادة",
|
||||
"Valid": "صالح",
|
||||
"Invalid": "غير صالح",
|
||||
"AccessKeyId": "معرف AccessKey",
|
||||
"SecretAccessKey": "Accesskey Secret",
|
||||
"PhoneNumbers": "أرقام الهواتف",
|
||||
"TemplateCode": "TemplateCode",
|
||||
"SignName": "اسم تسجيل الدخول",
|
||||
"Sms template must contain parameters: ": "يجب أن يحتوي قالب الرسائل القصيرة على معلمات:",
|
||||
"Bark Endpoint": "نقطة نهاية اللحاء",
|
||||
"Bark Group": "مجموعة اللحاء",
|
||||
"Bark Sound": "صوت اللحاء",
|
||||
"WebHookUrl": "webhookurl",
|
||||
"SecretKey": "Secretkey",
|
||||
"For safety, must use secret key": "للسلامة يجب استخدام المفتاح السري",
|
||||
"Device Token": "رمز الجهاز",
|
||||
"Platform": "منصة",
|
||||
"iOS": "iOS",
|
||||
"Android": "ذكري المظهر",
|
||||
"Huawei": "هواوي",
|
||||
"High": "عالٍ",
|
||||
"Retry": "إعادة المحاولة",
|
||||
"Topic": "عنوان",
|
||||
"WeCom Bot Key": "WECOM BOT KEY",
|
||||
"Setup Proxy": "وكيل الإعداد",
|
||||
"Proxy Protocol": "بروتوكول الوكيل",
|
||||
"Proxy Server": "مخدم بروكسي",
|
||||
"Proxy server has authentication": "خادم الوكيل لديه مصادقة",
|
||||
"User": "المستعمل",
|
||||
"Installed": "المثبتة",
|
||||
"Not installed": "غير مثبت",
|
||||
"Running": "جري",
|
||||
"Not running": "لا يعمل",
|
||||
"Remove Token": "إزالة الرمز المميز",
|
||||
"Start": "بداية",
|
||||
"Stop": "قف",
|
||||
"Uptime Kuma": "وقت التشغيل كوما",
|
||||
"Add New Status Page": "أضف صفحة حالة جديدة",
|
||||
"Slug": "سبيكة",
|
||||
"Accept characters": "قبول الشخصيات",
|
||||
"startOrEndWithOnly": "ابدأ أو ينتهي بـ {0} فقط",
|
||||
"No consecutive dashes": "لا شرطات متتالية",
|
||||
"Next": "التالي",
|
||||
"The slug is already taken. Please choose another slug.": "تم أخذ سبيكة بالفعل. الرجاء اختيار سبيكة أخرى.",
|
||||
"No Proxy": "لا الوكيل",
|
||||
"Authentication": "المصادقة",
|
||||
"HTTP Basic Auth": "HTTP الأساسي Auth",
|
||||
"New Status Page": "صفحة حالة جديدة",
|
||||
"Page Not Found": "الصفحة غير موجودة",
|
||||
"Reverse Proxy": "وكيل عكسي",
|
||||
"Backup": "دعم",
|
||||
"About": "عن",
|
||||
"wayToGetCloudflaredURL": "(قم بتنزيل CloudFlared من {0})",
|
||||
"cloudflareWebsite": "موقع CloudFlare",
|
||||
"Message:": ":رسالة",
|
||||
"Don't know how to get the token? Please read the guide": "لا أعرف كيف تحصل على الرمز المميز؟ يرجى قراءة الدليل",
|
||||
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "قد يضيع الاتصال الحالي إذا كنت تتصل حاليًا عبر نفق CloudFlare. هل أنت متأكد تريد إيقافها؟ اكتب كلمة المرور الحالية لتأكيدها.",
|
||||
"HTTP Headers": "رؤوس HTTP",
|
||||
"Trust Proxy": "الوكيل الثقة",
|
||||
"Other Software": "برامج أخرى",
|
||||
"For example: nginx, Apache and Traefik.": "على سبيل المثال: nginx و Apache و Traefik.",
|
||||
"Please read": "يرجى القراءة",
|
||||
"Subject": "موضوع",
|
||||
"Valid To": "صالحة ل",
|
||||
"Days Remaining": "الأيام المتبقية",
|
||||
"Issuer": "المصدر",
|
||||
"Fingerprint": "بصمة",
|
||||
"No status pages": "لا صفحات الحالة",
|
||||
"Domain Name Expiry Notification": "اسم النطاق إشعار انتهاء الصلاحية",
|
||||
"Proxy": "الوكيل",
|
||||
"Date Created": "تاريخ الإنشاء",
|
||||
"HomeAssistant": "مساعد المنزل",
|
||||
"onebotHttpAddress": "OneBot HTTP عنوان",
|
||||
"onebotMessageType": "نوع رسالة OneBot",
|
||||
"onebotGroupMessage": "مجموعة",
|
||||
"onebotPrivateMessage": "خاص",
|
||||
"onebotUserOrGroupId": "معرف المجموعة/المستخدم",
|
||||
"onebotSafetyTips": "للسلامة يجب ضبط الرمز المميز للوصول",
|
||||
"PushDeer Key": "مفتاح PushDeer",
|
||||
"Footer Text": "نص تذييل",
|
||||
"Show Powered By": "عرض مدعوم من قبل",
|
||||
"Domain Names": "أسماء المجال",
|
||||
"signedInDisp": "وقعت في {0}",
|
||||
"signedInDispDisabled": "معاق المصادقة.",
|
||||
"RadiusSecret": "سر نصف القطر",
|
||||
"RadiusSecretDescription": "السر المشترك بين العميل والخادم",
|
||||
"RadiusCalledStationId": "يسمى معرف المحطة",
|
||||
"RadiusCalledStationIdDescription": "معرف الجهاز المتصل",
|
||||
"RadiusCallingStationId": "معرف محطة الاتصال",
|
||||
"RadiusCallingStationIdDescription": "معرف جهاز الاتصال",
|
||||
"Certificate Expiry Notification": "إشعار انتهاء الصلاحية",
|
||||
"API Username": "اسم المستخدم API",
|
||||
"API Key": "مفتاح API",
|
||||
"Recipient Number": "رقم المستلم",
|
||||
"From Name/Number": "من الاسم/الرقم",
|
||||
"Leave blank to use a shared sender number.": "اترك فارغًا لاستخدام رقم المرسل المشترك.",
|
||||
"Octopush API Version": "إصدار Octopush API",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"endpoint": "نقطة النهاية",
|
||||
"octopushAPIKey": "\"API key\" from HTTP API بيانات اعتماد في لوحة التحكم",
|
||||
"octopushLogin": "\"Login\" من بيانات اعتماد API HTTP في لوحة التحكم",
|
||||
"promosmsLogin": "اسم تسجيل الدخول API",
|
||||
"promosmsPassword": "كلمة مرور API",
|
||||
"pushoversounds pushover": "سداد (افتراضي)",
|
||||
"pushoversounds bike": "دراجة هوائية",
|
||||
"pushoversounds bugle": "بوق",
|
||||
"pushoversounds cashregister": "ماكينة تسجيل المدفوعات النقدية",
|
||||
"pushoversounds classical": "كلاسيكي",
|
||||
"pushoversounds cosmic": "كونية",
|
||||
"pushoversounds falling": "هبوط",
|
||||
"pushoversounds gamelan": "Gamelan",
|
||||
"pushoversounds incoming": "واردة",
|
||||
"pushoversounds intermission": "استراحة",
|
||||
"pushoversounds magic": "سحر",
|
||||
"pushoversounds mechanical": "ميكانيكي",
|
||||
"pushoversounds pianobar": "شريط البيانو",
|
||||
"pushoversounds siren": "صفارة إنذار",
|
||||
"pushoversounds spacealarm": "إنذار الفضاء",
|
||||
"pushoversounds tugboat": "قارب السحب",
|
||||
"pushoversounds alien": "إنذار أجنبي (طويل)",
|
||||
"pushoversounds climb": "تسلق (طويل)",
|
||||
"pushoversounds persistent": "مستمر (طويل)",
|
||||
"pushoversounds echo": "صدى مهووس (طويل)",
|
||||
"pushoversounds updown": "صعودا (طويلة)",
|
||||
"pushoversounds vibrate": "يهتز فقط",
|
||||
"pushoversounds none": "لا شيء (صامت)",
|
||||
"pushyAPIKey": "مفتاح API السري",
|
||||
"pushyToken": "رمز الجهاز",
|
||||
"Show update if available": "عرض التحديث إذا كان ذلك متاحًا",
|
||||
"Also check beta release": "تحقق أيضًا من الإصدار التجريبي",
|
||||
"Using a Reverse Proxy?": "باستخدام وكيل عكسي؟",
|
||||
"Check how to config it for WebSocket": "تحقق من كيفية تكوينه لـ WebSocket",
|
||||
"Steam Game Server": "خادم لعبة البخار",
|
||||
"Most likely causes": "الأسباب المرجحة",
|
||||
"The resource is no longer available.": "لم يعد المورد متاحًا.",
|
||||
"There might be a typing error in the address.": "قد يكون هناك خطأ مطبعي في العنوان.",
|
||||
"What you can try": "ماذا تستطيع أن تجرب",
|
||||
"Retype the address.": "اعد كتابة العنوان.",
|
||||
"Go back to the previous page.": "عد للصفحة السابقة.",
|
||||
"Coming Soon": "قريبا",
|
||||
"wayToGetClickSendSMSToken": "يمكنك الحصول على اسم مستخدم API ومفتاح API من {0}.",
|
||||
"Connection String": "سلسلة الاتصال",
|
||||
"Query": "استفسار",
|
||||
"settingsCertificateExpiry": "شهادة TLS انتهاء الصلاحية",
|
||||
"certificationExpiryDescription": "شاشات HTTPS تضيء عندما تنتهي شهادة TLS في",
|
||||
"Setup Docker Host": "إعداد مضيف Docker",
|
||||
"Connection Type": "نوع الاتصال",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
"deleteDockerHostMsg": "هل أنت متأكد من حذف مضيف Docker لجميع الشاشات؟",
|
||||
"socket": "قابس كهرباء",
|
||||
"tcp": "TCP / HTTP",
|
||||
"Docker Container": "حاوية Docker",
|
||||
"Container Name / ID": "اسم الحاوية / معرف",
|
||||
"Docker Host": "مضيف Docker",
|
||||
"Docker Hosts": "مضيفي Docker",
|
||||
"ntfy Topic": "موضوع ntfy",
|
||||
"Domain": "اِختِصاص",
|
||||
"Workstation": "محطة العمل",
|
||||
"disableCloudflaredNoAuthMsg": "أنت في وضع مصادقة لا توجد كلمة مرور غير مطلوبة.",
|
||||
"trustProxyDescription": "الثقة 'x-forward-*'. إذا كنت ترغب في الحصول على IP العميل الصحيح وكوما في الوقت المناسب مثل Nginx أو Apache ، فيجب عليك تمكين ذلك.",
|
||||
"wayToGetLineNotifyToken": "يمكنك الحصول على رمز الوصول من {0}",
|
||||
"Examples": "أمثلة",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "الرمز المميز للوصول منذ فترة طويلة",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "يمكن إنشاء رمز الوصول منذ فترة طويلة عن طريق النقر على اسم ملف التعريف الخاص بك (أسفل اليسار) والتمرير إلى الأسفل ثم انقر فوق إنشاء الرمز المميز.",
|
||||
"Notification Service": "خدمة الإخطار",
|
||||
"default: notify all devices": "الافتراضي: إخطار جميع الأجهزة",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "يمكن العثور على قائمة بخدمات الإخطار في المساعد المنزلي ضمن \"Developer Tools > Services\" ابحث عن \"notification\" للعثور على اسم جهازك/هاتفك.",
|
||||
"Automations can optionally be triggered in Home Assistant": "يمكن أن يتم تشغيل الأتمتة اختياريًا في مساعد المنزل",
|
||||
"Trigger type": "نوع الزناد",
|
||||
"Event type": "نوع الحدث",
|
||||
"Event data": "بيانات الحدث",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "ثم اختر إجراءً على سبيل المثال قم بتبديل المشهد إلى حيث يكون ضوء RGB أحمر.",
|
||||
"Frontend Version": "إصدار الواجهة الأمامية",
|
||||
"Frontend Version do not match backend version!": "إصدار Frontend لا يتطابق مع الإصدار الخلفي!",
|
||||
"Base URL": "عنوان URL الأساسي",
|
||||
"goAlertInfo": "الهدف هو تطبيق مفتوح المصدر لجدولة الجدولة التلقائية والإشعارات (مثل الرسائل القصيرة أو المكالمات الصوتية). إشراك الشخص المناسب تلقائيًا بالطريقة الصحيحة وفي الوقت المناسب! {0}",
|
||||
"goAlertIntegrationKeyInfo": "احصل على مفتاح تكامل API العام للخدمة في هذا التنسيق \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" عادةً قيمة المعلمة الرمزية لعنوان url المنسق.",
|
||||
"goAlert": "المرمى",
|
||||
"backupOutdatedWarning": "إهمال",
|
||||
"backupRecommend": "يرجى النسخ الاحتياطي لحجم الصوت أو مجلد البيانات (./data/) مباشرة بدلاً من ذلك.",
|
||||
"Optional": "اختياري",
|
||||
"squadcast": "القاء فريقي",
|
||||
"SendKey": "Sendkey",
|
||||
"SMSManager API Docs": "مستندات SMSManager API",
|
||||
"Gateway Type": "نوع البوابة",
|
||||
"SMSManager": "smsmanager",
|
||||
"You can divide numbers with": "يمكنك تقسيم الأرقام مع",
|
||||
"or": "أو",
|
||||
"recurringInterval": "فترة",
|
||||
"Recurring": "يتكرر",
|
||||
"strategyManual": "نشط/غير نشط يدويًا",
|
||||
"warningTimezone": "إنه يستخدم المنطقة الزمنية للخادم",
|
||||
"weekdayShortMon": "الاثنين",
|
||||
"weekdayShortTue": "الثلاثاء",
|
||||
"weekdayShortWed": "تزوج",
|
||||
"weekdayShortThu": "الخميس",
|
||||
"weekdayShortFri": "الجمعة",
|
||||
"weekdayShortSat": "جلس",
|
||||
"weekdayShortSun": "شمس",
|
||||
"dayOfWeek": "يوم من الأسبوع",
|
||||
"dayOfMonth": "يوم من الشهر",
|
||||
"lastDay": "بالأمس",
|
||||
"lastDay1": "آخر يوم من الشهر",
|
||||
"lastDay2": "الثاني في اليوم الأخير من الشهر",
|
||||
"lastDay3": "الثالث في اليوم الأخير من الشهر",
|
||||
"lastDay4": "الرابع في اليوم الأخير من الشهر",
|
||||
"No Maintenance": "لا صيانة",
|
||||
"pauseMaintenanceMsg": "هل أنت متأكد من أن تتوقف مؤقتًا؟",
|
||||
"maintenanceStatus-under-maintenance": "تحت الصيانة",
|
||||
"maintenanceStatus-inactive": "غير نشط",
|
||||
"maintenanceStatus-scheduled": "المقرر",
|
||||
"maintenanceStatus-ended": "انتهى",
|
||||
"maintenanceStatus-unknown": "مجهول",
|
||||
"Display Timezone": "عرض المنطقة الزمنية",
|
||||
"Server Timezone": "المنطقة الزمنية الخادم",
|
||||
"statusPageMaintenanceEndDate": "نهاية",
|
||||
"IconUrl": "url url icon",
|
||||
"Enable DNS Cache": "تمكين ذاكرة التخزين المؤقت DNS",
|
||||
"Enable": "يُمكَِن",
|
||||
"Disable": "إبطال",
|
||||
"dnsCacheDescription": "قد لا يعمل في بعض بيئات IPv6 تعطيله إذا واجهت أي مشكلات.",
|
||||
"Single Maintenance Window": "نافذة صيانة واحدة",
|
||||
"Maintenance Time Window of a Day": "نافذة وقت الصيانة لليوم",
|
||||
"Effective Date Range": "نطاق التاريخ السريع",
|
||||
"Schedule Maintenance": "جدولة الصيانة",
|
||||
"Date and Time": "التاريخ و الوقت",
|
||||
"DateTime Range": "نطاق DateTime",
|
||||
"Strategy": "إستراتيجية",
|
||||
"Free Mobile User Identifier": "معرف مستخدم الهاتف المحمول المجاني",
|
||||
"Free Mobile API Key": "مفتاح واجهة برمجة تطبيقات مجانية للهاتف المحمول",
|
||||
"Enable TLS": "تمكين TLS",
|
||||
"Proto Service Name": "اسم خدمة البروتو",
|
||||
"Proto Method": "طريقة البروتو",
|
||||
"Proto Content": "محتوى proto",
|
||||
"Economy": "اقتصاد",
|
||||
"Lowcost": "تكلفة منخفضة",
|
||||
"high": "عالي",
|
||||
"General Monitor Type": "نوع الشاشة العامة",
|
||||
"Passive Monitor Type": "نوع الشاشة السلبي",
|
||||
"Specific Monitor Type": "نوع شاشة محدد",
|
||||
"dataRetentionTimeError": "يجب أن تكون فترة الاستبقاء 0 أو أكبر",
|
||||
"infiniteRetention": "ضبط على 0 للاحتفاظ لا نهائي.",
|
||||
"confirmDeleteTagMsg": "هل أنت متأكد من أنك تريد حذف هذه العلامة؟ لن يتم حذف الشاشات المرتبطة بهذه العلامة."
|
||||
}
|
695
src/lang/bg-BG.json
Normal file
695
src/lang/bg-BG.json
Normal file
@@ -0,0 +1,695 @@
|
||||
{
|
||||
"languageName": "Български",
|
||||
"checkEverySecond": "Ще се извършва на всеки {0} секунди",
|
||||
"retryCheckEverySecond": "Ще се извършва на всеки {0} секунди",
|
||||
"retriesDescription": "Максимален брой опити преди маркиране на услугата като недостъпна и изпращане на известие",
|
||||
"ignoreTLSError": "Игнорирай TLS/SSL грешки за HTTPS уеб сайтове",
|
||||
"upsideDownModeDescription": "Обръща статуса от достъпен на недостъпен. Ако услугата е достъпна, ще се вижда като НЕДОСТЪПНА.",
|
||||
"maxRedirectDescription": "Максимален брой пренасочвания, които да бъдат следвани. Въведете 0 за да изключите пренасочване.",
|
||||
"acceptedStatusCodesDescription": "Изберете статус кодове, които да се считат за успешен отговор.",
|
||||
"passwordNotMatchMsg": "Повторената парола не съвпада.",
|
||||
"notificationDescription": "Моля, задайте известието към монитор(и), за да функционира.",
|
||||
"keywordDescription": "Търси ключова дума в чист HTML или JSON отговор - чувствителна е към регистъра.",
|
||||
"pauseDashboardHome": "Пауза",
|
||||
"deleteMonitorMsg": "Наистина ли желаете да изтриете този монитор?",
|
||||
"deleteNotificationMsg": "Наистина ли желаете да изтриете това известие за всички монитори?",
|
||||
"resolverserverDescription": "Cloudflare е сървърът по подразбиране, но можете да го промените по всяко време.",
|
||||
"rrtypeDescription": "Изберете ресурсния запис, който желаете да наблюдавате",
|
||||
"pauseMonitorMsg": "Наистина ли желаете да поставите в режим пауза?",
|
||||
"enableDefaultNotificationDescription": "За всеки нов монитор това известие ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.",
|
||||
"clearEventsMsg": "Наистина ли желаете да изтриете всички събития за този монитор?",
|
||||
"clearHeartbeatsMsg": "Наистина ли желаете да изтриете всички записи за честотни проверки на този монитор?",
|
||||
"confirmClearStatisticsMsg": "Наистина ли желаете да изтриете всички статистически данни?",
|
||||
"importHandleDescription": "Изберете 'Пропусни съществуващите', ако желаете да пропуснете всеки монитор или известие със същото име. 'Презапис' ще изтрие всеки съществуващ монитор и известие.",
|
||||
"confirmImportMsg": "Сигурни ли сте, че желаете импортирането на архива? Моля, уверете се, че сте избрали правилната опция за импортиране.",
|
||||
"twoFAVerifyLabel": "Моля, въведете вашия токен код, за да проверите дали 2FA работи:",
|
||||
"tokenValidSettingsMsg": "Токен кодът е валиден! Вече можете да запазите настройките за 2FA.",
|
||||
"confirmEnableTwoFAMsg": "Сигурни ли сте, че желаете да активирате 2FA?",
|
||||
"confirmDisableTwoFAMsg": "Сигурни ли сте, че желаете да изключите 2FA?",
|
||||
"Settings": "Настройки",
|
||||
"Dashboard": "Табло",
|
||||
"New Update": "Налична е актуализация",
|
||||
"Language": "Език",
|
||||
"Appearance": "Изглед",
|
||||
"Theme": "Тема",
|
||||
"General": "Общи",
|
||||
"Version": "Версия",
|
||||
"Check Update On GitHub": "Проверка за актуализация в GitHub",
|
||||
"List": "Списък",
|
||||
"Add": "Добави",
|
||||
"Add New Monitor": "Добави монитор",
|
||||
"Quick Stats": "Кратка статистика",
|
||||
"Up": "Достъпен",
|
||||
"Down": "Недостъпен",
|
||||
"Pending": "Изчаква",
|
||||
"Unknown": "Неизвестен",
|
||||
"Pause": "Пауза",
|
||||
"Name": "Име",
|
||||
"Status": "Статус",
|
||||
"DateTime": "Дата и час",
|
||||
"Message": "Отговор",
|
||||
"No important events": "Все още няма събития",
|
||||
"Resume": "Възобнови",
|
||||
"Edit": "Редактирай",
|
||||
"Delete": "Изтрий",
|
||||
"Current": "Текущ",
|
||||
"Uptime": "Достъпност",
|
||||
"Cert Exp.": "Вал. сертификат",
|
||||
"day": "ден | дни",
|
||||
"-day": "-дни",
|
||||
"hour": "час",
|
||||
"-hour": "-часa",
|
||||
"Response": "Отговор",
|
||||
"Ping": "Пинг",
|
||||
"Monitor Type": "Монитор тип",
|
||||
"Keyword": "Ключова дума",
|
||||
"Friendly Name": "Псевдоним",
|
||||
"URL": "URL Адрес",
|
||||
"Hostname": "Име на хост",
|
||||
"Port": "Порт",
|
||||
"Heartbeat Interval": "Честота на проверка",
|
||||
"Retries": "Повторни опити",
|
||||
"Heartbeat Retry Interval": "Честота на повторните опити",
|
||||
"Advanced": "Разширени",
|
||||
"Upside Down Mode": "Обърнат режим",
|
||||
"Max. Redirects": "Макс. брой пренасочвания",
|
||||
"Accepted Status Codes": "Допустими статус кодове",
|
||||
"Save": "Запази",
|
||||
"Notifications": "Известия",
|
||||
"Not available, please setup.": "Не са налични. Моля, настройте.",
|
||||
"Setup Notification": "Настрой известие",
|
||||
"Light": "Светла",
|
||||
"Dark": "Тъмна",
|
||||
"Auto": "Автоматично",
|
||||
"Theme - Heartbeat Bar": "Тема - поле проверки",
|
||||
"Normal": "Нормално",
|
||||
"Bottom": "Долу",
|
||||
"None": "Без",
|
||||
"Timezone": "Часова зона",
|
||||
"Search Engine Visibility": "Видимост за търсачки",
|
||||
"Allow indexing": "Разреши индексиране",
|
||||
"Discourage search engines from indexing site": "Не позволявай на търсачките да индексират този сайт",
|
||||
"Change Password": "Промяна на парола",
|
||||
"Current Password": "Текуща парола",
|
||||
"New Password": "Нова парола",
|
||||
"Repeat New Password": "Повторете новата парола",
|
||||
"Update Password": "Актуализирай паролата",
|
||||
"Disable Auth": "Изключи удостоверяване",
|
||||
"Enable Auth": "Активирай удостоверяване",
|
||||
"disableauth.message1": "Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?",
|
||||
"disableauth.message2": "Използва се в случаите, когато <strong>има настроен алтернативен метод за удостоверяване</strong> преди Uptime Kuma, например Cloudflare Access, Authelia или друг механизъм за удостоверяване.",
|
||||
"Please use this option carefully!": "Моля, използвайте с повишено внимание!",
|
||||
"Logout": "Изход от профила",
|
||||
"Leave": "Отказ",
|
||||
"I understand, please disable": "Разбирам. Моля, изключи",
|
||||
"Confirm": "Потвърдете",
|
||||
"Yes": "Да",
|
||||
"No": "Не",
|
||||
"Username": "Потребител",
|
||||
"Password": "Парола",
|
||||
"Remember me": "Запомни ме",
|
||||
"Login": "Вход",
|
||||
"No Monitors, please": "Все още няма монитори. Моля,",
|
||||
"add one": "добавете един.",
|
||||
"Notification Type": "Тип известие",
|
||||
"Email": "Имейл",
|
||||
"Test": "Тест",
|
||||
"Certificate Info": "Информация за сертификат",
|
||||
"Resolver Server": "Преобразуващ (DNS) сървър",
|
||||
"Resource Record Type": "Тип запис",
|
||||
"Last Result": "Последен резултат",
|
||||
"Create your admin account": "Създаване на администриращ акаунт",
|
||||
"Repeat Password": "Повторете паролата",
|
||||
"Import Backup": "Импорт на архив",
|
||||
"Export Backup": "Експорт на архив",
|
||||
"Export": "Експорт",
|
||||
"Import": "Импорт",
|
||||
"respTime": "Време за отговор (ms)",
|
||||
"notAvailableShort": "Няма",
|
||||
"Default enabled": "Активирано по подразбиране",
|
||||
"Apply on all existing monitors": "Приложи върху всички съществуващи монитори",
|
||||
"Create": "Създай",
|
||||
"Clear Data": "Изтрий данни",
|
||||
"Events": "Събития",
|
||||
"Heartbeats": "Проверки",
|
||||
"Auto Get": "Авт. попълване",
|
||||
"backupDescription": "Можете да архивирате всички монитори и всички известия в JSON файл.",
|
||||
"backupDescription2": "PS: Имайте предвид, че данните за история и събития няма да бъдат включени.",
|
||||
"backupDescription3": "Чувствителни данни, като токен кодове за известия, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.",
|
||||
"alertNoFile": "Моля, изберете файл за импортиране.",
|
||||
"alertWrongFileType": "Моля, изберете JSON файл.",
|
||||
"Clear all statistics": "Изтрий цялата статистика",
|
||||
"Skip existing": "Пропусни съществуващите",
|
||||
"Overwrite": "Презапиши",
|
||||
"Options": "Опции",
|
||||
"Keep both": "Запази двете",
|
||||
"Verify Token": "Провери токен код",
|
||||
"Setup 2FA": "Настройка 2FA",
|
||||
"Enable 2FA": "Активирай 2FA",
|
||||
"Disable 2FA": "Деактивирай 2FA",
|
||||
"2FA Settings": "Настройка за 2FA",
|
||||
"Two Factor Authentication": "Двуфакторно удостоверяване",
|
||||
"Active": "Активно",
|
||||
"Inactive": "Неактивно",
|
||||
"Token": "Токен код",
|
||||
"Show URI": "Покажи URI",
|
||||
"Tags": "Етикети",
|
||||
"Add New below or Select...": "Добавете нов по-долу или изберете…",
|
||||
"Tag with this name already exist.": "Етикет с това име вече съществува.",
|
||||
"Tag with this value already exist.": "Етикет с тази стойност вече съществува.",
|
||||
"color": "цвят",
|
||||
"value (optional)": "стойност (по желание)",
|
||||
"Gray": "Сиво",
|
||||
"Red": "Червено",
|
||||
"Orange": "Оранжево",
|
||||
"Green": "Зелено",
|
||||
"Blue": "Синьо",
|
||||
"Indigo": "Индиго",
|
||||
"Purple": "Лилаво",
|
||||
"Pink": "Розово",
|
||||
"Search...": "Търси…",
|
||||
"Avg. Ping": "Ср. пинг",
|
||||
"Avg. Response": "Ср. отговор",
|
||||
"Entry Page": "Основна страница",
|
||||
"statusPageNothing": "Все още няма нищо тук. Моля, добавете група или монитор.",
|
||||
"No Services": "Няма Услуги",
|
||||
"All Systems Operational": "Всички услуги са достъпни",
|
||||
"Partially Degraded Service": "Част от услугите са недостъпни",
|
||||
"Degraded Service": "Всички услуги са недостъпни",
|
||||
"Add Group": "Добави група",
|
||||
"Add a monitor": "Добави монитор",
|
||||
"Edit Status Page": "Редактиране Статус страница",
|
||||
"Go to Dashboard": "Към Таблото",
|
||||
"telegram": "Telegram",
|
||||
"webhook": "Уеб кука",
|
||||
"smtp": "Имейл (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 (Поддържа 50+ услуги за известяване)",
|
||||
"pushbullet": "Pushbullet",
|
||||
"line": "Line Messenger",
|
||||
"mattermost": "Mattermost",
|
||||
"Status Page": "Статус страница",
|
||||
"Status Pages": "Статус страници",
|
||||
"Primary Base URL": "Основен базов URL адрес",
|
||||
"Push URL": "Генериран Push URL адрес",
|
||||
"needPushEvery": "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди.",
|
||||
"pushOptionalParams": "Допълнителни, но не задължителни параметри: {0}",
|
||||
"defaultNotificationName": "Моето {notification} известие ({number})",
|
||||
"here": "тук",
|
||||
"Required": "Задължително поле",
|
||||
"Bot Token": "Бот токен",
|
||||
"wayToGetTelegramToken": "Можете да получите токен от {0}.",
|
||||
"Chat ID": "Чат ID",
|
||||
"supportTelegramChatID": "Поддържа Direct Chat / Group / Channel's Chat ID",
|
||||
"wayToGetTelegramChatID": "Можете да получите вашето чат ID, като изпратите съобщение на бота, след което е нужно да посетите този URL адрес за да го видите:",
|
||||
"YOUR BOT TOKEN HERE": "ВАШИЯТ БОТ ТОКЕН ТУК",
|
||||
"chatIDNotFound": "Чат ID не е намерено. Моля, първо изпратете съобщение до този бот",
|
||||
"Post URL": "Post URL адрес",
|
||||
"Content Type": "Тип съдържание",
|
||||
"webhookJsonDesc": "{0} е подходящ за всички съвременни http сървъри, като например express.js",
|
||||
"webhookFormDataDesc": "{multipart} е подходящ за PHP, нужно е да анализирате json чрез {decodeFunction}",
|
||||
"secureOptionNone": "Няма (25) / STARTTLS (587)",
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
"Ignore TLS Error": "Игнорирай TLS грешките",
|
||||
"From Email": "От имейл адрес",
|
||||
"emailCustomSubject": "Модифициране на тема",
|
||||
"To Email": "Получател имейл адрес",
|
||||
"smtpCC": "Явно копие до имейл адрес:",
|
||||
"smtpBCC": "Скрито копие до имейл адрес:",
|
||||
"Discord Webhook URL": "Discord URL адрес на уеб кука",
|
||||
"wayToGetDiscordURL": "Може да създадете, от меню \"Настройки на сървъра\" -> \"Интеграции\" -> \"Уеб куки\" -> \"Нова уеб кука\"",
|
||||
"Bot Display Name": "Име на бота, което да се показва",
|
||||
"Prefix Custom Message": "Модифицирано обръщение",
|
||||
"Hello @everyone is...": "Здравейте, {'@'}everyone е…",
|
||||
"Webhook URL": "Уеб кука URL адрес",
|
||||
"wayToGetTeamsURL": "Можете да научите как се създава URL адрес за уеб кука {0}.",
|
||||
"Number": "Номер",
|
||||
"Recipients": "Получатели",
|
||||
"needSignalAPI": "Необходимо е да разполагате със Signal клиент с REST API.",
|
||||
"wayToCheckSignalURL": "Може да посетите този URL адрес, ако се нуждаете от помощ при настройването:",
|
||||
"signalImportant": "ВАЖНО: Не може да смесвате \"Групи\" и \"Номера\" в поле \"Получатели\"!",
|
||||
"Application Token": "Токен код за приложението",
|
||||
"Server URL": "URL адрес на сървъра",
|
||||
"Priority": "Приоритет",
|
||||
"Icon Emoji": "Иконка Емотикон",
|
||||
"Channel Name": "Канал име",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL адрес",
|
||||
"aboutWebhooks": "Повече информация относно уеб куки на: {0}",
|
||||
"aboutChannelName": "Въведете името на канала в поле {0} \"Канал име\", ако желаете да заобиколите канала от уеб куката. Например: #other-channel",
|
||||
"aboutKumaURL": "Ако оставите празно полето \"Uptime Kuma URL адрес\", по подразбиране ще се използва GitHub страницата на проекта.",
|
||||
"emojiCheatSheet": "Подсказки за емотикони: {0}",
|
||||
"User Key": "Потребителски ключ",
|
||||
"Device": "Устройство",
|
||||
"Message Title": "Заглавие на съобщението",
|
||||
"Notification Sound": "Звуков сигнал",
|
||||
"More info on:": "Повече информация на: {0}",
|
||||
"pushoverDesc1": "Приоритет Спешно (2) по подразбиране изчаква 30 секунди между повторните опити и изтича след 1 час.",
|
||||
"pushoverDesc2": "Ако желаете да изпратите известия до различни устройства, попълнете полето Устройство.",
|
||||
"SMS Type": "SMS тип",
|
||||
"octopushTypePremium": "Премиум (Бърз - препоръчителен в случай на тревога)",
|
||||
"octopushTypeLowCost": "Евтин (Бавен - понякога бива блокиран от оператора)",
|
||||
"checkPrice": "Тарифни планове на {0}:",
|
||||
"octopushLegacyHint": "Дали използвате съвместима версия на Octopush (2011-2020) или нова версия?",
|
||||
"Check octopush prices": "Тарифни планове на octopush {0}.",
|
||||
"octopushPhoneNumber": "Телефонен номер (в международен формат, например: +33612345678) ",
|
||||
"octopushSMSSender": "SMS подател Име: 3-11 знака - букви, цифри и интервал (a-zA-Z0-9)",
|
||||
"LunaSea Device ID": "LunaSea ID на устройство",
|
||||
"Apprise URL": "Apprise URL адрес",
|
||||
"Example:": "Пример: {0}",
|
||||
"Read more:": "Научете повече: {0}",
|
||||
"Status:": "Статус: {0}",
|
||||
"Read more": "Научете повече",
|
||||
"appriseInstalled": "Apprise е инсталиран.",
|
||||
"appriseNotInstalled": "Apprise не е инсталиран. {0}",
|
||||
"Access Token": "Токен код за достъп",
|
||||
"Channel access token": "Канал токен код",
|
||||
"Line Developers Console": "Line - Конзола за разработчици",
|
||||
"lineDevConsoleTo": "Line - Конзола за разработчици - {0}",
|
||||
"Basic Settings": "Основни настройки",
|
||||
"User ID": "Потребител ID",
|
||||
"Messaging API": "API за съобщаване",
|
||||
"wayToGetLineChannelToken": "Необходимо е първо да посетите {0}, за да създадете (Messaging API) за доставчик и канал, след което може да вземете токен кода за канал и потребителско ID от споменатите по-горе елементи на менюто.",
|
||||
"Icon URL": "URL адрес за иконка",
|
||||
"aboutIconURL": "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.",
|
||||
"aboutMattermostChannelName": "Може да замените канала по подразбиране, към който публикува уеб куката, като въведете името на канала в полето \"Канал име\". Трябва да бъде активирано в настройките за уеб кука на Mattermost. Например: #other-channel",
|
||||
"matrix": "Matrix",
|
||||
"promosmsTypeEco": "SMS ECO - евтин, но бавен. Често е претоварен. Само за получатели от Полша.",
|
||||
"promosmsTypeFlash": "SMS FLASH - Съобщението автоматично се показва на устройството на получателя. Само за получатели от Полша.",
|
||||
"promosmsTypeFull": "SMS FULL - Високо ниво на SMS услуга. Може да използвате Вашето име като подател (Необходимо е първо да регистрирате името). Надежден метод за съобщения тип тревога.",
|
||||
"promosmsTypeSpeed": "SMS SPEED - Най-висок приоритет в системата. Много бърза и надеждна, но същевременно скъпа услуга. (Около два пъти по-висока цена в сравнение с SMS FULL).",
|
||||
"promosmsPhoneNumber": "Телефонен номер (за получатели от Полша, може да пропуснете въвеждането на код за населено място)",
|
||||
"promosmsSMSSender": "SMS Подател име: Предварително регистрирано име или някое от имената по подразбиране: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||
"Feishu WebHookUrl": "Feishu URL адрес за уеб кука",
|
||||
"matrixHomeserverURL": "Сървър URL адрес (започва с http(s):// и порт по желание)",
|
||||
"Internal Room Id": "ID на вътрешна стая",
|
||||
"matrixDesc1": "Може да намерите \"ID на вътрешна стая\" в разширените настройки на стаята във вашия Matrix клиент. Примерен изглед: !QMdRCpUIfLwsfjxye6:home.server.",
|
||||
"matrixDesc2": "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребител, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известията. Токен код за достъп ще получите изпълнявайки {0}",
|
||||
"Method": "Метод",
|
||||
"Body": "Съобщение",
|
||||
"Headers": "Хедъри",
|
||||
"PushUrl": "Push URL адрес",
|
||||
"HeadersInvalidFormat": "Заявените хедъри не са валидни JSON: ",
|
||||
"BodyInvalidFormat": "Заявеното съобщение не е валиден JSON: ",
|
||||
"Monitor History": "История на мониторите",
|
||||
"clearDataOlderThan": "Ще се съхранява за {0} дни.",
|
||||
"records": "записа",
|
||||
"One record": "Един запис",
|
||||
"steamApiKeyDescription": "За да мониторирате Steam Gameserver се нуждаете от Steam Web-API ключ. Може да регистрирате Вашия API ключ тук: ",
|
||||
"clicksendsms": "ClickSend SMS",
|
||||
"apiCredentials": "API удостоверяване",
|
||||
"PasswordsDoNotMatch": "Паролите не съвпадат.",
|
||||
"Current User": "Текущ потребител",
|
||||
"recent": "Скорошни",
|
||||
"shrinkDatabaseDescription": "Инициира \"VACUUM\" за \"SQLite\" база данни. Ако Вашата база данни е създадена след версия 1.10.0, \"AUTO_VACUUM\" функцията е активна и това действие не е нужно.",
|
||||
"Done": "Готово",
|
||||
"Info": "Информация",
|
||||
"Security": "Сигурност",
|
||||
"Steam API Key": "Steam API ключ",
|
||||
"Shrink Database": "Редуцирай базата данни",
|
||||
"Pick a RR-Type...": "Изберете вида на ресурсния запис за мониториране…",
|
||||
"Pick Accepted Status Codes...": "Изберете статус кодове, които да се считат за успешен отговор…",
|
||||
"Default": "По подразбиране",
|
||||
"HTTP Options": "HTTP Опции",
|
||||
"Create Incident": "Създаване на инцидент",
|
||||
"Title": "Заглавие",
|
||||
"Content": "Съдържание",
|
||||
"Style": "Стил",
|
||||
"info": "информация",
|
||||
"warning": "предупреждение",
|
||||
"danger": "опасност",
|
||||
"primary": "основен",
|
||||
"light": "светъл",
|
||||
"dark": "тъмен",
|
||||
"Post": "Публикувай",
|
||||
"Please input title and content": "Моля, въведете заглавие и съдържание",
|
||||
"Created": "Създаден",
|
||||
"Last Updated": "Последно обновен",
|
||||
"Unpin": "Откачи",
|
||||
"Switch to Light Theme": "Превключи към светла тема",
|
||||
"Switch to Dark Theme": "Превключи към тъмна тема",
|
||||
"Show Tags": "Покажи етикети",
|
||||
"Hide Tags": "Скрий етикети",
|
||||
"Description": "Описание",
|
||||
"No monitors available.": "Няма налични монитори.",
|
||||
"Add one": "Добави един",
|
||||
"No Monitors": "Няма монитори",
|
||||
"Untitled Group": "Група без заглавие",
|
||||
"Services": "Услуги",
|
||||
"Discard": "Отмени",
|
||||
"Cancel": "Отмени",
|
||||
"Powered by": "Създадено чрез",
|
||||
"serwersms": "SerwerSMS.pl",
|
||||
"serwersmsAPIUser": "API Потребителско име (вкл. webapi_ prefix)",
|
||||
"serwersmsAPIPassword": "API Парола",
|
||||
"serwersmsPhoneNumber": "Телефон номер",
|
||||
"serwersmsSenderName": "SMS Подател име (регистриран през клиентския портал)",
|
||||
"stackfield": "Stackfield",
|
||||
"smtpDkimSettings": "DKIM Настройки",
|
||||
"smtpDkimDesc": "Моля, вижте {0} на Nodemailer DKIM за инструкции.",
|
||||
"documentation": "документацията",
|
||||
"smtpDkimDomain": "Домейн",
|
||||
"smtpDkimKeySelector": "Селектор на ключ",
|
||||
"smtpDkimPrivateKey": "Частен ключ",
|
||||
"smtpDkimHashAlgo": "Хеш алгоритъм (по желание)",
|
||||
"smtpDkimheaderFieldNames": "Хедър ключове за подписване (по желание)",
|
||||
"smtpDkimskipFields": "Хедър ключове, които да не се подписват (по желание)",
|
||||
"PushByTechulus": "Push от Techulus",
|
||||
"GoogleChat": "Google Chat (Само за работното пространство на Google)",
|
||||
"gorush": "Gorush",
|
||||
"alerta": "Alerta",
|
||||
"alertaApiEndpoint": "Крайна точка на API",
|
||||
"alertaEnvironment": "Среда",
|
||||
"alertaApiKey": "API Ключ",
|
||||
"alertaAlertState": "Състояние на тревога",
|
||||
"alertaRecoverState": "Състояние на възстановяване",
|
||||
"deleteStatusPageMsg": "Сигурни ли сте, че желаете да изтриете тази статус страница?",
|
||||
"Proxies": "Прокси",
|
||||
"default": "По подразбиране",
|
||||
"enabled": "Активирано",
|
||||
"setAsDefault": "Зададен по подразбиране",
|
||||
"deleteProxyMsg": "Сигурни ли сте, че желаете да изтриете това прокси за всички монитори?",
|
||||
"proxyDescription": "За да функционират трябва да бъдат зададени към монитор.",
|
||||
"enableProxyDescription": "Това прокси няма да има ефект върху заявките за мониторинг, докато не бъде активирано. Може да контролирате временното деактивиране на проксито от всички монитори чрез статуса на активиране.",
|
||||
"setAsDefaultProxyDescription": "Това прокси ще бъде активно по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.",
|
||||
"Certificate Chain": "Верига на сертификата",
|
||||
"Valid": "Валиден",
|
||||
"Invalid": "Невалиден",
|
||||
"AccessKeyId": "ID на ключ за достъп",
|
||||
"SecretAccessKey": "Тайна на ключа за достъп",
|
||||
"PhoneNumbers": "Телефонни номера",
|
||||
"TemplateCode": "Шаблон Код",
|
||||
"SignName": "Знак име",
|
||||
"Sms template must contain parameters: ": "SMS шаблонът трябва да съдържа следните параметри: ",
|
||||
"Bark Endpoint": "Bark крайна точка",
|
||||
"WebHookUrl": "URL адрес на уеб кука",
|
||||
"SecretKey": "Таен ключ",
|
||||
"For safety, must use secret key": "За сигурност, трябва да се използва таен ключ",
|
||||
"Device Token": "Токен за устройство",
|
||||
"Platform": "Платформа",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Висок",
|
||||
"Retry": "Повтори",
|
||||
"Topic": "Тема",
|
||||
"WeCom Bot Key": "WeCom бот ключ",
|
||||
"Setup Proxy": "Настрой прокси",
|
||||
"Proxy Protocol": "Прокси протокол",
|
||||
"Proxy Server": "Прокси сървър",
|
||||
"Proxy server has authentication": "Прокси сървърът е с удостоверяване",
|
||||
"User": "Потребител",
|
||||
"Installed": "Инсталиран",
|
||||
"Not installed": "Не е инсталиран",
|
||||
"Running": "Работи",
|
||||
"Not running": "Не работи",
|
||||
"Remove Token": "Премахни токен",
|
||||
"Start": "Стартирай",
|
||||
"Stop": "Спри",
|
||||
"Uptime Kuma": "Uptime Kuma",
|
||||
"Add New Status Page": "Добави нова статус страница",
|
||||
"Slug": "Слъг",
|
||||
"Accept characters:": "Приеми символи:",
|
||||
"startOrEndWithOnly": "Започва или завършва само с {0}",
|
||||
"No consecutive dashes": "Без последователни тирета",
|
||||
"Next": "Следващ",
|
||||
"The slug is already taken. Please choose another slug.": "Този слъг вече се използва. Моля изберете друг.",
|
||||
"No Proxy": "Без прокси",
|
||||
"Authentication": "Удостоверяване",
|
||||
"HTTP Basic Auth": "HTTP основно удостоверяване",
|
||||
"New Status Page": "Нова статус страница",
|
||||
"Page Not Found": "Страницата не е открита",
|
||||
"Reverse Proxy": "Ревърс прокси",
|
||||
"Backup": "Архивиране",
|
||||
"About": "Относно",
|
||||
"wayToGetCloudflaredURL": "(Свалете \"cloudflared\" от {0})",
|
||||
"cloudflareWebsite": "Cloudflare уеб сайт",
|
||||
"Message:": "Съобщение:",
|
||||
"Don't know how to get the token? Please read the guide:": "Не знаете как да вземете токен? Моля, прочетете ръководството:",
|
||||
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Текущата връзка може да прекъсне ако в момента сте свързани чрез \"Cloudflare Tunnel\". Сигурни ли сте, че желаете да го спрете? Въведете Вашата текуща парола за да потвърдите.",
|
||||
"Other Software": "Друг софтуер",
|
||||
"For example: nginx, Apache and Traefik.": "Например: Nginx, Apache и Traefik.",
|
||||
"Please read": "Моля, прочетете",
|
||||
"Subject:": "Тема:",
|
||||
"Valid To:": "Валиден до:",
|
||||
"Days Remaining:": "Оставащи дни:",
|
||||
"Issuer:": "Издател:",
|
||||
"Fingerprint:": "Пръстов отпечатък:",
|
||||
"No status pages": "Няма статус страници",
|
||||
"topic": "Тема",
|
||||
"topicExplanation": "MQTT тема за мониториране",
|
||||
"successMessage": "Съобщение при успех",
|
||||
"successMessageExplanation": "MQTT съобщение, което ще бъде считано за успех",
|
||||
"Customize": "Персонализирай",
|
||||
"Custom Footer": "Персонализиран долен колонтитул",
|
||||
"Custom CSS": "Потребителски CSS",
|
||||
"Domain Name Expiry Notification": "Известие при изтичащ домейн",
|
||||
"Proxy": "Прокси",
|
||||
"Date Created": "Дата на създаване",
|
||||
"onebotHttpAddress": "OneBot HTTP адрес",
|
||||
"onebotMessageType": "OneBot тип съобщение",
|
||||
"onebotGroupMessage": "Група",
|
||||
"onebotPrivateMessage": "Лично",
|
||||
"onebotUserOrGroupId": "Група/Потребител ID",
|
||||
"onebotSafetyTips": "С цел безопасност трябва да зададете токен код за достъп",
|
||||
"PushDeer Key": "PushDeer ключ",
|
||||
"Footer Text": "Текст долен колонтитул",
|
||||
"Show Powered By": "Покажи \"Създадено чрез\"",
|
||||
"Domain Names": "Домейни",
|
||||
"signedInDisp": "Вписан като {0}",
|
||||
"signedInDispDisabled": "Удостоверяването е изключено.",
|
||||
"Certificate Expiry Notification": "Известие за изтичане валидността на сертификата",
|
||||
"API Username": "API Потребител",
|
||||
"API Key": "API Ключ",
|
||||
"Recipient Number": "Номер на получателя",
|
||||
"From Name/Number": "От Име/Номер",
|
||||
"Leave blank to use a shared sender number.": "Оставете празно, за да използвате споделен номер на подател.",
|
||||
"Octopush API Version": "Octopush API версия",
|
||||
"Legacy Octopush-DM": "Octopush-DM старa версия",
|
||||
"endpoint": "крайна точка",
|
||||
"octopushAPIKey": "\"API ключ\" от HTTP API удостоверяване в контролния панел",
|
||||
"octopushLogin": "\"Вписване\" от HTTP API удостоверяване в контролния панел",
|
||||
"promosmsLogin": "API Потребителско име",
|
||||
"promosmsPassword": "API Парола",
|
||||
"pushoversounds pushover": "Pushover (по подразбиране)",
|
||||
"pushoversounds bike": "Велосипед",
|
||||
"pushoversounds bugle": "Тромпет",
|
||||
"pushoversounds cashregister": "Касов апарат",
|
||||
"pushoversounds classical": "Класическа музика",
|
||||
"pushoversounds cosmic": "Космически",
|
||||
"pushoversounds falling": "Падащ",
|
||||
"pushoversounds gamelan": "Игра в мрежа",
|
||||
"pushoversounds incoming": "Входящ",
|
||||
"pushoversounds intermission": "Прекъсване",
|
||||
"pushoversounds magic": "Магия",
|
||||
"pushoversounds mechanical": "Механичен",
|
||||
"pushoversounds pianobar": "Пиано бар",
|
||||
"pushoversounds siren": "Сирена",
|
||||
"pushoversounds spacealarm": "Космическа аларма",
|
||||
"pushoversounds tugboat": "Буксир",
|
||||
"pushoversounds alien": "Извънземна аларма (дълъг)",
|
||||
"pushoversounds climb": "Изкачване (дълъг)",
|
||||
"pushoversounds persistent": "Постоянен (дълъг)",
|
||||
"pushoversounds echo": "Pushover ехо (дълъг)",
|
||||
"pushoversounds updown": "Горе долу (дълъг)",
|
||||
"pushoversounds vibrate": "Само вибрация",
|
||||
"pushoversounds none": "Без (тих)",
|
||||
"pushyAPIKey": "Таен API ключ",
|
||||
"pushyToken": "Токен на устройство",
|
||||
"Show update if available": "Покажи актуализация, ако е налична",
|
||||
"Also check beta release": "Проверявай и за бета версии",
|
||||
"Using a Reverse Proxy?": "Използвате ревърс прокси?",
|
||||
"Check how to config it for WebSocket": "Проверете как да го конфигурирате за WebSocket",
|
||||
"Steam Game Server": "Steam Game сървър",
|
||||
"Most likely causes:": "Най-вероятни причини:",
|
||||
"The resource is no longer available.": "Ресурсът вече не е наличен.",
|
||||
"There might be a typing error in the address.": "Възможно е да е допусната грешка при изписването на адреса.",
|
||||
"What you can try:": "Може да опитате:",
|
||||
"Retype the address.": "Повторно въвеждане на адреса.",
|
||||
"Go back to the previous page.": "Да се върнете към предишната страница.",
|
||||
"Coming Soon": "Очаквайте скоро",
|
||||
"wayToGetClickSendSMSToken": "Може да получите API потребителско име и API ключ от {0} .",
|
||||
"dnsPortDescription": "DNS порт на сървъра. По подразбиране е 53, но може да бъде променен по всяко време.",
|
||||
"error": "грешка",
|
||||
"critical": "критично",
|
||||
"wayToGetPagerDutyKey": "Може да го получите като посетите Service -> Service Directory -> (Select a service) -> Integrations -> Add integration. Тук трябва да потърсите \"Events API V2\". Повече информация {0}",
|
||||
"Integration Key": "Ключ за интегриране",
|
||||
"Integration URL": "URL адрес за интеграция",
|
||||
"Auto resolve or acknowledged": "Автоматично разрешаване или потвърждаване",
|
||||
"do nothing": "не прави нищо",
|
||||
"auto acknowledged": "автоматично потвърждаване",
|
||||
"auto resolve": "автоматично разрешаване",
|
||||
"Connection String": "Стринг за връзка",
|
||||
"Query": "Заявка",
|
||||
"settingsCertificateExpiry": "Изтичане валидността на TLS сертификата",
|
||||
"certificationExpiryDescription": "HTTPS мониторите ще задействат известие, ако е наличен изтичащ TLS сертификат, през следващите:",
|
||||
"ntfy Topic": "ntfy Тема",
|
||||
"Domain": "Домейн",
|
||||
"Workstation": "Работна станция",
|
||||
"disableCloudflaredNoAuthMsg": "Тъй като сте в режим \"No Auth mode\", парола не се изисква.",
|
||||
"wayToGetLineNotifyToken": "Може да получите токен код за достъп от {0}",
|
||||
"resendEveryXTimes": "Изпращай повторно на всеки {0} пъти",
|
||||
"resendDisabled": "Повторното изпращане е изключено",
|
||||
"Resend Notification if Down X times consequently": "Повторно изпращане на известие, ако е недостъпен X пъти последователно",
|
||||
"Bark Group": "Bark група",
|
||||
"Bark Sound": "Bark звук",
|
||||
"HTTP Headers": "HTTP хедъри",
|
||||
"Trust Proxy": "Доверено Proxy",
|
||||
"HomeAssistant": "Home Assistant",
|
||||
"RadiusSecret": "Radius таен код",
|
||||
"RadiusSecretDescription": "Споделен таен код между клиент и сървър",
|
||||
"RadiusCalledStationId": "Повиквана станция ID",
|
||||
"RadiusCalledStationIdDescription": "Идентификатор на повикваното устройство",
|
||||
"RadiusCallingStationId": "Повикваща станция ID",
|
||||
"RadiusCallingStationIdDescription": "Идентификатор на повикващото устройство",
|
||||
"Setup Docker Host": "Настройка на Docker хост",
|
||||
"Connection Type": "Тип свързване",
|
||||
"Docker Daemon": "Docker демон",
|
||||
"deleteDockerHostMsg": "Сигурни ли сте, че желаете да изтриете този Docker хост за всички монитори?",
|
||||
"socket": "Сокет",
|
||||
"tcp": "TCP / HTTP",
|
||||
"Docker Container": "Docker контейнер",
|
||||
"Container Name / ID": "Име на контейнер / ID",
|
||||
"Docker Host": "Docker хост",
|
||||
"Docker Hosts": "Docker хостове",
|
||||
"trustProxyDescription": "Доверяване на 'X-Forwarded-*' хедърите. В случай, че желаете да получавате реалния IP адрес на клиента и Uptime Kuma е зад системи като Nginx или Apache, трябва да разрешите тази опция.",
|
||||
"Examples": "Примери",
|
||||
"Home Assistant URL": "Home Assistant URL адрес",
|
||||
"Long-Lived Access Token": "Long-Lived токен за достъп",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Long-Lived Access Token можете да създадете, като кликнете върху името на профила си (долу ляво) и превъртите до най-долу, след това кликнете върху Създаване на токен. ",
|
||||
"Notification Service": "Услуга за известяване",
|
||||
"default: notify all devices": "по подразбиране: извести всички устройства",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Списък с услугите за известяване може да бъде намерен в Home Assistant под \"Developer Tools > Services\", там потърсете \"notification\", за да намерите името на вашето устройство/телефон.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Автоматизациите могат да се задействат при нужда в Home Assistant:",
|
||||
"Trigger type:": "Задействане тип:",
|
||||
"Event type:": "Събитие тип:",
|
||||
"Event data:": "Събитие данни:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "След което изберете действие, например да превключите сцената, където RGB светлината е червена.",
|
||||
"Frontend Version": "Фронтенд версия",
|
||||
"Frontend Version do not match backend version!": "Фронтенд версията не съвпада с Бекенд версията!",
|
||||
"Base URL": "Базов URL адрес",
|
||||
"goAlertInfo": "GoAlert е приложение с отворен код за планиране на повиквания, автоматизирани ескалации и известия (като SMS или гласови повиквания). Автоматично ангажирайте точния човек, по точния начин и в точното време! {0}",
|
||||
"goAlertIntegrationKeyInfo": "Вземете общ API интеграционен ключ за услугата във формат \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" обикновено стойността на параметъра token на копирания URL адрес.",
|
||||
"goAlert": "GoAlert",
|
||||
"backupOutdatedWarning": "Отпаднала: Тъй като са добавени много функции, тази опция за архивиране не е достатъчно поддържана и не може да генерира или възстанови пълен архив.",
|
||||
"backupRecommend": "Вместо това моля, архивирайте директно дяла или папката (./data/).",
|
||||
"Maintenance": "Поддръжка",
|
||||
"statusMaintenance": "Поддръжка",
|
||||
"Schedule maintenance": "Планиране на поддръжка",
|
||||
"Affected Monitors": "Засегнати монитори",
|
||||
"Pick Affected Monitors...": "Изберете засегнатите монитори…",
|
||||
"Start of maintenance": "Стартирай поддръжка",
|
||||
"All Status Pages": "Всички статус страници",
|
||||
"Select status pages...": "Изберете статус страници…",
|
||||
"recurringIntervalMessage": "Изпълнявай ежедневно | Изпълнявай всеки {0} дни",
|
||||
"affectedMonitorsDescription": "Изберете монитори, засегнати от текущата поддръжка",
|
||||
"affectedStatusPages": "Покажи това съобщение за поддръжка на избрани статус страници",
|
||||
"atLeastOneMonitor": "Изберете поне един засегнат монитор",
|
||||
"deleteMaintenanceMsg": "Сигурни ли сте, че желаете да изтриете тази поддръжка?",
|
||||
"Optional": "По желание",
|
||||
"squadcast": "Squadcast",
|
||||
"SendKey": "SendKey",
|
||||
"SMSManager API Docs": "SMSManager API Документация ",
|
||||
"Gateway Type": "Тип на шлюза",
|
||||
"SMSManager": "SMSManager",
|
||||
"You can divide numbers with": "Може да разделяте числата с",
|
||||
"or": "или",
|
||||
"recurringInterval": "Интервал",
|
||||
"Recurring": "Повтаряне",
|
||||
"strategyManual": "Активен/Неактивен ръчно",
|
||||
"warningTimezone": "Използва се часовата зона на сървъра",
|
||||
"weekdayShortMon": "Пон",
|
||||
"weekdayShortTue": "Вт",
|
||||
"weekdayShortWed": "Ср",
|
||||
"weekdayShortThu": "Чет",
|
||||
"weekdayShortFri": "Пет",
|
||||
"weekdayShortSat": "Съб",
|
||||
"weekdayShortSun": "Нед",
|
||||
"dayOfWeek": "Ден",
|
||||
"dayOfMonth": "Дата",
|
||||
"lastDay": "Последен ден",
|
||||
"lastDay1": "Последен ден от месеца",
|
||||
"lastDay2": "2-ри последен ден на месеца",
|
||||
"lastDay3": "3-ти последен ден на месеца",
|
||||
"lastDay4": "4-ти последен ден на месеца",
|
||||
"No Maintenance": "Няма поддръжка",
|
||||
"pauseMaintenanceMsg": "Сигурни ли сте, че желаете да направите пауза?",
|
||||
"maintenanceStatus-under-maintenance": "В режим поддръжка",
|
||||
"maintenanceStatus-inactive": "Неактивна",
|
||||
"maintenanceStatus-scheduled": "Планирана",
|
||||
"maintenanceStatus-ended": "Приключена",
|
||||
"maintenanceStatus-unknown": "Неизвестна",
|
||||
"Display Timezone": "Покажи часова зона",
|
||||
"Server Timezone": "Часова зона на сървъра",
|
||||
"statusPageMaintenanceEndDate": "Край",
|
||||
"enableGRPCTls": "Разреши изпращане на gRPC заявка с TLS връзка",
|
||||
"grpcMethodDescription": "Името на метода се форматира в \"cammelCase\", например sayHello, check, и т.н.",
|
||||
"smseagle": "SMSEagle",
|
||||
"smseagleTo": "Тел. номер(а)",
|
||||
"smseagleGroup": "Име на група/и от тел. указател",
|
||||
"smseagleContact": "Име(на) от тел. указател",
|
||||
"smseagleRecipientType": "Получател тип",
|
||||
"smseagleRecipient": "Получател(и) (при повече от един разделете със запетая)",
|
||||
"smseagleToken": "API токен за достъп",
|
||||
"smseagleUrl": "Вашият SMSEagle URL на устройството",
|
||||
"smseagleEncoding": "Изпрати като Unicode",
|
||||
"smseaglePriority": "Приоритет на съобщението (0-9, по подразбиране = 0)",
|
||||
"IconUrl": "Икона URL адрес",
|
||||
"webhookAdditionalHeadersTitle": "Допълнителни хедъри",
|
||||
"webhookAdditionalHeadersDesc": "Задава допълнителни хедъри, изпратени с уеб куката.",
|
||||
"Enable DNS Cache": "Активирай DNS кеширане",
|
||||
"Enable": "Активирай",
|
||||
"Disable": "Деактивирай",
|
||||
"dnsCacheDescription": "Възможно е да не работи в IPv6 среда - деактивирайте, ако срещнете проблеми.",
|
||||
"Single Maintenance Window": "Единичен времеви интервал за поддръжка",
|
||||
"Maintenance Time Window of a Day": "Времеви интервал от деня за поддръжка",
|
||||
"Effective Date Range": "Интервал от дни на влизане в сила",
|
||||
"Schedule Maintenance": "Планирай поддръжка",
|
||||
"Date and Time": "Дата и час",
|
||||
"DateTime Range": "Изтрий времеви интервал",
|
||||
"Strategy": "Стратегия",
|
||||
"Free Mobile User Identifier": "Free Mobile потребителски идентификатор",
|
||||
"Free Mobile API Key": "Free Mobile API ключ",
|
||||
"Enable TLS": "Активирай TLS",
|
||||
"Proto Service Name": "Proto име на услугата",
|
||||
"Proto Method": "Proto метод",
|
||||
"Proto Content": "Proto съдържание",
|
||||
"Economy": "Икономичен",
|
||||
"Lowcost": "Евтин",
|
||||
"high": "висок",
|
||||
"General Monitor Type": "Общ тип монитор",
|
||||
"Passive Monitor Type": "Пасивет тип монитор",
|
||||
"Specific Monitor Type": "Специфичен тип монитор",
|
||||
"ZohoCliq": "ZohoCliq",
|
||||
"wayToGetZohoCliqURL": "Можете да научите как се създава URL адрес за уеб кука {0}.",
|
||||
"Kook": "Kook",
|
||||
"wayToGetKookBotToken": "Създайте приложение и вземете вашия бот токен на {0}",
|
||||
"wayToGetKookGuildID": "Превключете в 'Developer Mode' в 'Kook' настройките, след което десен клик върху 'guild' за да вземете неговото 'ID'",
|
||||
"Guild ID": "Guild ID",
|
||||
"Help": "Помощ",
|
||||
"Game": "игрови",
|
||||
"Custom": "Потребителски",
|
||||
"infiniteRetention": "Задайте стойност 0 за безкрайно съхранение.",
|
||||
"Monitor": "Монитор | Монитори",
|
||||
"dataRetentionTimeError": "Периодът на съхранение трябва да е 0 или по-голям",
|
||||
"confirmDeleteTagMsg": "Сигурни ли сте, че желаете да изтриете този таг? Мониторите, свързани с него, няма да бъдат изтрити.",
|
||||
"promosmsAllowLongSMS": "Позволи дълъг SMS",
|
||||
"Packet Size": "Размер на пакет",
|
||||
"Custom Monitor Type": "Потребителски тип монитор",
|
||||
"loadingError": "Данните не могат да бъдат изтеглени. Моля, опитайте отново по-късно.",
|
||||
"plugin": "Плъгин | Плъгини",
|
||||
"install": "Инсталирай",
|
||||
"installing": "Инсталиране",
|
||||
"uninstall": "Деинсталирай",
|
||||
"uninstalling": "Деинсталиране",
|
||||
"confirmUninstallPlugin": "Сигурни ли сте, че желаете да деинсталирате този плъгин?"
|
||||
}
|
695
src/lang/cs-CZ.json
Normal file
695
src/lang/cs-CZ.json
Normal file
@@ -0,0 +1,695 @@
|
||||
{
|
||||
"languageName": "Czech",
|
||||
"checkEverySecond": "Kontrolovat každých {0} sekund",
|
||||
"retryCheckEverySecond": "Opakovat každých {0} sekund",
|
||||
"resendEveryXTimes": "Znovu zaslat {0}krát",
|
||||
"resendDisabled": "Opakované zasílání je vypnuté",
|
||||
"retriesDescription": "Maximální počet pokusů před označením služby jako nedostupné a odesláním oznámení",
|
||||
"ignoreTLSError": "Ignorovat TLS/SSL chyby na HTTPS stránkách",
|
||||
"upsideDownModeDescription": "Pomocí této možnosti změníte způsob vyhodnocování stavu. Pokud je služba dosažitelná, je NEDOSTUPNÁ.",
|
||||
"maxRedirectDescription": "Maximální počet přesměrování, která se mají následovat. Nastavením hodnoty 0 zakážete přesměrování.",
|
||||
"enableGRPCTls": "Umožnit odeslání gRPC žádosti během TLS spojení",
|
||||
"grpcMethodDescription": "Název metody se převede do cammelCase formátu jako je sayHello, check, aj.",
|
||||
"acceptedStatusCodesDescription": "Vyberte stavové kódy, které jsou považovány za úspěšnou odpověď.",
|
||||
"Maintenance": "Údržba",
|
||||
"statusMaintenance": "Údržba",
|
||||
"Schedule maintenance": "Naplánovat údržbu",
|
||||
"Affected Monitors": "Dotčené dohledy",
|
||||
"Pick Affected Monitors...": "Vyberte dotčené dohledy…",
|
||||
"Start of maintenance": "Zahájit údržbu",
|
||||
"All Status Pages": "Všechny stavové stránky",
|
||||
"Select status pages...": "Vyberte stavovou stránku…",
|
||||
"recurringIntervalMessage": "Spustit jednou každý den | Spustit jednou každých {0} dní",
|
||||
"affectedMonitorsDescription": "Vyberte dohledy, které budou ovlivněny touto údržbou",
|
||||
"affectedStatusPages": "Zobrazit tuto zprávu o údržbě na vybraných stavových stránkách",
|
||||
"atLeastOneMonitor": "Vyberte alespoň jeden dotčený dohled",
|
||||
"passwordNotMatchMsg": "Hesla se neshodují.",
|
||||
"notificationDescription": "Pro zajištění funkčnosti oznámení je nutné jej přiřadit dohledu.",
|
||||
"keywordDescription": "Vyhledat klíčové slovo v prosté odpovědi HTML nebo JSON. Při hledání se rozlišuje velikost písmen.",
|
||||
"pauseDashboardHome": "Pozastaveno",
|
||||
"deleteMonitorMsg": "Opravdu chcete odstranit tento dohled?",
|
||||
"deleteMaintenanceMsg": "Opravdu chcete odstranit tuto údržbu?",
|
||||
"deleteNotificationMsg": "Opravdu chcete odstranit toto oznámení pro všechny dohledy?",
|
||||
"dnsPortDescription": "Port DNS serveru. Standardně běží na portu 53. V případě potřeby jej můžete kdykoli změnit.",
|
||||
"resolverserverDescription": "Cloudflare je výchozí server. V případě potřeby můžete Resolver server kdykoli změnit.",
|
||||
"rrtypeDescription": "Vyberte typ záznamu o prostředku, který chcete monitorovat",
|
||||
"pauseMonitorMsg": "Opravdu chcete dohled pozastavit?",
|
||||
"enableDefaultNotificationDescription": "Toto oznámení bude standardně aktivní pro nové dohledy. V případě potřeby můžete oznámení stále zakázat na úrovni jednotlivých dohledů.",
|
||||
"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ý přehled",
|
||||
"Up": "Běží",
|
||||
"Down": "Nedostupný",
|
||||
"Pending": "Čekám",
|
||||
"Unknown": "Neznámý",
|
||||
"Pause": "Pauza",
|
||||
"Name": "Název",
|
||||
"Status": "Stav",
|
||||
"DateTime": "Časové razítko",
|
||||
"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",
|
||||
"Monitor": "Dohled | Dohledy",
|
||||
"day": "den | dny/í",
|
||||
"-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í heartbeatu",
|
||||
"Resend Notification if Down X times consequently": "Znovu zaslat oznámení, pokud je služba nedostupná Xkrát za sebou",
|
||||
"Advanced": "Rozšířené",
|
||||
"Upside Down Mode": "Inverzní režim",
|
||||
"Max. Redirects": "Max. přesměrování",
|
||||
"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í",
|
||||
"disableauth.message1": "Opravdu chcete <strong>deaktivovat autentifikaci</strong>?",
|
||||
"disableauth.message2": "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.",
|
||||
"Please use this option carefully!": "Používejte ji prosím s rozmyslem!",
|
||||
"Logout": "Odhlásit",
|
||||
"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": "Server Resolveru",
|
||||
"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": "Doba odezvy (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á",
|
||||
"Custom": "Vlastní",
|
||||
"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",
|
||||
"ZohoCliq": "ZohoCliq",
|
||||
"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": "SEM ZADEJTE TOKEN VAŠEHO CHATBOTA",
|
||||
"chatIDNotFound": "ID chatu nebylo nalezeno; nejprve tomuto robotovi zašlete zprávu",
|
||||
"webhook": "Webhook",
|
||||
"Post URL": "URL adresa příspěvku",
|
||||
"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}",
|
||||
"webhookAdditionalHeadersTitle": "Dodatečné hlavičky",
|
||||
"webhookAdditionalHeadersDesc": "Nastavte dodatečné hlavičky, které se odešlou společně s webhookem.",
|
||||
"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": "URL Webhooku Discord",
|
||||
"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 na {0}.",
|
||||
"wayToGetZohoCliqURL": "Informace o tom, jak vytvořit URL adresu webhooku naleznete na {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",
|
||||
"PushByTechulus": "Push od Techulus",
|
||||
"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",
|
||||
"Kook": "Kook",
|
||||
"wayToGetKookBotToken": "Aplikaci vytvoříte a token bota získáte na {0}",
|
||||
"wayToGetKookGuildID": "V nastavení Kook aktivujte 'Vývojářský režim' a kliknutím pravým tlačítkem na guild získejte jeho ID",
|
||||
"Guild ID": "Guild ID",
|
||||
"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",
|
||||
"promosmsAllowLongSMS": "Povolit dlouhé SMS",
|
||||
"Feishu WebHookUrl": "URL Webhooku Feishu",
|
||||
"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": "Hlaviča žádosti není platný JSON: ",
|
||||
"BodyInvalidFormat": "Text žádosti není platný JSON: ",
|
||||
"Monitor History": "Historie dohledu",
|
||||
"clearDataOlderThan": "Historie dohledu bude uchovávána po dobu {0} dní.",
|
||||
"PasswordsDoNotMatch": "Hesla se neshodují.",
|
||||
"records": "záznamů",
|
||||
"One record": "Jeden záznam",
|
||||
"steamApiKeyDescription": "Pro monitorování Steam Game Serveru je nutné zadat Steam Web-API klíč. Svůj API klíč získáte na následující stránce: ",
|
||||
"Current User": "Aktuálně přihlášený uživatel",
|
||||
"topic": "Téma",
|
||||
"topicExplanation": "MQTT téma, které chcete sledovat",
|
||||
"successMessage": "Zpráva o úspěchu",
|
||||
"successMessageExplanation": "MQTT zpráva považovaná za úspěšnou",
|
||||
"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 RR záznamu…",
|
||||
"Pick Accepted Status Codes...": "Vyberte stavové kódy, které chcete akceptovat…",
|
||||
"Default": "Výchozí",
|
||||
"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",
|
||||
"error": "chyba",
|
||||
"critical": "kritické",
|
||||
"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řepnout 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)",
|
||||
"smseagle": "SMSEagle",
|
||||
"smseagleTo": "Telefonní číslo(a)",
|
||||
"smseagleGroup": "Název skupiny v adresáři",
|
||||
"smseagleContact": "Název kontaktu v adresáři",
|
||||
"smseagleRecipientType": "Typ příjemce",
|
||||
"smseagleRecipient": "Příjemce(i) (více záznamů oddělte čárkou)",
|
||||
"smseagleToken": "API přístupový token",
|
||||
"smseagleUrl": "URL vašeho SMSEagle zařízení",
|
||||
"smseagleEncoding": "Odeslat v Unicode",
|
||||
"smseaglePriority": "Priorita zprávy (0-9, výchozí = 0)",
|
||||
"stackfield": "Stackfield",
|
||||
"Customize": "Přizpůsobit",
|
||||
"Custom Footer": "Vlastní patička",
|
||||
"Custom CSS": "Vlastní CSS",
|
||||
"smtpDkimSettings": "Nastavení DKIM",
|
||||
"smtpDkimDesc": "Informace o použití naleznete v {0} Nodemailer DKIM.",
|
||||
"documentation": "dokumentaci",
|
||||
"smtpDkimDomain": "Název domény",
|
||||
"smtpDkimKeySelector": "Selektor klíče",
|
||||
"smtpDkimPrivateKey": "Privátní klíč",
|
||||
"smtpDkimHashAlgo": "Hashovací algoritmus (volitelné)",
|
||||
"smtpDkimheaderFieldNames": "Podepisovat tyto hlavičky (volitelné)",
|
||||
"smtpDkimskipFields": "Nepodepisovat tyto hlavičky (volitelné)",
|
||||
"wayToGetPagerDutyKey": "Získat jej můžete v sekci Service -> Service Directory -> (vyberte službu) -> Integrations -> Add integration. Následně vyhledejte \"Events API V2\". Více informace naleznete na adrese {0}",
|
||||
"Integration Key": "Integrační klíč",
|
||||
"Integration URL": "Integrační URL",
|
||||
"Auto resolve or acknowledged": "Automatické řešení nebo potvrzení",
|
||||
"do nothing": "nedělat nic",
|
||||
"auto acknowledged": "automaticky uznáno",
|
||||
"auto resolve": "automatické řešení",
|
||||
"gorush": "Gorush",
|
||||
"alerta": "Alerta",
|
||||
"alertaApiEndpoint": "API Endpoint",
|
||||
"alertaEnvironment": "Prostředí",
|
||||
"alertaApiKey": "API klíč",
|
||||
"alertaAlertState": "Stav upozornění",
|
||||
"alertaRecoverState": "Stav obnovení",
|
||||
"deleteStatusPageMsg": "Opravdu chcete odstranit tuto stavovou stránku?",
|
||||
"Proxies": "Proxy",
|
||||
"default": "Výchozí",
|
||||
"enabled": "Zapnuto",
|
||||
"setAsDefault": "Nastavit jako výchozí",
|
||||
"deleteProxyMsg": "Opravdu chcete odstranit tuto proxy ze všech dohledů?",
|
||||
"proxyDescription": "Pro zajištění funkčnosti musí být proxy přiřazena dohledům.",
|
||||
"enableProxyDescription": "Tato proxy neovlivní žádosti dohledu do doby, než ji aktivujete. Změnou tohoto nastavení dočasně zakážete použití proxy ve všech dohledech.",
|
||||
"setAsDefaultProxyDescription": "Tato proxy se použije pro všechny nové dohledy. V případě potřeby můžete její využívání zakázat v konkrétním dohledu.",
|
||||
"Certificate Chain": "Řetězec certifikátu",
|
||||
"Valid": "Platný",
|
||||
"Invalid": "Neplatný",
|
||||
"AccessKeyId": "ID přístupového klíče",
|
||||
"SecretAccessKey": "Tajemství přístupového klíče",
|
||||
"PhoneNumbers": "Telefonní čísla",
|
||||
"TemplateCode": "TemplateCode",
|
||||
"SignName": "SignName",
|
||||
"Sms template must contain parameters: ": "Šablona SMS musí obsahovat parametry: ",
|
||||
"Bark Endpoint": "Bark Endpoint",
|
||||
"Bark Group": "Skupina Bark",
|
||||
"Bark Sound": "Bark zvuk",
|
||||
"WebHookUrl": "WebHookUrl",
|
||||
"SecretKey": "Tajný klíč",
|
||||
"For safety, must use secret key": "Z důvodu bezpečnosti použijte secret key",
|
||||
"Device Token": "Token zařízení",
|
||||
"Platform": "Platforma",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Vysoký",
|
||||
"Retry": "Opakovat",
|
||||
"Topic": "Téma",
|
||||
"WeCom Bot Key": "Klíč WeCom Bota",
|
||||
"Setup Proxy": "Nastavit proxy",
|
||||
"Proxy Protocol": "Protokol proxy",
|
||||
"Proxy Server": "Proxy Server",
|
||||
"Proxy server has authentication": "Proxy server vyžaduje ověření",
|
||||
"User": "Uživatel",
|
||||
"Installed": "Nainstalováno",
|
||||
"Not installed": "Nenainstalováno",
|
||||
"Running": "Běží",
|
||||
"Not running": "Neběží",
|
||||
"Remove Token": "Odstranit token",
|
||||
"Start": "Spustit",
|
||||
"Stop": "Zastavit",
|
||||
"Uptime Kuma": "Uptime Kuma",
|
||||
"Add New Status Page": "Přidat novou stavovou stránku",
|
||||
"Slug": "Slug",
|
||||
"Accept characters:": "Přípustné znaky:",
|
||||
"startOrEndWithOnly": "Počáteční a koncový znak může být pouze {0}",
|
||||
"No consecutive dashes": "Nesmí se opakovat pomlčky",
|
||||
"Next": "Další",
|
||||
"The slug is already taken. Please choose another slug.": "Slug s tímto názvem již existuje. Prosím, zadejte jiný název.",
|
||||
"No Proxy": "Žádná proxy",
|
||||
"Authentication": "Ověření",
|
||||
"HTTP Basic Auth": "HTTP Basic ověření",
|
||||
"New Status Page": "Nová stavová stránka",
|
||||
"Page Not Found": "Stránka nenalezena",
|
||||
"Reverse Proxy": "Reverzní proxy",
|
||||
"Backup": "Záloha",
|
||||
"About": "O programu",
|
||||
"wayToGetCloudflaredURL": "(Stáhnout cloudflared z {0})",
|
||||
"cloudflareWebsite": "Webová stránka Cloudflare",
|
||||
"Message:": "Zpráva:",
|
||||
"Don't know how to get the token? Please read the guide:": "Nevíte jak získat? Prosím, přečtěte si tuto příručku:",
|
||||
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Stávající připojení mohlo být ztraceno, pokud jste připojeni prostřednictvím Cloudflare tunelu. Opravdu jej chcete zastavit? Pro potvrzení zadejte své současné heslo.",
|
||||
"HTTP Headers": "HTTP hlavičky",
|
||||
"Trust Proxy": "Důvěryhodná proxy",
|
||||
"Other Software": "Jiný software",
|
||||
"For example: nginx, Apache and Traefik.": "Například nginx, Apache nebo Traefik.",
|
||||
"Please read": "Prosím, přečtěte si informace na adrese",
|
||||
"Subject:": "Předmět:",
|
||||
"Valid To:": "Platnost do:",
|
||||
"Days Remaining:": "Počet zbývajících dní:",
|
||||
"Issuer:": "Vydavatel:",
|
||||
"Fingerprint:": "Otisk:",
|
||||
"No status pages": "Žádná stavová stránka",
|
||||
"Domain Name Expiry Notification": "Oznámení na blížící se konec platnosti doménového jména",
|
||||
"Proxy": "Proxy",
|
||||
"Date Created": "Datum vytvoření",
|
||||
"HomeAssistant": "Home Assistant",
|
||||
"onebotHttpAddress": "OneBot HTTP adresa",
|
||||
"onebotMessageType": "Typ OneBot zprávy",
|
||||
"onebotGroupMessage": "Skupinová",
|
||||
"onebotPrivateMessage": "Soukromá",
|
||||
"onebotUserOrGroupId": "ID skupiny/uživatele",
|
||||
"onebotSafetyTips": "Z důvodu bezpečnosti je nutné zadat přístupový token",
|
||||
"PushDeer Key": "PushDeer klíč",
|
||||
"Footer Text": "Text v patičce",
|
||||
"Show Powered By": "Zobrazit \"Poskytuje\"",
|
||||
"Domain Names": "Názvy domén",
|
||||
"signedInDisp": "Přihlášen jako {0}",
|
||||
"signedInDispDisabled": "Ověření je vypnuté.",
|
||||
"RadiusSecret": "Tajemství Radius",
|
||||
"RadiusSecretDescription": "Sdílený tajný klíč mezi klientem a serverem",
|
||||
"RadiusCalledStationId": "ID volaného zařízení",
|
||||
"RadiusCalledStationIdDescription": "Identifikátor volaného zařízení",
|
||||
"RadiusCallingStationId": "ID volajícího zařízení",
|
||||
"RadiusCallingStationIdDescription": "Identifikátor volajícího zařízení",
|
||||
"Certificate Expiry Notification": "Oznámení na blížící se konec platnosti certifikátu",
|
||||
"API Username": "Uživatelské jména API",
|
||||
"API Key": "API klíč",
|
||||
"Recipient Number": "Číslo příjemce",
|
||||
"From Name/Number": "Jméno/číslo odesílatele",
|
||||
"Leave blank to use a shared sender number.": "Ponechte prázdné, pokud chcete použít číslo sdíleného příjemce.",
|
||||
"Octopush API Version": "Octopush API verze",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"endpoint": "endpoint",
|
||||
"octopushAPIKey": "\"API key\" ze sekce HTTP API credentials na nástěnce",
|
||||
"octopushLogin": "\"Login\" ze sekce HTTP API credentials na nástěnce",
|
||||
"promosmsLogin": "API Login Name",
|
||||
"promosmsPassword": "API Password",
|
||||
"pushoversounds pushover": "Pushover (výchozí)",
|
||||
"pushoversounds bike": "Kolo",
|
||||
"pushoversounds bugle": "Bugle",
|
||||
"pushoversounds cashregister": "Pokladna",
|
||||
"pushoversounds classical": "Classical",
|
||||
"pushoversounds cosmic": "Kosmický",
|
||||
"pushoversounds falling": "Falling",
|
||||
"pushoversounds gamelan": "Gamelan",
|
||||
"pushoversounds incoming": "Příchozí",
|
||||
"pushoversounds intermission": "Přestávka",
|
||||
"pushoversounds magic": "Kouzlo",
|
||||
"pushoversounds mechanical": "Mechanika",
|
||||
"pushoversounds pianobar": "Barové piano",
|
||||
"pushoversounds siren": "Siréna",
|
||||
"pushoversounds spacealarm": "Space Alarm",
|
||||
"pushoversounds tugboat": "Tug Boat",
|
||||
"pushoversounds alien": "Alien Alarm (dlouhý)",
|
||||
"pushoversounds climb": "Climb (dlouhý)",
|
||||
"pushoversounds persistent": "Persistent (dlouhý)",
|
||||
"pushoversounds echo": "Pushover Echo (dlouhý)",
|
||||
"pushoversounds updown": "Up Down (dlouhý)",
|
||||
"pushoversounds vibrate": "Pouze vibrace",
|
||||
"pushoversounds none": "Žádný (ticho)",
|
||||
"pushyAPIKey": "Tajný API klíč",
|
||||
"pushyToken": "Token zařízení",
|
||||
"Show update if available": "Upozornit na aktualizace, pokud jsou k dispozici",
|
||||
"Also check beta release": "Kontrolovat také dostupnost beta verzí",
|
||||
"Using a Reverse Proxy?": "Používáte reverzní proxy?",
|
||||
"Check how to config it for WebSocket": "Zjistěte, jak ji nakonfigurovat pro WebSockety",
|
||||
"Steam Game Server": "Steam Game Server",
|
||||
"Most likely causes:": "Nejčastější důvody:",
|
||||
"The resource is no longer available.": "Zdroj již není k dispozici.",
|
||||
"There might be a typing error in the address.": "Při zadávání adresy jste udělali chybu.",
|
||||
"What you can try:": "Co můžete vyzkoušet:",
|
||||
"Retype the address.": "Znovu zadat adresu.",
|
||||
"Go back to the previous page.": "Vrátit se na předchozí stránku.",
|
||||
"Coming Soon": "Připravujeme",
|
||||
"wayToGetClickSendSMSToken": "API Username a API Key získáte na adrese {0} .",
|
||||
"Connection String": "Připojovací řetězec",
|
||||
"Query": "Dotaz",
|
||||
"settingsCertificateExpiry": "Platnost TLS certifikátu",
|
||||
"certificationExpiryDescription": "Aktivovat oznámení nad HTTPS dohledy, pokud platnost TLS certifikátu vyprší za:",
|
||||
"Setup Docker Host": "Nastavit Docker hostitele",
|
||||
"Connection Type": "Typ připojení",
|
||||
"Docker Daemon": "Démon Dockeru",
|
||||
"deleteDockerHostMsg": "Opravdu chcete odstranit tohoto docker hostitele ze všech dohledů?",
|
||||
"socket": "Socket",
|
||||
"tcp": "TCP / HTTP",
|
||||
"Docker Container": "Docker kontejner",
|
||||
"Container Name / ID": "ID / název kontejneru",
|
||||
"Docker Host": "Docker hostitel",
|
||||
"Docker Hosts": "Docker hostitelé",
|
||||
"ntfy Topic": "ntfy Téma",
|
||||
"Domain": "Doména",
|
||||
"Workstation": "Pracovní stanice",
|
||||
"disableCloudflaredNoAuthMsg": "Používáte režim bez ověření, heslo není vyžadováno.",
|
||||
"trustProxyDescription": "Důvěřovat 'X-Forwarded-*' hlavičkám. Pokud chcete získat správnou IP adresu klientů a vaše instance Uptime Kuma je za Nginx nebo Apache, měli byste tuto možnost zapnout.",
|
||||
"wayToGetLineNotifyToken": "Přístupový token můžete získat na adrese {0}",
|
||||
"Examples": "Příklady",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "Dlouhodobý přístupový token",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Pro vytvoření dlouhodobého přístupový tokenu klikněte na název svého profilu (v levém dolním rohu) a následně v dolní části stránky klikněte na tlačítko Create Token. ",
|
||||
"Notification Service": "Oznamovací služba",
|
||||
"default: notify all devices": "výchozí: upozornit všechny zařízení",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Seznam dostupných oznamovacích služeb naleznete v Home Assistant v sekci \"Developer Tools > Services\", kde vyhledejte \"notification\" pro zjištění názvu zařízení.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Automatizaci můžete volitelně aktivovat prostřednictvím Home Assistant:",
|
||||
"Trigger type:": "Typ podmínky spuštění:",
|
||||
"Event type:": "Typ události:",
|
||||
"Event data:": "Data události:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Následně vyberte akci, například přepnutí scény z RGB světla na červenou.",
|
||||
"Frontend Version": "Verze frontendu",
|
||||
"Frontend Version do not match backend version!": "Verze frontendu neodpovídá verzi backendu!",
|
||||
"Base URL": "Primární URL adresa",
|
||||
"goAlertInfo": "GoAlert je aplikace s otevřeným zdrojovým kódem pro plánování hovorů, automatické eskalace a upozornění (jako jsou SMS nebo hlasové hovory). Automaticky zapojte správnou osobu, správným způsobem a ve správný čas! {0}",
|
||||
"goAlertIntegrationKeyInfo": "Obecný API integrační klíč pro danou službu ve formátu \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" se obvykle nachází ve zkopírované URL jako hodnota parametru token.",
|
||||
"goAlert": "GoAlert",
|
||||
"backupOutdatedWarning": "Zastaralé: Vzhledem k tomu, že bylo přidáno mnoho funkcí a tato funkce zálohování je poněkud neudržovaná, nemůže vytvářet nebo obnovit kompletní zálohu.",
|
||||
"backupRecommend": "Prosím, zálohujte si ručně celý svazek nebo datovou složku (./data/).",
|
||||
"Optional": "Volitelný",
|
||||
"squadcast": "Squadcast",
|
||||
"SendKey": "SendKey",
|
||||
"SMSManager API Docs": "Dokumentace SMSManager API ",
|
||||
"Gateway Type": "Typ brány",
|
||||
"SMSManager": "SMSManager",
|
||||
"You can divide numbers with": "Čísla můžete oddělit pomocí",
|
||||
"or": "nebo",
|
||||
"recurringInterval": "Interval",
|
||||
"Recurring": "Opakující se",
|
||||
"strategyManual": "Ruční spuštění/vypnutí",
|
||||
"warningTimezone": "Používá se časové pásmo serveru",
|
||||
"weekdayShortMon": "Po",
|
||||
"weekdayShortTue": "Út",
|
||||
"weekdayShortWed": "St",
|
||||
"weekdayShortThu": "Čt",
|
||||
"weekdayShortFri": "Pá",
|
||||
"weekdayShortSat": "So",
|
||||
"weekdayShortSun": "Ne",
|
||||
"dayOfWeek": "Den v týdnu",
|
||||
"dayOfMonth": "Den v měsíci",
|
||||
"lastDay": "Poslední den",
|
||||
"lastDay1": "1. poslední den v měsíci",
|
||||
"lastDay2": "2. poslední den v měsíci",
|
||||
"lastDay3": "3. poslední den v měsíci",
|
||||
"lastDay4": "4. poslední den v měsíci",
|
||||
"No Maintenance": "Žádná údržba",
|
||||
"pauseMaintenanceMsg": "Opravdu chcete údržbu pozastavit?",
|
||||
"maintenanceStatus-under-maintenance": "Údržba",
|
||||
"maintenanceStatus-inactive": "Neaktivní",
|
||||
"maintenanceStatus-scheduled": "Naplánováno",
|
||||
"maintenanceStatus-ended": "Ukončeno",
|
||||
"maintenanceStatus-unknown": "Neznámý",
|
||||
"Display Timezone": "Zobrazit časové pásmo",
|
||||
"Server Timezone": "Časové pásmo serveru",
|
||||
"statusPageMaintenanceEndDate": "Konec",
|
||||
"IconUrl": "Adresa URL ikony",
|
||||
"Enable DNS Cache": "Povolit DNS Cache",
|
||||
"Enable": "Povolit",
|
||||
"Disable": "Zakázat",
|
||||
"dnsCacheDescription": "V některých IPv6 prostředích nemusí fungovat. Pokud narazíte na nějaké problémy, vypněte jej.",
|
||||
"Single Maintenance Window": "Konkrétní časové okno pro údržbu",
|
||||
"Maintenance Time Window of a Day": "Časové okno pro údržbu v daný den",
|
||||
"Effective Date Range": "Časové období",
|
||||
"Schedule Maintenance": "Naplánovat údržbu",
|
||||
"Date and Time": "Datum a čas",
|
||||
"DateTime Range": "Rozsah data a času",
|
||||
"Strategy": "Strategie",
|
||||
"Free Mobile User Identifier": "Identifikátor uživatele Free Mobile",
|
||||
"Free Mobile API Key": "API klíč Free Mobile",
|
||||
"Enable TLS": "Povolit TLS",
|
||||
"Proto Service Name": "Proto Service Name",
|
||||
"Proto Method": "Proto metoda",
|
||||
"Proto Content": "Proto obsah",
|
||||
"Economy": "Úsporná",
|
||||
"Lowcost": "Nízkonákladová",
|
||||
"high": "high",
|
||||
"General Monitor Type": "Obecný typ dohledu",
|
||||
"Passive Monitor Type": "Pasivní typ dohledu",
|
||||
"Specific Monitor Type": "Konkrétní typ dohledu",
|
||||
"dataRetentionTimeError": "Doba pro uchování musí být větší nebo rovna 0",
|
||||
"infiniteRetention": "Pro nekonečný záznam zadejte 0.",
|
||||
"confirmDeleteTagMsg": "Opravdu chcete odstranit tento štítek? Provedením této akce nedojde k odstranění dohledů, které jej mají přiřazeny.",
|
||||
"Help": "Nápověda",
|
||||
"Game": "Hra",
|
||||
"Custom Monitor Type": "Vlastní typ dohledu",
|
||||
"loadingError": "Nelze načíst data, zkuste to prosím později.",
|
||||
"confirmUninstallPlugin": "Opravdu chcete tento zásuvný modul odinstalovat?",
|
||||
"plugin": "Zásuvné moduly | Zásuvné moduly",
|
||||
"install": "Instalace",
|
||||
"installing": "Instaluji",
|
||||
"uninstall": "Odinstalace",
|
||||
"uninstalling": "Odinstalování",
|
||||
"Packet Size": "Velikost paketu"
|
||||
}
|
354
src/lang/da-DK.json
Normal file
354
src/lang/da-DK.json
Normal file
@@ -0,0 +1,354 @@
|
||||
{
|
||||
"languageName": "Danish (Danmark)",
|
||||
"Settings": "Indstillinger",
|
||||
"Dashboard": "Betjeningspanel",
|
||||
"New Update": "Opdatering tilgængelig",
|
||||
"Language": "Sprog",
|
||||
"Appearance": "Udseende",
|
||||
"Theme": "Tema",
|
||||
"General": "Generelt",
|
||||
"Version": "Version",
|
||||
"Check Update On GitHub": "Tjek efter opdateringer på Github",
|
||||
"List": "Liste",
|
||||
"Add": "Tilføj",
|
||||
"Add New Monitor": "Tilføj ny Overvåger",
|
||||
"Quick Stats": "Oversigt",
|
||||
"Up": "Aktiv",
|
||||
"Down": "Inaktiv",
|
||||
"Pending": "Afventer",
|
||||
"Unknown": "Ukendt",
|
||||
"Pause": "Stands",
|
||||
"pauseDashboardHome": "Standset",
|
||||
"Name": "Navn",
|
||||
"Status": "Status",
|
||||
"DateTime": "Dato / Tid",
|
||||
"Message": "Beskeder",
|
||||
"No important events": "Inden vigtige begivenheder",
|
||||
"Resume": "Fortsæt",
|
||||
"Edit": "Rediger",
|
||||
"Delete": "Slet",
|
||||
"Current": "Aktuelt",
|
||||
"Uptime": "Oppetid",
|
||||
"Cert Exp.": "Certifikatets udløb",
|
||||
"day": "Dag | Dage",
|
||||
"-day": "-Dage",
|
||||
"hour": "Timer",
|
||||
"-hour": "-Timer",
|
||||
"checkEverySecond": "Tjek hvert {0} sekund",
|
||||
"Response": "Respons",
|
||||
"Ping": "Ping",
|
||||
"Monitor Type": "Overvåger Type",
|
||||
"Keyword": "Nøgleord",
|
||||
"Friendly Name": "Visningsnavn",
|
||||
"URL": "URL",
|
||||
"Hostname": "Hostname",
|
||||
"Port": "Port",
|
||||
"Heartbeat Interval": "Taktinterval",
|
||||
"Retries": "Gentagelser",
|
||||
"retriesDescription": "Maksimalt antal gentagelser, før tjenesten markeres som inaktiv og sender en meddelelse.",
|
||||
"Advanced": "Avanceret",
|
||||
"ignoreTLSError": "Ignorere TLS/SSL web fejl",
|
||||
"Upside Down Mode": "Omvendt tilstand",
|
||||
"upsideDownModeDescription": "Håndter tilstanden omvendt. Hvis tjenesten er tilgængelig, vises den som inaktiv.",
|
||||
"Max. Redirects": "Maks. Omdirigeringer",
|
||||
"maxRedirectDescription": "Maksimalt antal omdirigeringer, der skal følges. Indstil til 0 for at deaktivere omdirigeringer.",
|
||||
"Accepted Status Codes": "Tilladte HTTP-Statuskoder",
|
||||
"acceptedStatusCodesDescription": "Vælg de statuskoder, der stadig skal vurderes som vellykkede.",
|
||||
"Save": "Gem",
|
||||
"Notifications": "Underretninger",
|
||||
"Not available, please setup.": "Ikke tilgængelige, opsæt venligst.",
|
||||
"Setup Notification": "Opsæt underretninger",
|
||||
"Light": "Lys",
|
||||
"Dark": "Mørk",
|
||||
"Auto": "Auto",
|
||||
"Theme - Heartbeat Bar": "Tema - Tidslinje",
|
||||
"Normal": "Normal",
|
||||
"Bottom": "Bunden",
|
||||
"None": "Ingen",
|
||||
"Timezone": "Tidszone",
|
||||
"Search Engine Visibility": "Søgemaskine synlighed",
|
||||
"Allow indexing": "Tillad indeksering",
|
||||
"Discourage search engines from indexing site": "Frabed søgemaskiner at indeksere webstedet",
|
||||
"Change Password": "Ændre adgangskode",
|
||||
"Current Password": "Nuværende adgangskode",
|
||||
"New Password": "Ny adgangskode",
|
||||
"Repeat New Password": "Gentag den nye adgangskode",
|
||||
"passwordNotMatchMsg": "Adgangskoderne er ikke ens.",
|
||||
"Update Password": "Opdater adgangskode",
|
||||
"Disable Auth": "Deaktiver autentificering",
|
||||
"Enable Auth": "Aktiver autentificering",
|
||||
"Logout": "Log ud",
|
||||
"notificationDescription": "Tildel underretninger til Overvåger(e), så denne funktion træder i kraft.",
|
||||
"Leave": "Verlassen",
|
||||
"I understand, please disable": "Jeg er indforstået, deaktiver venligst",
|
||||
"Confirm": "Bekræft",
|
||||
"Yes": "Ja",
|
||||
"No": "Nej",
|
||||
"Username": "Brugernavn",
|
||||
"Password": "Adgangskode",
|
||||
"Remember me": "Husk mig",
|
||||
"Login": "Log ind",
|
||||
"No Monitors, please": "Ingen Overvågere",
|
||||
"add one": "tilføj en",
|
||||
"Notification Type": "Underretningstype",
|
||||
"Email": "E-Mail",
|
||||
"Test": "Test",
|
||||
"Certificate Info": "Certifikatoplysninger",
|
||||
"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?",
|
||||
"deleteNotificationMsg": "Er du sikker på, at du vil slette denne underretning for alle overvågere?",
|
||||
"resolverserverDescription": "Cloudflare er standardserveren, den kan til enhver tid ændres.",
|
||||
"Resolver Server": "Navne-server",
|
||||
"rrtypeDescription": "Vælg den type RR, du vil overvåge.",
|
||||
"Last Result": "Seneste resultat",
|
||||
"pauseMonitorMsg": "Er du sikker på, at du vil standse Overvågeren?",
|
||||
"Create your admin account": "Opret din administratorkonto",
|
||||
"Repeat Password": "Gentag adgangskoden",
|
||||
"Resource Record Type": "Resource Record Type",
|
||||
"respTime": "Resp. Tid (ms)",
|
||||
"notAvailableShort": "N/A",
|
||||
"Create": "Opret",
|
||||
"clearEventsMsg": "Er du sikker på vil slette alle events for denne Overvåger?",
|
||||
"clearHeartbeatsMsg": "Er du sikker på vil slette alle hjerteslag for denne Overvåger?",
|
||||
"confirmClearStatisticsMsg": "Vil du helt sikkert slette ALLE statistikker?",
|
||||
"Clear Data": "Ryd Data",
|
||||
"Events": "Events",
|
||||
"Heartbeats": "Hjerteslag",
|
||||
"Auto Get": "Auto-hent",
|
||||
"enableDefaultNotificationDescription": "For hver ny overvåger aktiveres denne underretning som standard. Du kan stadig deaktivere underretningen separat for hver skærm.",
|
||||
"Default enabled": "Standard aktiveret",
|
||||
"Also apply to existing monitors": "Anvend også på eksisterende overvågere",
|
||||
"Export": "Eksport",
|
||||
"Import": "Import",
|
||||
"backupDescription": "Du kan sikkerhedskopiere alle Overvågere og alle underretninger til en JSON-fil.",
|
||||
"backupDescription2": "PS: Historik og hændelsesdata er ikke inkluderet.",
|
||||
"backupDescription3": "Følsom data, f.eks. underretnings-tokener, er inkluderet i eksportfilen. Gem den sikkert.",
|
||||
"alertNoFile": "Vælg en fil der skal importeres.",
|
||||
"alertWrongFileType": "Vælg venligst en JSON-fil.",
|
||||
"twoFAVerifyLabel": "Indtast venligst dit token for at bekræfte, at 2FA fungerer",
|
||||
"tokenValidSettingsMsg": "Token er gyldigt! Du kan nu gemme 2FA -indstillingerne.",
|
||||
"confirmEnableTwoFAMsg": "Er du sikker på at du vil aktivere 2FA?",
|
||||
"confirmDisableTwoFAMsg": "Er du sikker på at du vil deaktivere 2FA?",
|
||||
"Apply on all existing monitors": "Anvend på alle eksisterende overvågere",
|
||||
"Verify Token": "Verificere Token",
|
||||
"Setup 2FA": "Opsæt 2FA",
|
||||
"Enable 2FA": "Aktiver 2FA",
|
||||
"Disable 2FA": "Deaktiver 2FA",
|
||||
"2FA Settings": "2FA Indstillinger",
|
||||
"Two Factor Authentication": "To-Faktor Autentificering",
|
||||
"Active": "Aktive",
|
||||
"Inactive": "Inaktive",
|
||||
"Token": "Token",
|
||||
"Show URI": "Vis URI",
|
||||
"Clear all statistics": "Ryd alle Statistikker",
|
||||
"retryCheckEverySecond": "Prøv igen hvert {0} sekund.",
|
||||
"importHandleDescription": "Vælg 'Spring over eksisterende', hvis du vil springe over hver overvåger eller underretning med samme navn. 'Overskriv' sletter alle eksisterende overvågere og underretninger.",
|
||||
"confirmImportMsg": "Er du sikker på at importere sikkerhedskopien? Sørg for, at du har valgt den rigtige importindstilling.",
|
||||
"Heartbeat Retry Interval": "Hjerteslag Gentagelsesinterval",
|
||||
"Import Backup": "Importer Backup",
|
||||
"Export Backup": "Eksporter Backup",
|
||||
"Skip existing": "Spring over eksisterende",
|
||||
"Overwrite": "Overskriv",
|
||||
"Options": "Valgmuligheder",
|
||||
"Keep both": "Behold begge",
|
||||
"Tags": "Etiketter",
|
||||
"Add New below or Select...": "Tilføj Nyt nedenfor eller Vælg ...",
|
||||
"Tag with this name already exist.": "Et Tag med dette navn findes allerede.",
|
||||
"Tag with this value already exist.": "Et Tag med denne værdi findes allerede.",
|
||||
"color": "farve",
|
||||
"value (optional)": "værdi (valgfri)",
|
||||
"Gray": "Grå",
|
||||
"Red": "Rød",
|
||||
"Orange": "Orange",
|
||||
"Green": "Grøn",
|
||||
"Blue": "Blå",
|
||||
"Indigo": "Indigo",
|
||||
"Purple": "Lilla",
|
||||
"Pink": "Pink",
|
||||
"Search...": "Søg...",
|
||||
"Avg. Ping": "Gns. Ping",
|
||||
"Avg. Response": "Gns. Respons",
|
||||
"Entry Page": "Entry Side",
|
||||
"statusPageNothing": "Intet her, tilføj venligst en Gruppe eller en Overvåger.",
|
||||
"No Services": "Ingen Tjenester",
|
||||
"All Systems Operational": "Alle Systemer i Drift",
|
||||
"Partially Degraded Service": "Delvist Forringet Service",
|
||||
"Degraded Service": "Forringet Service",
|
||||
"Add Group": "Tilføj Gruppe",
|
||||
"Add a monitor": "Tilføj en Overvåger",
|
||||
"Edit Status Page": "Rediger Statusside",
|
||||
"Go to Dashboard": "Gå til Betjeningspanel",
|
||||
"Status Page": "Statusside",
|
||||
"Status Pages": "Statusside",
|
||||
"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 (Understøtter 50+ Notifikationstjenester)",
|
||||
"pushbullet": "Pushbullet",
|
||||
"line": "Line Messenger",
|
||||
"mattermost": "Mattermost",
|
||||
"Primary Base URL": "Primær Basis-URL",
|
||||
"Push URL": "Push URL",
|
||||
"needPushEvery": "Du bør kalde denne webadresse hvert {0} sekund.",
|
||||
"pushOptionalParams": "Valgfrie parametre: {0}",
|
||||
"defaultNotificationName": "Min {notification} Advarsel ({number})",
|
||||
"here": "her",
|
||||
"Required": "Påkrævet",
|
||||
"Bot Token": "Bot Token",
|
||||
"wayToGetTelegramToken": "Du kan få et token fra {0}.",
|
||||
"Chat ID": "Chat ID",
|
||||
"supportTelegramChatID": "Support Direct Chat / Group / Channel's Chat ID",
|
||||
"wayToGetTelegramChatID": "Du kan få dit chat-ID ved at sende en besked til bot'en og gå til denne URL for at se chat_id'et:",
|
||||
"YOUR BOT TOKEN HERE": "DIT BOT TOKEN HER",
|
||||
"chatIDNotFound": "Chat-ID blev ikke fundet; send venligst en besked til denne bot først ",
|
||||
"Post URL": "Post URL",
|
||||
"Content Type": "Indholdstype",
|
||||
"webhookJsonDesc": "{0} er god til alle moderne HTTP-servere som f.eks Express.js",
|
||||
"webhookFormDataDesc": "{multipart} er god til PHP. JSON'en skal parses med {decodeFunction}",
|
||||
"secureOptionNone": "Ingen / STARTTLS (25, 587)",
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
"Ignore TLS Error": "Ignorer TLS-fejl",
|
||||
"From Email": "Afsender Email",
|
||||
"emailCustomSubject": "Brugerdefineret Emne",
|
||||
"To Email": "Modtager Email",
|
||||
"smtpCC": "CC",
|
||||
"smtpBCC": "BCC",
|
||||
"Discord Webhook URL": "Discord Webhook URL",
|
||||
"wayToGetDiscordURL": "Du kan få dette ved at gå til Serverindstillinger -> Integrationer -> Opret webhook ",
|
||||
"Bot Display Name": "Bot Visningsnavn",
|
||||
"Prefix Custom Message": "Præfiks Brugerdefineret Besked",
|
||||
"Hello @everyone is...": "Hello {'@'}everyone is...",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"wayToGetTeamsURL": "Du kan lære, hvordan du laver en webhook URL {0}.",
|
||||
"Number": "Nummer",
|
||||
"Recipients": "Modtagere",
|
||||
"needSignalAPI": "Du skal have en Signal-klient med REST API.",
|
||||
"wayToCheckSignalURL": "Du kan tjekke denne URL for at se, hvordan du konfigurerer en:",
|
||||
"signalImportant": "VIGTIGT: Du kan ikke blande grupper og numre i modtagere!",
|
||||
"Application Token": "Program Token",
|
||||
"Server URL": "Server URL",
|
||||
"Priority": "Prioritet",
|
||||
"Icon Emoji": "Icon Emoji",
|
||||
"Channel Name": "Kanalnavn",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||
"aboutWebhooks": "Mere info om Webhooks på: {0}",
|
||||
"aboutChannelName": "Indtast kanalnavnet i {0} Kanalnavn feltet, hvis du vil omgå Webhook-kanalen. Eks: #anden-kanal",
|
||||
"aboutKumaURL": "Hvis du efterlader Uptime Kuma URL-feltet tomt, vil det som standard gå til projektets GitHub-siden.",
|
||||
"emojiCheatSheet": "Emoji cheat sheet: {0}",
|
||||
"clicksendsms": "ClickSend SMS",
|
||||
"User Key": "Bruger-Nøgle",
|
||||
"Device": "Enhed",
|
||||
"Message Title": "Besked Titel",
|
||||
"Notification Sound": "Notifikationslyd",
|
||||
"More info on:": "Mere info på: {0}",
|
||||
"pushoverDesc1": "Nødprioritet (2) har som standard 30 sekunders timeout mellem genforsøg og udløber efter 1 time.",
|
||||
"pushoverDesc2": "Hvis du vil sende meddelelser til forskellige enheder, skal du udfylde feltet Enhed.",
|
||||
"SMS Type": "SMS Type",
|
||||
"octopushTypePremium": "Premium (Hurtig - anbefales til advarsel)",
|
||||
"octopushTypeLowCost": "Lavpris (Langsom - nogle gange blokeret af operatøren)",
|
||||
"checkPrice": "Tjek {0} priser:",
|
||||
"apiCredentials": "API legitimationsoplysninger",
|
||||
"octopushLegacyHint": "Bruger du den ældre version af Octopush (2011-2020) eller den nye version?",
|
||||
"Check octopush prices": "Tjek octopush priser {0}.",
|
||||
"octopushPhoneNumber": "Telefonnummer (intl format, f.eks : +4512345678) ",
|
||||
"octopushSMSSender": "SMS Afsender Navn : 3-11 alfanumeriske tegn og mellemrum (a-zA-Z0-9)",
|
||||
"LunaSea Device ID": "LunaSea Enhed-ID",
|
||||
"Apprise URL": "Apprise URL",
|
||||
"Example:": "Eksempel: {0}",
|
||||
"Read more:": "Læs mere: {0}",
|
||||
"Status:": "Status: {0}",
|
||||
"Read more": "Læs mere",
|
||||
"appriseInstalled": "Apprise er installeret.",
|
||||
"appriseNotInstalled": "Apprise er ikke installeret. {0}",
|
||||
"Access Token": "Access Token",
|
||||
"Channel access token": "kanaladgangstoken",
|
||||
"Line Developers Console": "Line Udviklerkonsol",
|
||||
"lineDevConsoleTo": "Line Udviklerkonsol - {0}",
|
||||
"Basic Settings": "Basisindstillinger",
|
||||
"User ID": "Bruger-ID",
|
||||
"Messaging API": "Messaging API",
|
||||
"wayToGetLineChannelToken": "Tilgå først {0}, opret en udbyder og kanal (Messaging API), så kan du få kanaladgangstoken'et og bruger-ID'et fra de ovennævnte menupunkter.",
|
||||
"Icon URL": "Ikon URL",
|
||||
"aboutIconURL": "Du kan angive et link til et billede i \"Ikon URL\" for at tilsidesætte standardprofilbilledet. Vil ikke blive brugt, hvis Ikon Emoji er angivet.",
|
||||
"aboutMattermostChannelName": "Du kan tilsidesætte standardkanalen, som Webhoo'en sender til ved at indtaste kanalnavnet i feltet \"Kanalnavn\". Dette skal aktiveres i Mattermost Webhook-indstillingerne. Eks: #anden-kanal",
|
||||
"matrix": "Matrix",
|
||||
"promosmsTypeEco": "SMS ECO - billig, men langsom og ofte overbelastet. Begrænset kun til polske modtagere.",
|
||||
"promosmsTypeFlash": "SMS FLASH - Beskeden vises automatisk på modtagerenheden. Begrænset kun til polske modtagere.",
|
||||
"promosmsTypeFull": "SMS FULL - Premium-niveau af SMS, Du kan bruge dit \"Sender Name\" (Du skal først registrere navn). Pålidelig til advarsler.",
|
||||
"promosmsTypeSpeed": "SMS SPEED - Højeste prioritet i systemet. Meget hurtig og pålidelig, men dyr (ca. to gange af SMS FULL pris).",
|
||||
"promosmsPhoneNumber": "Telefonnummer (polske numre behøver ikke angive områdenumre)",
|
||||
"promosmsSMSSender": "SMS Sender Name : Forudregistreret navn eller en af standarderne: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||
"Feishu WebHookUrl": "Feishu WebHookURL",
|
||||
"matrixHomeserverURL": "Hjemmeserver-URL (med http(s):// og eventuel port)",
|
||||
"Internal Room Id": "Intern Rum-ID",
|
||||
"matrixDesc1": "Du kan finde det interne rum-ID ved at se i det avancerede afsnit af rumindstillingerne i din Matrix-klient. Det skulle ligne !QMdRCpUIfLwsfjxye6:home.server.",
|
||||
"matrixDesc2": "Det anbefales stærkt, at du opretter en ny bruger og ikke bruger din egen Matrix-brugers adgangstoken, da det giver fuld adgang til din konto og alle de rum, du har tilsluttet dig. I stedet skal du oprette en ny bruger og kun invitere den til det rum, du vil modtage meddelelsen i. Du kan få adgangstokenet ved at køre {0}",
|
||||
"Method": "Metode",
|
||||
"Body": "Body",
|
||||
"Headers": "Headers",
|
||||
"PushUrl": "Push URL",
|
||||
"HeadersInvalidFormat": "\"request headers\"-erne er ikke gyldige JSON: ",
|
||||
"BodyInvalidFormat": "\"request body\"-en er ikke gyldige JSON: ",
|
||||
"Monitor History": "Overvåger Historik",
|
||||
"clearDataOlderThan": "Gem overvågningshistorikdata i {0} dage.",
|
||||
"PasswordsDoNotMatch": "Adgangskoderne stemmer ikke overens.",
|
||||
"records": "forekomster",
|
||||
"One record": "Én forekomst",
|
||||
"steamApiKeyDescription": "For at overvåge en Steam Game Server skal du bruge en Steam Web-API nøgle. Du kan registrere din API-nøgle her: ",
|
||||
"Current User": "Nuværende Bruger",
|
||||
"recent": "Seneste",
|
||||
"Done": "Færdig",
|
||||
"Info": "Info",
|
||||
"Security": "Sikkerhed",
|
||||
"Steam API Key": "Steam API-nøgle",
|
||||
"Shrink Database": "Krymp Database",
|
||||
"Pick a RR-Type...": "Vælg en RR-Type...",
|
||||
"Pick Accepted Status Codes...": "Vælg Accepterede Statuskoder...",
|
||||
"Default": "Standard",
|
||||
"HTTP Options": "HTTP Valgmuligheder",
|
||||
"Create Incident": "Opret Annoncering",
|
||||
"Title": "Titel",
|
||||
"Content": "Indhold",
|
||||
"Style": "Type",
|
||||
"info": "info",
|
||||
"warning": "advarsel",
|
||||
"danger": "fare",
|
||||
"primary": "primær",
|
||||
"light": "lys",
|
||||
"dark": "mørk",
|
||||
"Post": "Udgiv",
|
||||
"Please input title and content": "Indtast venligst titel og indhold",
|
||||
"Created": "Oprettet",
|
||||
"Last Updated": "Sidst Opdateret",
|
||||
"Unpin": "Frigør",
|
||||
"Switch to Light Theme": "Skift til Lys Tema",
|
||||
"Switch to Dark Theme": "Skift til Mørkt Tema",
|
||||
"Show Tags": "Vis Etiketter",
|
||||
"Hide Tags": "Skjul Etiketter",
|
||||
"Description": "Beskrivelse",
|
||||
"No monitors available.": "No monitors available.",
|
||||
"Add one": "Tilføj en",
|
||||
"No Monitors": "Ingen Overvågere",
|
||||
"Untitled Group": "Unavngivet Gruppe",
|
||||
"Services": "Tjenester",
|
||||
"Discard": "Kassér",
|
||||
"Cancel": "Annullér",
|
||||
"Powered by": "Drevet af",
|
||||
"shrinkDatabaseDescription": "Udfør database VACUUM for SQLite. Hvis din database er oprettet efter 1.10.0, er AUTO_VACUUM allerede aktiveret, og denne handling er ikke nødvendig.",
|
||||
"serwersms": "SerwerSMS.pl",
|
||||
"serwersmsAPIUser": "API Brugernavn (inkl. webapi_ prefix)",
|
||||
"serwersmsAPIPassword": "API Adgangskode",
|
||||
"serwersmsPhoneNumber": "Telefonnummer",
|
||||
"serwersmsSenderName": "SMS Afsender Navn (registreret via kundeportal)"
|
||||
}
|
633
src/lang/de-CH.json
Normal file
633
src/lang/de-CH.json
Normal file
@@ -0,0 +1,633 @@
|
||||
{
|
||||
"languageName": "Deutsch (Schweiz)",
|
||||
"Settings": "Einstellungen",
|
||||
"Dashboard": "Dashboard",
|
||||
"New Update": "Update verfügbar",
|
||||
"Language": "Sprache",
|
||||
"Appearance": "Erscheinungsbild",
|
||||
"Theme": "Erscheinungsbild",
|
||||
"General": "Allgemein",
|
||||
"Version": "Version",
|
||||
"Check Update On GitHub": "Auf GitHub nach Updates suchen",
|
||||
"List": "Liste",
|
||||
"Add": "Hinzufügen",
|
||||
"Add New Monitor": "Neuen Monitor hinzufügen",
|
||||
"Quick Stats": "Übersicht",
|
||||
"Up": "Aktiv",
|
||||
"Down": "Inaktiv",
|
||||
"Pending": "Ausstehend",
|
||||
"Unknown": "Unbekannt",
|
||||
"Pause": "Pausieren",
|
||||
"pauseDashboardHome": "Pausiert",
|
||||
"Name": "Name",
|
||||
"Status": "Status",
|
||||
"DateTime": "Datum / Uhrzeit",
|
||||
"Message": "Nachricht",
|
||||
"No important events": "Keine wichtigen Ereignisse",
|
||||
"Resume": "Fortsetzen",
|
||||
"Edit": "Bearbeiten",
|
||||
"Delete": "Löschen",
|
||||
"Current": "Aktuell",
|
||||
"Uptime": "Verfügbarkeit",
|
||||
"Cert Exp.": "Zertifikatsablauf",
|
||||
"day": "Tag | Tage",
|
||||
"-day": "-Tage",
|
||||
"hour": "Stunde",
|
||||
"-hour": "-Stunden",
|
||||
"checkEverySecond": "Überprüfe alle {0} Sekunden",
|
||||
"Response": "Antwortzeit",
|
||||
"Ping": "Ping",
|
||||
"Monitor Type": "Monitor-Typ",
|
||||
"Keyword": "Suchwort",
|
||||
"Friendly Name": "Anzeigename",
|
||||
"URL": "URL",
|
||||
"Hostname": "Hostname",
|
||||
"Port": "Port",
|
||||
"Heartbeat Interval": "Prüfintervall",
|
||||
"Retries": "Wiederholungen",
|
||||
"retriesDescription": "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
|
||||
"Advanced": "Erweitert",
|
||||
"ignoreTLSError": "Ignoriere TLS-/SSL-Fehler von Webseiten",
|
||||
"Upside Down Mode": "Umgekehrter Modus",
|
||||
"upsideDownModeDescription": "Im umgekehrten Modus wird der Dienst als inaktiv angezeigt, wenn er erreichbar ist.",
|
||||
"Max. Redirects": "Max. Weiterleitungen",
|
||||
"maxRedirectDescription": "Maximale Anzahl von Weiterleitungen, denen gefolgt werden soll. Auf 0 setzen, um Weiterleitungen zu deaktivieren.",
|
||||
"Accepted Status Codes": "Erlaubte HTTP-Statuscodes",
|
||||
"acceptedStatusCodesDescription": "Statuscodes auswählen, die als erfolgreiche Verbindung gelten sollen.",
|
||||
"Save": "Speichern",
|
||||
"Notifications": "Benachrichtigungen",
|
||||
"Not available, please setup.": "Nicht verfügbar, bitte einrichten.",
|
||||
"Setup Notification": "Benachrichtigung einrichten",
|
||||
"Light": "Hell",
|
||||
"Dark": "Dunkel",
|
||||
"Auto": "Auto",
|
||||
"Theme - Heartbeat Bar": "Erscheinungsbild - Zeitleiste",
|
||||
"Normal": "Normal",
|
||||
"Bottom": "Unten",
|
||||
"None": "Keine",
|
||||
"Timezone": "Zeitzone",
|
||||
"Search Engine Visibility": "Sichtbarkeit für Suchmaschinen",
|
||||
"Allow indexing": "Indizierung zulassen",
|
||||
"Discourage search engines from indexing site": "Suchmaschinen darum bitten, die Seite nicht zu indizieren",
|
||||
"Change Password": "Passwort ändern",
|
||||
"Current Password": "Aktuelles Passwort",
|
||||
"New Password": "Neues Passwort",
|
||||
"Repeat New Password": "Neues Passwort wiederholen",
|
||||
"passwordNotMatchMsg": "Passwörter stimmen nicht überein.",
|
||||
"Update Password": "Passwort aktualisieren",
|
||||
"Disable Auth": "Authentifizierung deaktivieren",
|
||||
"Enable Auth": "Authentifizierung aktivieren",
|
||||
"disableauth.message1": "Bist du sicher das du die <strong>Authentifizierung deaktivieren</strong> möchtest?",
|
||||
"disableauth.message2": "Dies ist für Szenarien gedacht, <strong>in denen man eine externe Authentifizierung</strong> vor Uptime Kuma geschaltet hat, wie z.B. Cloudflare Access, Authelia oder andere Authentifizierungsmechanismen.",
|
||||
"Please use this option carefully!": "Bitte mit Vorsicht nutzen!",
|
||||
"Logout": "Ausloggen",
|
||||
"notificationDescription": "Benachrichtigungen müssen einem Monitor zugewiesen werden, damit diese funktionieren.",
|
||||
"Leave": "Verlassen",
|
||||
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
|
||||
"Confirm": "Bestätigen",
|
||||
"Yes": "Ja",
|
||||
"No": "Nein",
|
||||
"Username": "Benutzername",
|
||||
"Password": "Passwort",
|
||||
"Remember me": "Angemeldet bleiben",
|
||||
"Login": "Einloggen",
|
||||
"No Monitors, please": "Keine Monitore, bitte",
|
||||
"add one": "hinzufügen",
|
||||
"Notification Type": "Benachrichtigungsdienst",
|
||||
"Email": "E-Mail",
|
||||
"Test": "Test",
|
||||
"Certificate Info": "Zertifikatsinformation",
|
||||
"keywordDescription": "Ein Suchwort in der HTML- oder JSON-Ausgabe finden. Bitte beachte: es wird zwischen Gross-/Kleinschreibung unterschieden.",
|
||||
"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?",
|
||||
"resolverserverDescription": "Cloudflare ist als der Standardserver festgelegt. Dieser kann jederzeit geändert werden.",
|
||||
"Resolver Server": "Auflösungsserver",
|
||||
"rrtypeDescription": "Wähle den RR-Typ aus, welchen du überwachen möchtest.",
|
||||
"Last Result": "Letztes Ergebnis",
|
||||
"pauseMonitorMsg": "Bist du sicher, dass du den Monitor pausieren möchtest?",
|
||||
"clearEventsMsg": "Bist du sicher, dass du alle Ereignisse für diesen Monitor löschen möchtest?",
|
||||
"clearHeartbeatsMsg": "Bist du sicher, dass du alle Statistiken für diesen Monitor löschen möchtest?",
|
||||
"Clear Data": "Lösche Daten",
|
||||
"Events": "Ereignisse",
|
||||
"Heartbeats": "Statistiken",
|
||||
"confirmClearStatisticsMsg": "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
|
||||
"Create your admin account": "Erstelle dein Admin-Konto",
|
||||
"Repeat Password": "Passwort erneut eingeben",
|
||||
"Resource Record Type": "Ressourcen Record Typ",
|
||||
"Export": "Export",
|
||||
"Import": "Import",
|
||||
"respTime": "Antw.-Zeit (ms)",
|
||||
"notAvailableShort": "N/A",
|
||||
"Default enabled": "Standardmässig aktiviert",
|
||||
"Apply on all existing monitors": "Auf alle existierenden Monitore anwenden",
|
||||
"enableDefaultNotificationDescription": "Für jeden neuen Monitor wird diese Benachrichtigung standardmässig aktiviert. Die Benachrichtigung kann weiterhin für jeden Monitor separat deaktiviert werden.",
|
||||
"Create": "Erstellen",
|
||||
"Auto Get": "Auto Get",
|
||||
"backupDescription": "Es können alle Monitore und Benachrichtigungen in einer JSON-Datei gesichert werden.",
|
||||
"backupDescription2": "PS: Verlaufs- und Ereignisdaten sind nicht enthalten.",
|
||||
"backupDescription3": "Sensible Daten wie Benachrichtigungs-Token sind in der Exportdatei enthalten, bitte bewahre sie sorgfältig auf.",
|
||||
"alertNoFile": "Bitte wähle eine Datei zum Importieren aus.",
|
||||
"alertWrongFileType": "Bitte wähle eine JSON-Datei aus.",
|
||||
"Clear all statistics": "Lösche alle Statistiken",
|
||||
"importHandleDescription": "Wähle 'Vorhandene überspringen' aus, wenn jeder Monitor oder jede Benachrichtigung mit demselben Namen übersprungen werden soll. 'Überschreiben' löscht jeden vorhandenen Monitor sowie Benachrichtigungen.",
|
||||
"Skip existing": "Vorhandene überspringen",
|
||||
"Overwrite": "Überschreiben",
|
||||
"Options": "Optionen",
|
||||
"confirmImportMsg": "Möchtest du das Backup wirklich importieren? Bitte stelle sicher, dass die richtige Import-Option ausgewählt ist.",
|
||||
"Keep both": "Beide behalten",
|
||||
"twoFAVerifyLabel": "Bitte trage deinen Token ein, um zu verifizieren, dass 2FA funktioniert",
|
||||
"Verify Token": "Token verifizieren",
|
||||
"Setup 2FA": "2FA einrichten",
|
||||
"Enable 2FA": "2FA aktivieren",
|
||||
"Disable 2FA": "2FA deaktivieren",
|
||||
"2FA Settings": "2FA-Einstellungen",
|
||||
"confirmEnableTwoFAMsg": "Bist du sicher, dass du 2FA aktivieren möchtest?",
|
||||
"confirmDisableTwoFAMsg": "Bist du sicher, dass du 2FA deaktivieren möchtest?",
|
||||
"tokenValidSettingsMsg": "Token gültig! Du kannst jetzt die 2FA-Einstellungen speichern.",
|
||||
"Two Factor Authentication": "Zwei-Faktor-Authentifizierung",
|
||||
"Active": "Aktiv",
|
||||
"Inactive": "Inaktiv",
|
||||
"Token": "Token",
|
||||
"Show URI": "URI anzeigen",
|
||||
"Tags": "Tags",
|
||||
"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 value already exist.": "Ein Tag mit diesem Wert existiert bereits.",
|
||||
"color": "Farbe",
|
||||
"value (optional)": "Wert (optional)",
|
||||
"Gray": "Grau",
|
||||
"Red": "Rot",
|
||||
"Orange": "Orange",
|
||||
"Green": "Grün",
|
||||
"Blue": "Blau",
|
||||
"Indigo": "Indigo",
|
||||
"Purple": "Lila",
|
||||
"Pink": "Pink",
|
||||
"Search...": "Suchen…",
|
||||
"Heartbeat Retry Interval": "Überprüfungsintervall",
|
||||
"Resend Notification if Down X times consequently": "Benachrichtigung erneut senden, wenn Inaktiv X mal hintereinander",
|
||||
"retryCheckEverySecond": "Alle {0} Sekunden neu versuchen",
|
||||
"resendEveryXTimes": "Erneut versenden alle {0} mal",
|
||||
"resendDisabled": "Erneut versenden deaktiviert",
|
||||
"Import Backup": "Backup importieren",
|
||||
"Export Backup": "Backup exportieren",
|
||||
"Avg. Ping": "Ping ø",
|
||||
"Avg. Response": "Antwortzeit ø",
|
||||
"Entry Page": "Einstiegsseite",
|
||||
"statusPageNothing": "Noch ist hier nichts. Bitte füge eine Gruppe oder einen Monitor hinzu.",
|
||||
"No Services": "Keine Dienste",
|
||||
"All Systems Operational": "Alle Systeme betriebsbereit",
|
||||
"Partially Degraded Service": "Teilweise beeinträchtigter Dienst",
|
||||
"Degraded Service": "Eingeschränkter Dienst",
|
||||
"Add Group": "Gruppe hinzufügen",
|
||||
"Add a monitor": "Monitor hinzufügen",
|
||||
"Edit Status Page": "Bearbeite Status-Seite",
|
||||
"Go to Dashboard": "Gehe zum Dashboard",
|
||||
"Status Page": "Status-Seite",
|
||||
"Status Pages": "Status-Seiten",
|
||||
"telegram": "Telegram",
|
||||
"webhook": "Webhook",
|
||||
"smtp": "E-Mail (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 (Unterstützung für 50+ Benachrichtigungsdienste)",
|
||||
"GoogleChat": "Google Chat (nur Google Workspace)",
|
||||
"pushbullet": "Pushbullet",
|
||||
"line": "Line Messenger",
|
||||
"mattermost": "Mattermost",
|
||||
"Primary Base URL": "Primär URL",
|
||||
"Push URL": "Push URL",
|
||||
"needPushEvery": "Du solltest diese URL alle {0} Sekunden aufrufen",
|
||||
"pushOptionalParams": "Optionale Parameter: {0}",
|
||||
"defaultNotificationName": "Mein {notification} Alarm ({number})",
|
||||
"here": "hier",
|
||||
"Required": "Erforderlich",
|
||||
"Bot Token": "Bot Token",
|
||||
"wayToGetTelegramToken": "Hier kannst du einen Token erhalten {0}.",
|
||||
"Chat ID": "Chat ID",
|
||||
"supportTelegramChatID": "Unterstützt Direkt Chat / Gruppe / Kanal Chat-ID's",
|
||||
"wayToGetTelegramChatID": "Du kannst die Chat-ID erhalten, indem du eine Nachricht an den Bot sendest und zu dieser URL gehst, um die chat_id: zu sehen.",
|
||||
"YOUR BOT TOKEN HERE": "HIER DEIN BOT TOKEN",
|
||||
"chatIDNotFound": "Chat-ID wurde nicht gefunden: bitte sende zuerst eine Nachricht an diesen Bot",
|
||||
"Post URL": "Post URL",
|
||||
"Content Type": "Content Type",
|
||||
"webhookJsonDesc": "{0} ist gut für alle modernen HTTP-Server, wie z.B. Express.js, geeignet",
|
||||
"webhookFormDataDesc": "{multipart} ist gut für PHP. Das JSON muss mit {decodeFunction} verarbeitet werden",
|
||||
"secureOptionNone": "Keine / STARTTLS (25, 587)",
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
"Ignore TLS Error": "TLS-Fehler ignorieren",
|
||||
"From Email": "Absender E-Mail",
|
||||
"emailCustomSubject": "Benutzerdefinierter Betreff",
|
||||
"To Email": "Empfänger E-Mail",
|
||||
"smtpCC": "CC",
|
||||
"smtpBCC": "BCC",
|
||||
"Discord Webhook URL": "Discord Webhook URL",
|
||||
"wayToGetDiscordURL": "Du kannst diese erhalten, indem du zu den Servereinstellungen gehst -> Integrationen -> Neuer Webhook",
|
||||
"Bot Display Name": "Bot-Anzeigename",
|
||||
"Prefix Custom Message": "Benutzerdefinierter Nachrichten Präfix",
|
||||
"Hello @everyone is...": "Hallo {'@'}everyone ist…",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"wayToGetTeamsURL": "Wie eine Webhook-URL erstellt werden kann, erfährst du {0}.",
|
||||
"Number": "Nummer",
|
||||
"Recipients": "Empfänger",
|
||||
"needSignalAPI": "Es wird ein Signal Client mit REST-API benötigt.",
|
||||
"wayToCheckSignalURL": "Du kannst diese URL aufrufen, um zu sehen, wie du eine einrichtest:",
|
||||
"signalImportant": "WICHTIG: Gruppen und Nummern können in Empfängern nicht gemischt werden!",
|
||||
"Application Token": "Anwendungstoken",
|
||||
"Server URL": "Server URL",
|
||||
"Priority": "Priorität",
|
||||
"Icon Emoji": "Icon Emoji",
|
||||
"Channel Name": "Kanalname",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||
"aboutWebhooks": "Weitere Informationen zu Webhooks auf: {0}",
|
||||
"aboutChannelName": "Gebe den Kanalnamen ein in {0} Feld Kanalname, falls du den Webhook-Kanal umgehen möchtest. Ex: #other-channel",
|
||||
"aboutKumaURL": "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird standardmässig die GitHub Projekt Seite verwendet.",
|
||||
"emojiCheatSheet": "Emoji Cheat Sheet: {0}",
|
||||
"User Key": "Benutzerschlüssel",
|
||||
"Device": "Gerät",
|
||||
"Message Title": "Nachrichtentitel",
|
||||
"Notification Sound": "Benachrichtigungston",
|
||||
"More info on:": "Mehr Infos auf: {0}",
|
||||
"pushoverDesc1": "Notfallpriorität (2) hat standardmässig 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.",
|
||||
"SMS Type": "SMS Typ",
|
||||
"octopushTypePremium": "Premium (Schnell - zur Benachrichtigung empfohlen)",
|
||||
"octopushTypeLowCost": "Kostengünstig (Langsam - manchmal vom Betreiber gesperrt)",
|
||||
"checkPrice": "Prüfe {0} Preise:",
|
||||
"octopushLegacyHint": "Verwendest du die Legacy-Version von Octopush (2011-2020) oder die neue Version?",
|
||||
"Check octopush prices": "Vergleiche die Oktopush Preise {0}.",
|
||||
"octopushPhoneNumber": "Telefonnummer (Internationales Format, z.B : +49612345678) ",
|
||||
"octopushSMSSender": "Name des SMS-Absenders : 3-11 alphanumerische Zeichen und Leerzeichen (a-zA-Z0-9)",
|
||||
"LunaSea Device ID": "LunaSea Geräte ID",
|
||||
"Apprise URL": "Apprise URL",
|
||||
"Example:": "Beispiel: {0}",
|
||||
"Read more:": "Weiterlesen: {0}",
|
||||
"Status:": "Status: {0}",
|
||||
"Read more": "Weiterlesen",
|
||||
"appriseInstalled": "Apprise ist installiert.",
|
||||
"appriseNotInstalled": "Apprise ist nicht installiert. {0}",
|
||||
"Access Token": "Access Token",
|
||||
"Channel access token": "Channel access token",
|
||||
"Line Developers Console": "Line Developers Console",
|
||||
"lineDevConsoleTo": "Line Developers Console - {0}",
|
||||
"Basic Settings": "Basic Settings",
|
||||
"User ID": "User ID",
|
||||
"Messaging API": "Messaging API",
|
||||
"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",
|
||||
"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 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",
|
||||
"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. 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.",
|
||||
"promosmsTypeSpeed": "SMS SPEED - Höchste Priorität im System. Sehr schnell und zuverlässig, aber teuer (Ungefähr das doppelte von SMS FULL).",
|
||||
"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",
|
||||
"Feishu WebHookUrl": "Feishu Webhook URL",
|
||||
"matrixHomeserverURL": "Heimserver URL (mit http(s):// und optionalen Ports)",
|
||||
"Internal Room Id": "Interne Raum-ID",
|
||||
"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 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",
|
||||
"Body": "Body",
|
||||
"Headers": "Headers",
|
||||
"PushUrl": "Push URL",
|
||||
"HeadersInvalidFormat": "Der Header ist kein gültiges JSON: ",
|
||||
"BodyInvalidFormat": "Der Body ist kein gültiges JSON: ",
|
||||
"Monitor History": "Monitor Verlauf",
|
||||
"clearDataOlderThan": "Bewahre die Aufzeichnungsdaten für {0} Tage auf.",
|
||||
"PasswordsDoNotMatch": "Passwörter stimmen nicht überein.",
|
||||
"records": "Einträge",
|
||||
"One record": "Ein Eintrag",
|
||||
"steamApiKeyDescription": "Um einen Steam Game Server zu überwachen, wird ein Steam Web-API-Schlüssel benötigt. Dieser kann hier registriert werden: ",
|
||||
"Current User": "Aktueller Benutzer",
|
||||
"recent": "Letzte",
|
||||
"Done": "Fertig",
|
||||
"Info": "Info",
|
||||
"Security": "Sicherheit",
|
||||
"Steam API Key": "Steam API Key",
|
||||
"Shrink Database": "Datenbank verkleinern",
|
||||
"Pick a RR-Type...": "Wähle ein RR-Typ aus…",
|
||||
"Pick Accepted Status Codes...": "Wähle akzeptierte Statuscodes aus…",
|
||||
"Default": "Standard",
|
||||
"HTTP Options": "HTTP Optionen",
|
||||
"Create Incident": "Vorfall erstellen",
|
||||
"Title": "Titel",
|
||||
"Content": "Inhalt",
|
||||
"Style": "Stil",
|
||||
"info": "info",
|
||||
"warning": "warnung",
|
||||
"danger": "gefahr",
|
||||
"primary": "primär",
|
||||
"light": "hell",
|
||||
"dark": "dunkel",
|
||||
"Post": "Eintrag",
|
||||
"Please input title and content": "Bitte Titel und Inhalt eingeben",
|
||||
"Created": "Erstellt",
|
||||
"Last Updated": "Zuletzt aktualisiert",
|
||||
"Unpin": "Loslösen",
|
||||
"Switch to Light Theme": "Zu hellem Thema wechseln",
|
||||
"Switch to Dark Theme": "Zum dunklen Thema wechseln",
|
||||
"Show Tags": "Tags anzeigen",
|
||||
"Hide Tags": "Tags ausblenden",
|
||||
"Description": "Beschreibung",
|
||||
"No monitors available.": "Keine Monitore verfügbar.",
|
||||
"Add one": "Hinzufügen",
|
||||
"No Monitors": "Keine Monitore",
|
||||
"Untitled Group": "Gruppe ohne Titel",
|
||||
"Services": "Dienste",
|
||||
"Discard": "Verwerfen",
|
||||
"Cancel": "Abbrechen",
|
||||
"Powered by": "Powered by",
|
||||
"shrinkDatabaseDescription": "Löse VACUUM für die SQLite Datenbank aus. Wenn die Datenbank nach 1.10.0 erstellt wurde, ist AUTO_VACUUM bereits aktiviert und diese Aktion ist nicht erforderlich.",
|
||||
"serwersms": "SerwerSMS.pl",
|
||||
"serwersmsAPIUser": "API Benutzername (inkl. webapi_ prefix)",
|
||||
"serwersmsAPIPassword": "API Passwort",
|
||||
"serwersmsPhoneNumber": "Telefonnummer",
|
||||
"serwersmsSenderName": "Name des SMS-Absenders (über Kundenportal registriert)",
|
||||
"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)",
|
||||
"PushByTechulus": "Push by Techulus",
|
||||
"gorush": "Gorush",
|
||||
"alerta": "Alerta",
|
||||
"alertaApiEndpoint": "API Endpunkt",
|
||||
"alertaEnvironment": "Umgebung",
|
||||
"alertaApiKey": "API Schlüssel",
|
||||
"alertaAlertState": "Alarmstatus",
|
||||
"alertaRecoverState": "Wiederherstellungsstatus",
|
||||
"deleteStatusPageMsg": "Bist du sicher, dass du diese Status-Seite löschen willst?",
|
||||
"Proxies": "Proxies",
|
||||
"default": "Standard",
|
||||
"enabled": "Aktiviert",
|
||||
"setAsDefault": "Als Standard setzen",
|
||||
"deleteProxyMsg": "Bist du sicher, dass du diesen Proxy für alle Monitore löschen willst?",
|
||||
"proxyDescription": "Proxies müssen einem Monitor zugewiesen werden, um zu funktionieren.",
|
||||
"enableProxyDescription": "Dieser Proxy wird keinen Effekt auf Monitor-Anfragen haben, bis er aktiviert ist. Du kannst ihn temporär von allen Monitoren nach Aktivierungsstatus deaktivieren.",
|
||||
"setAsDefaultProxyDescription": "Dieser Proxy wird standardmässig für alle neuen Monitore aktiviert sein. Du kannst den Proxy immer noch für jeden Monitor einzeln deaktivieren.",
|
||||
"Certificate Chain": "Zertifikatskette",
|
||||
"Valid": "Gültig",
|
||||
"Invalid": "Ungültig",
|
||||
"AccessKeyId": "AccessKey ID",
|
||||
"SecretAccessKey": "AccessKey Secret",
|
||||
"PhoneNumbers": "Telefonnummern",
|
||||
"TemplateCode": "Vorlagencode",
|
||||
"SignName": "Signaturname",
|
||||
"Sms template must contain parameters: ": "SMS Vorlage muss folgende Parameter enthalten: ",
|
||||
"Bark Endpoint": "Bark Endpunkt",
|
||||
"WebHookUrl": "Webhook URL",
|
||||
"SecretKey": "Geheimer Schlüssel",
|
||||
"For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden",
|
||||
"Device Token": "Gerätetoken",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Hoch",
|
||||
"Retry": "Wiederholungen",
|
||||
"Topic": "Thema",
|
||||
"WeCom Bot Key": "WeCom Bot Schlüssel",
|
||||
"Setup Proxy": "Proxy einrichten",
|
||||
"Proxy Protocol": "Proxy Protokoll",
|
||||
"Proxy Server": "Proxy-Server",
|
||||
"Proxy server has authentication": "Proxy-Server hat Authentifizierung",
|
||||
"User": "Benutzer",
|
||||
"Installed": "Installiert",
|
||||
"Not installed": "Nicht installiert",
|
||||
"Running": "Läuft",
|
||||
"Not running": "Gestoppt",
|
||||
"Remove Token": "Token entfernen",
|
||||
"Start": "Start",
|
||||
"Stop": "Stop",
|
||||
"Uptime Kuma": "Uptime Kuma",
|
||||
"Add New Status Page": "Neue Status-Seite hinzufügen",
|
||||
"Slug": "Slug",
|
||||
"Accept characters:": "Akzeptierte Zeichen:",
|
||||
"startOrEndWithOnly": "Nur mit {0} anfangen und enden",
|
||||
"No consecutive dashes": "Keine aufeinanderfolgenden Bindestriche",
|
||||
"Next": "Weiter",
|
||||
"The slug is already taken. Please choose another slug.": "Der Slug ist bereits in Verwendung. Bitte wähle einen anderen.",
|
||||
"No Proxy": "Kein Proxy",
|
||||
"Authentication": "Authentifizierung",
|
||||
"HTTP Basic Auth": "HTTP Basisauthentifizierung",
|
||||
"New Status Page": "Neue Status-Seite",
|
||||
"Page Not Found": "Seite nicht gefunden",
|
||||
"Reverse Proxy": "Reverse Proxy",
|
||||
"Backup": "Sicherung",
|
||||
"About": "Über",
|
||||
"wayToGetCloudflaredURL": "(Lade Cloudflare von {0} herunter)",
|
||||
"cloudflareWebsite": "Cloudflare Website",
|
||||
"Message:": "Nachricht:",
|
||||
"Don't know how to get the token? Please read the guide:": "Du weisst nicht, wie man den Token bekommt? Lies die Anleitung dazu:",
|
||||
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Die aktuelle Verbindung kann unterbrochen werden, wenn du aktuell über Cloudflare Tunnel verbunden bist. Bist du sicher, dass du es stoppen willst? Gib zur Bestätigung dein aktuelles Passwort ein.",
|
||||
"Other Software": "Andere Software",
|
||||
"For example: nginx, Apache and Traefik.": "Zum Beispiel: nginx, Apache und Traefik.",
|
||||
"Please read": "Bitte lesen",
|
||||
"Subject:": "Betreff:",
|
||||
"Valid To:": "Gültig bis:",
|
||||
"Days Remaining:": "Tage verbleibend:",
|
||||
"Issuer:": "Aussteller:",
|
||||
"Fingerprint:": "Fingerabdruck:",
|
||||
"No status pages": "Keine Status-Seiten",
|
||||
"Domain Name Expiry Notification": "Benachrichtigung bei Ablauf des Domainnamens",
|
||||
"Customize": "Anpassen",
|
||||
"Custom Footer": "Eigener Footer",
|
||||
"Custom CSS": "Eigenes CSS",
|
||||
"Footer Text": "Fusszeile",
|
||||
"Show Powered By": "Zeige 'Powered By'",
|
||||
"Date Created": "Erstellt am",
|
||||
"Domain Names": "Domainnamen",
|
||||
"signedInDisp": "Angemeldet als {0}",
|
||||
"signedInDispDisabled": "Authentifizierung deaktiviert.",
|
||||
"dnsPortDescription": "DNS server port. Standard ist 53. Der Port kann jederzeit geändert werden.",
|
||||
"topic": "Thema",
|
||||
"topicExplanation": "MQTT Thema für den monitor",
|
||||
"successMessage": "Erfolgsnachricht",
|
||||
"successMessageExplanation": "MQTT Nachricht, die als Erfolg angesehen wird",
|
||||
"error": "Fehler",
|
||||
"critical": "kritisch",
|
||||
"wayToGetPagerDutyKey": "Dieser kann unter Service -> Service Directory -> (Select a service) -> Integrations -> Add integration gefunden werden. Hier muss nach \"Events API V2\" gesucht werden. Mehr informationen {0}",
|
||||
"Integration Key": "Schlüssel der Integration",
|
||||
"Integration URL": "URL der Integration",
|
||||
"Auto resolve or acknowledged": "Automatisch lösen oder bestätigen",
|
||||
"do nothing": "nichts tun",
|
||||
"auto acknowledged": "automatisch bestätigen",
|
||||
"auto resolve": "automatisch lösen",
|
||||
"Bark Group": "Bark Gruppe",
|
||||
"Bark Sound": "Bark Klang",
|
||||
"HTTP Headers": "HTTP Kopfzeilen",
|
||||
"Trust Proxy": "Vertrauenswürdiger Proxy",
|
||||
"Proxy": "Proxy",
|
||||
"HomeAssistant": "Home Assistant",
|
||||
"onebotHttpAddress": "OneBot HTTP Adresse",
|
||||
"onebotMessageType": "OneBot Nachrichtentyp",
|
||||
"onebotGroupMessage": "Gruppe",
|
||||
"onebotPrivateMessage": "Privat",
|
||||
"onebotUserOrGroupId": "Gruppe/Nutzer ID",
|
||||
"onebotSafetyTips": "Zur Sicherheit ein access token setzen",
|
||||
"PushDeer Key": "PushDeer Schlüssel",
|
||||
"RadiusSecret": "Radius Geheimnis",
|
||||
"RadiusSecretDescription": "Geteiltes Geheimnis zwischen Client und Server",
|
||||
"RadiusCalledStationId": "ID der angesprochenen Station",
|
||||
"RadiusCalledStationIdDescription": "Identifikation des angesprochenen Geräts",
|
||||
"RadiusCallingStationId": "ID der ansprechenden Station",
|
||||
"RadiusCallingStationIdDescription": "Identifikation des ansprechenden Geräts",
|
||||
"Certificate Expiry Notification": "Benachrichtigung ablaufendes Zertifikat",
|
||||
"API Username": "API Nutzername",
|
||||
"API Key": "API Schlüssel",
|
||||
"Recipient Number": "Empfängernummer",
|
||||
"From Name/Number": "Von Name/Nummer",
|
||||
"Leave blank to use a shared sender number.": "Leer lassen um eine geteilte Absendernummer zu nutzen.",
|
||||
"Octopush API Version": "Octopush API Version",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"endpoint": "Endpunkt",
|
||||
"octopushAPIKey": "\"API Schlüssel\" der HTTP API Zugangsdaten im control panel",
|
||||
"octopushLogin": "\"Login\" der HTTP API Zugangsdaten im control panel",
|
||||
"promosmsLogin": "API Login Name",
|
||||
"promosmsPassword": "API Password",
|
||||
"pushoversounds pushover": "Pushover (Standard)",
|
||||
"pushoversounds bike": "Fahrrad",
|
||||
"pushoversounds bugle": "Signalhorn",
|
||||
"pushoversounds cashregister": "Kasse",
|
||||
"pushoversounds classical": "Klassisch",
|
||||
"pushoversounds cosmic": "Kosmisch",
|
||||
"pushoversounds falling": "Abfallend",
|
||||
"pushoversounds gamelan": "Gamelan",
|
||||
"pushoversounds incoming": "Eingang",
|
||||
"pushoversounds intermission": "Pause",
|
||||
"pushoversounds magic": "Magisch",
|
||||
"pushoversounds mechanical": "Mechanisch",
|
||||
"pushoversounds pianobar": "Piano Bar",
|
||||
"pushoversounds siren": "Sirene",
|
||||
"pushoversounds spacealarm": "Space Alarm",
|
||||
"pushoversounds tugboat": "Schlepper Horn",
|
||||
"pushoversounds alien": "Ausserirdisch (lang)",
|
||||
"pushoversounds climb": "Ansteigende (lang)",
|
||||
"pushoversounds persistent": "Hartnäckig (lang)",
|
||||
"pushoversounds echo": "Pushover Echo (lang)",
|
||||
"pushoversounds updown": "Auf und Ab (lang)",
|
||||
"pushoversounds vibrate": "Nur vibrieren",
|
||||
"pushoversounds none": "Nichts (Stille)",
|
||||
"pushyAPIKey": "Geheimer API Schlüssel",
|
||||
"pushyToken": "Gerätetoken",
|
||||
"Show update if available": "Verfügbare Updates anzeigen",
|
||||
"Also check beta release": "Auch nach beta Versionen schauen",
|
||||
"Using a Reverse Proxy?": "Wird ein Reverse Proxy genutzt?",
|
||||
"Check how to config it for WebSocket": "Prüfen, wie er für die Nutzung mit WebSocket konfiguriert wird",
|
||||
"Steam Game Server": "Steam Game Server",
|
||||
"Most likely causes:": "Wahrscheinliche Ursachen:",
|
||||
"The resource is no longer available.": "Die Quelle ist nicht mehr verfügbar.",
|
||||
"There might be a typing error in the address.": "Es gibt einen Tippfehler in der Adresse.",
|
||||
"What you can try:": "Was du versuchen kannst:",
|
||||
"Retype the address.": "Schreibe die Adresse erneut.",
|
||||
"Go back to the previous page.": "Gehe zur vorigen Seite.",
|
||||
"Coming Soon": "Kommt bald",
|
||||
"wayToGetClickSendSMSToken": "Du kannst einen API Nutzernamen und Schlüssel unter {0} erhalten.",
|
||||
"Connection String": "Verbindungstext",
|
||||
"Query": "Abfrage",
|
||||
"settingsCertificateExpiry": "TLS Zertifikatsablauf",
|
||||
"certificationExpiryDescription": "HTTPS Monitore senden eine Benachrichtigung, wenn das Zertifikat abläuft in:",
|
||||
"Setup Docker Host": "Docker Host einrichten",
|
||||
"Connection Type": "Verbindungstyp",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
"deleteDockerHostMsg": "Bist du sicher diesen docker host für alle Monitore zu löschen?",
|
||||
"socket": "Socket",
|
||||
"tcp": "TCP / HTTP",
|
||||
"Docker Container": "Docker Container",
|
||||
"Container Name / ID": "Container Name / ID",
|
||||
"Docker Host": "Docker Host",
|
||||
"Docker Hosts": "Docker Hosts",
|
||||
"ntfy Topic": "ntfy Thema",
|
||||
"Domain": "Domain",
|
||||
"Workstation": "Workstation",
|
||||
"disableCloudflaredNoAuthMsg": "Du bist im nicht-authentifizieren Modus, ein Passwort wird nicht benötigt.",
|
||||
"trustProxyDescription": "Vertraue 'X-Forwarded-*' headern. Wenn man die richtige client IP haben möchte und Uptime Kuma hinter einem Proxy wie Nginx or Apache läuft, wollte dies aktiviert werden.",
|
||||
"wayToGetLineNotifyToken": "Du kannst hier ein Token erhalten: {0}",
|
||||
"Examples": "Beispiele",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "Lange gültiges Access Token",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Lange gültige Access Token können durch klicken auf den Profilnamen (unten links) und dann einen Klick auf Create Token am Ende erstellt werden. ",
|
||||
"Notification Service": "Benachrichtigungsdienst",
|
||||
"default: notify all devices": "standard: Alle Geräte benachrichtigen",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Eine Liste der Benachrichtigungsdienste kann im Home Assistant unter \"Developer Tools > Services\" gefunden werden, wnen man nach \"notification\" sucht um den Geräte-/Telefonnamen zu finden.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Automatisierungen können optional im Home Assistant ausgelöst werden:",
|
||||
"Trigger type:": "Auslöser:",
|
||||
"Event type:": "Ereignistyp:",
|
||||
"Event data:": "Ereignis daten:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.",
|
||||
"Frontend Version": "Frontend Version",
|
||||
"Frontend Version do not match backend version!": "Die Frontend Version stimmt nicht mit der backend version überein!",
|
||||
"Maintenance": "Wartung",
|
||||
"statusMaintenance": "Wartung",
|
||||
"Schedule maintenance": "Geplante Wartung",
|
||||
"Affected Monitors": "Betroffene Monitore",
|
||||
"Pick Affected Monitors...": "Wähle betroffene Monitore…",
|
||||
"Start of maintenance": "Beginn der Wartung",
|
||||
"All Status Pages": "Alle Status Seiten",
|
||||
"Select status pages...": "Wähle Status Seiten…",
|
||||
"recurringIntervalMessage": "einmal pro Tag ausgeführt | Wird alle {0} Tage ausgführt",
|
||||
"affectedMonitorsDescription": "Wähle alle Monitore die von der Wartung betroffen sind",
|
||||
"affectedStatusPages": "Zeige diese Nachricht auf ausgewählten Status Seiten",
|
||||
"atLeastOneMonitor": "Wähle mindestens einen Monitor",
|
||||
"deleteMaintenanceMsg": "Möchtest du diese Wartung löschen?",
|
||||
"Base URL": "Basis URL",
|
||||
"goAlertInfo": "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt. {0}",
|
||||
"goAlertIntegrationKeyInfo": "Bekommt einen generischen API Schlüssel in folgenden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise entspricht dies dem Wert des Token aus der URL.",
|
||||
"goAlert": "GoAlert",
|
||||
"backupOutdatedWarning": "Veraltet: Eine menge Neuerungen sind eingeflossen und diese Funktion wurde etwas vernachlässigt worden. Es kann kein vollständiges Backup erstellt oder eingespielt werden.",
|
||||
"backupRecommend": "Bitte Backup das Volume oder den Ordner (./ data /) selbst.",
|
||||
"Optional": "Optional",
|
||||
"squadcast": "Squadcast",
|
||||
"SendKey": "SendKey",
|
||||
"SMSManager API Docs": "SMSManager API Dokumente",
|
||||
"Gateway Type": "Gateway Type",
|
||||
"SMSManager": "SMSManager",
|
||||
"You can divide numbers with": "Du kannst Zahlen teilen mit",
|
||||
"or": "oder",
|
||||
"recurringInterval": "Intervall",
|
||||
"Recurring": "Wiederkehrend",
|
||||
"strategyManual": "Active/Inactive Manually",
|
||||
"warningTimezone": "Es wird die Zeitzone des Servers genutzt",
|
||||
"weekdayShortMon": "Mo",
|
||||
"weekdayShortTue": "Di",
|
||||
"weekdayShortWed": "Mi",
|
||||
"weekdayShortThu": "Do",
|
||||
"weekdayShortFri": "Fr",
|
||||
"weekdayShortSat": "Sa",
|
||||
"weekdayShortSun": "So",
|
||||
"dayOfWeek": "Tag der Woche",
|
||||
"dayOfMonth": "Tag im Monat",
|
||||
"lastDay": "Letzter Tag",
|
||||
"lastDay1": "Letzter Tag im Monat",
|
||||
"lastDay2": "Vorletzer Tag im Monat",
|
||||
"lastDay3": "3. letzter Tag im Monat",
|
||||
"lastDay4": "4. letzter Tag im Monat",
|
||||
"No Maintenance": "Keine Wartung",
|
||||
"pauseMaintenanceMsg": "Möchtest du wirklich pausieren?",
|
||||
"maintenanceStatus-under-maintenance": "Unter Wartung",
|
||||
"maintenanceStatus-inactive": "Inaktiv",
|
||||
"maintenanceStatus-scheduled": "Geplant",
|
||||
"maintenanceStatus-ended": "Ende",
|
||||
"maintenanceStatus-unknown": "Unbekannt",
|
||||
"Display Timezone": "Zeitzone anzeigen",
|
||||
"Server Timezone": "Server Zeitzone"
|
||||
}
|
647
src/lang/de-DE.json
Normal file
647
src/lang/de-DE.json
Normal file
@@ -0,0 +1,647 @@
|
||||
{
|
||||
"languageName": "Deutsch (Deutschland)",
|
||||
"Settings": "Einstellungen",
|
||||
"Dashboard": "Dashboard",
|
||||
"New Update": "Update verfügbar",
|
||||
"Language": "Sprache",
|
||||
"Appearance": "Erscheinungsbild",
|
||||
"Theme": "Erscheinungsbild",
|
||||
"General": "Allgemein",
|
||||
"Version": "Version",
|
||||
"Check Update On GitHub": "Auf GitHub nach Updates suchen",
|
||||
"List": "Liste",
|
||||
"Add": "Hinzufügen",
|
||||
"Add New Monitor": "Neuen Monitor hinzufügen",
|
||||
"Quick Stats": "Übersicht",
|
||||
"Up": "Aktiv",
|
||||
"Down": "Inaktiv",
|
||||
"Pending": "Ausstehend",
|
||||
"Unknown": "Unbekannt",
|
||||
"Pause": "Pausieren",
|
||||
"pauseDashboardHome": "Pausiert",
|
||||
"Name": "Name",
|
||||
"Status": "Status",
|
||||
"DateTime": "Datum / Uhrzeit",
|
||||
"Message": "Nachricht",
|
||||
"No important events": "Keine wichtigen Ereignisse",
|
||||
"Resume": "Fortsetzen",
|
||||
"Edit": "Bearbeiten",
|
||||
"Delete": "Löschen",
|
||||
"Current": "Aktuell",
|
||||
"Uptime": "Verfügbarkeit",
|
||||
"Cert Exp.": "Zertifikatsablauf",
|
||||
"day": "Tag | Tage",
|
||||
"-day": "-Tage",
|
||||
"hour": "Stunde",
|
||||
"-hour": "-Stunden",
|
||||
"checkEverySecond": "Überprüfe alle {0} Sekunden",
|
||||
"Response": "Antwortzeit",
|
||||
"Ping": "Ping",
|
||||
"Monitor Type": "Monitor-Typ",
|
||||
"Keyword": "Suchwort",
|
||||
"Friendly Name": "Anzeigename",
|
||||
"URL": "URL",
|
||||
"Hostname": "Hostname",
|
||||
"Port": "Port",
|
||||
"Heartbeat Interval": "Prüfintervall",
|
||||
"Retries": "Wiederholungen",
|
||||
"retriesDescription": "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
|
||||
"Advanced": "Erweitert",
|
||||
"ignoreTLSError": "Ignoriere TLS-/SSL-Fehler von Webseiten",
|
||||
"Upside Down Mode": "Umgekehrter Modus",
|
||||
"upsideDownModeDescription": "Im umgekehrten Modus wird der Dienst als inaktiv angezeigt, wenn er erreichbar ist.",
|
||||
"Max. Redirects": "Max. Weiterleitungen",
|
||||
"maxRedirectDescription": "Maximale Anzahl von Weiterleitungen, denen gefolgt werden soll. Auf 0 setzen, um Weiterleitungen zu deaktivieren.",
|
||||
"Accepted Status Codes": "Erlaubte HTTP-Statuscodes",
|
||||
"acceptedStatusCodesDescription": "Statuscodes auswählen, die als erfolgreiche Verbindung gelten sollen.",
|
||||
"Save": "Speichern",
|
||||
"Notifications": "Benachrichtigungen",
|
||||
"Not available, please setup.": "Nicht verfügbar, bitte einrichten.",
|
||||
"Setup Notification": "Benachrichtigung einrichten",
|
||||
"Light": "Hell",
|
||||
"Dark": "Dunkel",
|
||||
"Auto": "Auto",
|
||||
"Theme - Heartbeat Bar": "Erscheinungsbild - Zeitleiste",
|
||||
"Normal": "Normal",
|
||||
"Bottom": "Unten",
|
||||
"None": "Keine",
|
||||
"Timezone": "Zeitzone",
|
||||
"Search Engine Visibility": "Sichtbarkeit für Suchmaschinen",
|
||||
"Allow indexing": "Indizierung zulassen",
|
||||
"Discourage search engines from indexing site": "Suchmaschinen darum bitten, die Seite nicht zu indizieren",
|
||||
"Change Password": "Passwort ändern",
|
||||
"Current Password": "Aktuelles Passwort",
|
||||
"New Password": "Neues Passwort",
|
||||
"Repeat New Password": "Neues Passwort wiederholen",
|
||||
"passwordNotMatchMsg": "Passwörter stimmen nicht überein.",
|
||||
"Update Password": "Passwort aktualisieren",
|
||||
"Disable Auth": "Authentifizierung deaktivieren",
|
||||
"Enable Auth": "Authentifizierung aktivieren",
|
||||
"disableauth.message1": "Bist du sicher das du die <strong>Authentifizierung deaktivieren</strong> möchtest?",
|
||||
"disableauth.message2": "Dies ist für Szenarien gedacht, <strong>in denen man eine externe Authentifizierung</strong> vor Uptime Kuma geschaltet hat, wie z.B. Cloudflare Access, Authelia oder andere Authentifizierungsmechanismen.",
|
||||
"Please use this option carefully!": "Bitte mit Vorsicht nutzen!",
|
||||
"Logout": "Ausloggen",
|
||||
"notificationDescription": "Benachrichtigungen müssen einem Monitor zugewiesen werden, damit diese funktionieren.",
|
||||
"Leave": "Verlassen",
|
||||
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
|
||||
"Confirm": "Bestätigen",
|
||||
"Yes": "Ja",
|
||||
"No": "Nein",
|
||||
"Username": "Benutzername",
|
||||
"Password": "Passwort",
|
||||
"Remember me": "Angemeldet bleiben",
|
||||
"Login": "Einloggen",
|
||||
"No Monitors, please": "Keine Monitore, bitte",
|
||||
"add one": "hinzufügen",
|
||||
"Notification Type": "Benachrichtigungsdienst",
|
||||
"Email": "E-Mail",
|
||||
"Test": "Test",
|
||||
"Certificate Info": "Zertifikatsinformation",
|
||||
"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?",
|
||||
"deleteNotificationMsg": "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?",
|
||||
"resolverserverDescription": "Cloudflare ist als der Standardserver festgelegt. Dieser kann jederzeit geändert werden.",
|
||||
"Resolver Server": "Auflösungsserver",
|
||||
"rrtypeDescription": "Wähle den RR-Typ aus, welchen du überwachen möchtest.",
|
||||
"Last Result": "Letztes Ergebnis",
|
||||
"pauseMonitorMsg": "Bist du sicher, dass du den Monitor pausieren möchtest?",
|
||||
"clearEventsMsg": "Bist du sicher, dass du alle Ereignisse für diesen Monitor löschen möchtest?",
|
||||
"clearHeartbeatsMsg": "Bist du sicher, dass du alle Statistiken für diesen Monitor löschen möchtest?",
|
||||
"Clear Data": "Lösche Daten",
|
||||
"Events": "Ereignisse",
|
||||
"Heartbeats": "Statistiken",
|
||||
"confirmClearStatisticsMsg": "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
|
||||
"Create your admin account": "Erstelle dein Admin-Konto",
|
||||
"Repeat Password": "Passwort erneut eingeben",
|
||||
"Resource Record Type": "Ressourcen Record Typ",
|
||||
"Export": "Export",
|
||||
"Import": "Import",
|
||||
"respTime": "Antw.-Zeit (ms)",
|
||||
"notAvailableShort": "N/A",
|
||||
"Default enabled": "Standardmäßig aktiviert",
|
||||
"Apply on all existing monitors": "Auf alle existierenden Monitore anwenden",
|
||||
"enableDefaultNotificationDescription": "Für jeden neuen Monitor wird diese Benachrichtigung standardmäßig aktiviert. Die Benachrichtigung kann weiterhin für jeden Monitor separat deaktiviert werden.",
|
||||
"Create": "Erstellen",
|
||||
"Auto Get": "Auto Get",
|
||||
"backupDescription": "Es können alle Monitore und Benachrichtigungen in einer JSON-Datei gesichert werden.",
|
||||
"backupDescription2": "PS: Verlaufs- und Ereignisdaten sind nicht enthalten.",
|
||||
"backupDescription3": "Sensible Daten wie Benachrichtigungstoken sind in der Exportdatei enthalten, bitte bewahre sie sorgfältig auf.",
|
||||
"alertNoFile": "Bitte wähle eine Datei zum Importieren aus.",
|
||||
"alertWrongFileType": "Bitte wähle eine JSON-Datei aus.",
|
||||
"Clear all statistics": "Lösche alle Statistiken",
|
||||
"importHandleDescription": "Wähle 'Vorhandene überspringen' aus, wenn jeder Monitor oder jede Benachrichtigung mit demselben Namen übersprungen werden soll. 'Überschreiben' löscht jeden vorhandenen Monitor sowie Benachrichtigungen.",
|
||||
"Skip existing": "Vorhandene überspringen",
|
||||
"Overwrite": "Überschreiben",
|
||||
"Options": "Optionen",
|
||||
"confirmImportMsg": "Möchtest du das Backup wirklich importieren? Bitte stelle sicher, dass die richtige Import-Option ausgewählt ist.",
|
||||
"Keep both": "Beide behalten",
|
||||
"twoFAVerifyLabel": "Bitte trage deinen Token ein, um zu verifizieren, dass 2FA funktioniert",
|
||||
"Verify Token": "Token verifizieren",
|
||||
"Setup 2FA": "2FA einrichten",
|
||||
"Enable 2FA": "2FA aktivieren",
|
||||
"Disable 2FA": "2FA deaktivieren",
|
||||
"2FA Settings": "2FA-Einstellungen",
|
||||
"confirmEnableTwoFAMsg": "Bist du sicher, dass du 2FA aktivieren möchtest?",
|
||||
"confirmDisableTwoFAMsg": "Bist du sicher, dass du 2FA deaktivieren möchtest?",
|
||||
"tokenValidSettingsMsg": "Token gültig! Du kannst jetzt die 2FA-Einstellungen speichern.",
|
||||
"Two Factor Authentication": "Zwei-Faktor-Authentifizierung",
|
||||
"Active": "Aktiv",
|
||||
"Inactive": "Inaktiv",
|
||||
"Token": "Token",
|
||||
"Show URI": "URI anzeigen",
|
||||
"Tags": "Tags",
|
||||
"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 value already exist.": "Ein Tag mit diesem Wert existiert bereits.",
|
||||
"color": "Farbe",
|
||||
"value (optional)": "Wert (optional)",
|
||||
"Gray": "Grau",
|
||||
"Red": "Rot",
|
||||
"Orange": "Orange",
|
||||
"Green": "Grün",
|
||||
"Blue": "Blau",
|
||||
"Indigo": "Indigo",
|
||||
"Purple": "Lila",
|
||||
"Pink": "Pink",
|
||||
"Search...": "Suchen…",
|
||||
"Heartbeat Retry Interval": "Überprüfungsintervall",
|
||||
"Resend Notification if Down X times consequently": "Benachrichtigung erneut senden, wenn Inaktiv X mal hintereinander",
|
||||
"retryCheckEverySecond": "Alle {0} Sekunden neu versuchen",
|
||||
"resendEveryXTimes": "Erneut versenden alle {0} mal",
|
||||
"resendDisabled": "Erneut versenden deaktiviert",
|
||||
"Import Backup": "Backup importieren",
|
||||
"Export Backup": "Backup exportieren",
|
||||
"Avg. Ping": "Durchschn. Ping",
|
||||
"Avg. Response": "Durchschn. Antwort",
|
||||
"Entry Page": "Einstiegsseite",
|
||||
"statusPageNothing": "Noch ist hier nichts. Bitte füge eine Gruppe oder einen Monitor hinzu.",
|
||||
"No Services": "Keine Dienste",
|
||||
"All Systems Operational": "Alle Systeme betriebsbereit",
|
||||
"Partially Degraded Service": "Teilweise beeinträchtigter Dienst",
|
||||
"Degraded Service": "Eingeschränkter Dienst",
|
||||
"Add Group": "Gruppe hinzufügen",
|
||||
"Add a monitor": "Monitor hinzufügen",
|
||||
"Edit Status Page": "Statusseite bearbeiten",
|
||||
"Go to Dashboard": "Gehe zum Dashboard",
|
||||
"Status Page": "Status-Seite",
|
||||
"Status Pages": "Status-Seiten",
|
||||
"telegram": "Telegram",
|
||||
"webhook": "Webhook",
|
||||
"smtp": "E-Mail (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 (Unterstützung für 50+ Benachrichtigungsdienste)",
|
||||
"GoogleChat": "Google Chat (nur Google Workspace)",
|
||||
"pushbullet": "Pushbullet",
|
||||
"line": "Line Messenger",
|
||||
"mattermost": "Mattermost",
|
||||
"Primary Base URL": "Primäre Basis-URL",
|
||||
"Push URL": "Push URL",
|
||||
"needPushEvery": "Du solltest diese URL alle {0} Sekunden aufrufen",
|
||||
"pushOptionalParams": "Optionale Parameter: {0}",
|
||||
"defaultNotificationName": "Mein {notification} Alarm ({number})",
|
||||
"here": "hier",
|
||||
"Required": "Erforderlich",
|
||||
"Bot Token": "Bot Token",
|
||||
"wayToGetTelegramToken": "Hier kannst du einen Token erhalten {0}.",
|
||||
"Chat ID": "Chat ID",
|
||||
"supportTelegramChatID": "Unterstützt Direkt Chat / Gruppe / Kanal Chat-ID's",
|
||||
"wayToGetTelegramChatID": "Du kannst die Chat-ID erhalten, indem du eine Nachricht an den Bot sendest und zu dieser URL gehst, um die chat_id: zu sehen.",
|
||||
"YOUR BOT TOKEN HERE": "HIER DEIN BOT TOKEN",
|
||||
"chatIDNotFound": "Chat-ID wurde nicht gefunden: bitte sende zuerst eine Nachricht an diesen Bot",
|
||||
"Post URL": "Post URL",
|
||||
"Content Type": "Content Type",
|
||||
"webhookJsonDesc": "{0} ist gut für alle modernen HTTP-Server, wie z.B. Express.js, geeignet",
|
||||
"webhookFormDataDesc": "{multipart} ist gut für PHP. Das JSON muss mit {decodeFunction} verarbeitet werden",
|
||||
"secureOptionNone": "Keine / STARTTLS (25, 587)",
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
"Ignore TLS Error": "TLS-Fehler ignorieren",
|
||||
"From Email": "Absender E-Mail",
|
||||
"emailCustomSubject": "Benutzerdefinierter Betreff",
|
||||
"To Email": "Empfänger E-Mail",
|
||||
"smtpCC": "CC",
|
||||
"smtpBCC": "BCC",
|
||||
"Discord Webhook URL": "Discord Webhook URL",
|
||||
"wayToGetDiscordURL": "Du kannst diese erhalten, indem du zu den Servereinstellungen gehst -> Integrationen -> Neuer Webhook",
|
||||
"Bot Display Name": "Bot-Anzeigename",
|
||||
"Prefix Custom Message": "Benutzerdefinierter Nachrichten Präfix",
|
||||
"Hello @everyone is...": "Hallo {'@'}everyone ist…",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"wayToGetTeamsURL": "Wie eine Webhook-URL erstellt werden kann, erfährst du {0}.",
|
||||
"Number": "Nummer",
|
||||
"Recipients": "Empfänger",
|
||||
"needSignalAPI": "Es wird ein Signal Client mit REST-API benötigt.",
|
||||
"wayToCheckSignalURL": "Du kannst diese URL aufrufen, um zu sehen, wie du eine einrichtest:",
|
||||
"signalImportant": "WICHTIG: Gruppen und Nummern können in Empfängern nicht gemischt werden!",
|
||||
"Application Token": "Anwendungs Token",
|
||||
"Server URL": "Server URL",
|
||||
"Priority": "Priorität",
|
||||
"Icon Emoji": "Icon Emoji",
|
||||
"Channel Name": "Kanalname",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||
"aboutWebhooks": "Weitere Informationen zu Webhooks auf: {0}",
|
||||
"aboutChannelName": "Gebe den Kanalnamen ein in {0} Feld Kanalname, falls du den Webhook-Kanal umgehen möchtest. Ex: #other-channel",
|
||||
"aboutKumaURL": "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird standardmäßig die GitHub Projekt Seite verwendet.",
|
||||
"emojiCheatSheet": "Emoji Cheat Sheet: {0}",
|
||||
"User Key": "Benutzerschlüssel",
|
||||
"Device": "Gerät",
|
||||
"Message Title": "Nachrichtentitel",
|
||||
"Notification Sound": "Benachrichtigungston",
|
||||
"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.",
|
||||
"pushoverDesc2": "Fülle das Geräte Feld aus, wenn du Benachrichtigungen an verschiedene Geräte senden möchtest.",
|
||||
"SMS Type": "SMS Typ",
|
||||
"octopushTypePremium": "Premium (Schnell - zur Benachrichtigung empfohlen)",
|
||||
"octopushTypeLowCost": "Kostengünstig (Langsam - manchmal vom Betreiber gesperrt)",
|
||||
"checkPrice": "Prüfe {0} Preise:",
|
||||
"octopushLegacyHint": "Verwendest du die Legacy-Version von Octopush (2011-2020) oder die neue Version?",
|
||||
"Check octopush prices": "Vergleiche die Oktopush Preise {0}.",
|
||||
"octopushPhoneNumber": "Telefonnummer (Internationales Format, z.B : +49612345678) ",
|
||||
"octopushSMSSender": "Name des SMS-Absenders : 3-11 alphanumerische Zeichen und Leerzeichen (a-zA-Z0-9)",
|
||||
"LunaSea Device ID": "LunaSea Geräte ID",
|
||||
"Apprise URL": "Apprise URL",
|
||||
"Example:": "Beispiel: {0}",
|
||||
"Read more:": "Weiterlesen: {0}",
|
||||
"Status:": "Status: {0}",
|
||||
"Read more": "Weiterlesen",
|
||||
"appriseInstalled": "Apprise ist installiert.",
|
||||
"appriseNotInstalled": "Apprise ist nicht installiert. {0}",
|
||||
"Access Token": "Access Token",
|
||||
"Channel access token": "Channel access token",
|
||||
"Line Developers Console": "Line Developers Console",
|
||||
"lineDevConsoleTo": "Line Developers Console - {0}",
|
||||
"Basic Settings": "Basic Settings",
|
||||
"User ID": "User ID",
|
||||
"Messaging API": "Messaging API",
|
||||
"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",
|
||||
"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 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",
|
||||
"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. 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.",
|
||||
"promosmsTypeSpeed": "SMS SPEED - Höchste Priorität im System. Sehr schnell und zuverlässig, aber teuer (Ungefähr das doppelte von SMS FULL).",
|
||||
"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",
|
||||
"Feishu WebHookUrl": "Feishu Webhook URL",
|
||||
"matrixHomeserverURL": "Heimserver URL (mit http(s):// und optionalen Ports)",
|
||||
"Internal Room Id": "Interne Raum-ID",
|
||||
"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 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",
|
||||
"Body": "Body",
|
||||
"Headers": "Headers",
|
||||
"PushUrl": "Push URL",
|
||||
"HeadersInvalidFormat": "Der Header ist kein gültiges JSON: ",
|
||||
"BodyInvalidFormat": "Der Body ist kein gültiges JSON: ",
|
||||
"Monitor History": "Monitor Verlauf",
|
||||
"clearDataOlderThan": "Bewahre die Monitor-Verlaufsdaten für {0} Tage auf.",
|
||||
"PasswordsDoNotMatch": "Passwörter stimmen nicht überein.",
|
||||
"records": "Einträge",
|
||||
"One record": "Ein Eintrag",
|
||||
"steamApiKeyDescription": "Um einen Steam Game Server zu überwachen, wird ein Steam Web-API-Schlüssel benötigt. Dieser kann hier registriert werden: ",
|
||||
"Current User": "Aktueller Benutzer",
|
||||
"recent": "Letzte",
|
||||
"Done": "Fertig",
|
||||
"Info": "Info",
|
||||
"Security": "Sicherheit",
|
||||
"Steam API Key": "Steam API Key",
|
||||
"Shrink Database": "Datenbank verkleinern",
|
||||
"Pick a RR-Type...": "Wähle ein RR-Typ aus…",
|
||||
"Pick Accepted Status Codes...": "Wähle akzeptierte Statuscodes aus…",
|
||||
"Default": "Standard",
|
||||
"HTTP Options": "HTTP Optionen",
|
||||
"Create Incident": "Vorfall erstellen",
|
||||
"Title": "Titel",
|
||||
"Content": "Inhalt",
|
||||
"Style": "Stil",
|
||||
"info": "info",
|
||||
"warning": "warnung",
|
||||
"danger": "gefahr",
|
||||
"primary": "primär",
|
||||
"light": "hell",
|
||||
"dark": "dunkel",
|
||||
"Post": "Eintrag",
|
||||
"Please input title and content": "Bitte Titel und Inhalt eingeben",
|
||||
"Created": "Erstellt",
|
||||
"Last Updated": "Zuletzt aktualisiert",
|
||||
"Unpin": "Loslösen",
|
||||
"Switch to Light Theme": "Zu hellem Thema wechseln",
|
||||
"Switch to Dark Theme": "Zum dunklen Thema wechseln",
|
||||
"Show Tags": "Tags anzeigen",
|
||||
"Hide Tags": "Tags ausblenden",
|
||||
"Description": "Beschreibung",
|
||||
"No monitors available.": "Keine Monitore verfügbar.",
|
||||
"Add one": "Hinzufügen",
|
||||
"No Monitors": "Keine Monitore",
|
||||
"Untitled Group": "Gruppe ohne Titel",
|
||||
"Services": "Dienste",
|
||||
"Discard": "Verwerfen",
|
||||
"Cancel": "Abbrechen",
|
||||
"Powered by": "Powered by",
|
||||
"shrinkDatabaseDescription": "Löse VACUUM für die SQLite Datenbank aus. Wenn die Datenbank nach 1.10.0 erstellt wurde, ist AUTO_VACUUM bereits aktiviert und diese Aktion ist nicht erforderlich.",
|
||||
"serwersms": "SerwerSMS.pl",
|
||||
"serwersmsAPIUser": "API Benutzername (inkl. webapi_ prefix)",
|
||||
"serwersmsAPIPassword": "API Passwort",
|
||||
"serwersmsPhoneNumber": "Telefonnummer",
|
||||
"serwersmsSenderName": "Name des SMS-Absenders (über Kundenportal registriert)",
|
||||
"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)",
|
||||
"PushByTechulus": "Push by Techulus",
|
||||
"gorush": "Gorush",
|
||||
"alerta": "Alerta",
|
||||
"alertaApiEndpoint": "API Endpunkt",
|
||||
"alertaEnvironment": "Umgebung",
|
||||
"alertaApiKey": "API Schlüssel",
|
||||
"alertaAlertState": "Alarmstatus",
|
||||
"alertaRecoverState": "Wiederherstellungsstatus",
|
||||
"deleteStatusPageMsg": "Bist du sicher, dass du diese Status-Seite löschen willst?",
|
||||
"Proxies": "Proxies",
|
||||
"default": "Standard",
|
||||
"enabled": "Aktiviert",
|
||||
"setAsDefault": "Als Standard setzen",
|
||||
"deleteProxyMsg": "Bist du sicher, dass du diesen Proxy für alle Monitore löschen willst?",
|
||||
"proxyDescription": "Proxies müssen einem Monitor zugewiesen werden, um zu funktionieren.",
|
||||
"enableProxyDescription": "Dieser Proxy wird keinen Effekt auf Monitor-Anfragen haben, bis er aktiviert ist. Du kannst ihn temporär von allen Monitoren nach Aktivierungsstatus deaktivieren.",
|
||||
"setAsDefaultProxyDescription": "Dieser Proxy wird standardmäßig für alle neuen Monitore aktiviert sein. Du kannst den Proxy immer noch für jeden Monitor einzeln deaktivieren.",
|
||||
"Certificate Chain": "Zertifikatskette",
|
||||
"Valid": "Gültig",
|
||||
"Invalid": "Ungültig",
|
||||
"AccessKeyId": "AccessKey ID",
|
||||
"SecretAccessKey": "AccessKey Secret",
|
||||
"PhoneNumbers": "Telefonnummern",
|
||||
"TemplateCode": "Vorlagencode",
|
||||
"SignName": "Signaturname",
|
||||
"Sms template must contain parameters: ": "SMS Vorlage muss folgende Parameter enthalten: ",
|
||||
"Bark Endpoint": "Bark Endpunkt",
|
||||
"WebHookUrl": "Webhook URL",
|
||||
"SecretKey": "Geheimer Schlüssel",
|
||||
"For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden",
|
||||
"Device Token": "Gerätetoken",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "Hoch",
|
||||
"Retry": "Wiederholungen",
|
||||
"Topic": "Thema",
|
||||
"WeCom Bot Key": "WeCom Bot Schlüssel",
|
||||
"Setup Proxy": "Proxy einrichten",
|
||||
"Proxy Protocol": "Proxy Protokoll",
|
||||
"Proxy Server": "Proxy-Server",
|
||||
"Proxy server has authentication": "Proxy-Server hat Authentifizierung",
|
||||
"User": "Benutzer",
|
||||
"Installed": "Installiert",
|
||||
"Not installed": "Nicht installiert",
|
||||
"Running": "Läuft",
|
||||
"Not running": "Gestoppt",
|
||||
"Remove Token": "Token entfernen",
|
||||
"Start": "Start",
|
||||
"Stop": "Stop",
|
||||
"Uptime Kuma": "Uptime Kuma",
|
||||
"Add New Status Page": "Neue Status-Seite hinzufügen",
|
||||
"Slug": "Slug",
|
||||
"Accept characters:": "Akzeptierte Zeichen:",
|
||||
"startOrEndWithOnly": "Nur mit {0} anfangen und enden",
|
||||
"No consecutive dashes": "Keine aufeinanderfolgenden Bindestriche",
|
||||
"Next": "Weiter",
|
||||
"The slug is already taken. Please choose another slug.": "Der Slug ist bereits in Verwendung. Bitte wähle einen anderen.",
|
||||
"No Proxy": "Kein Proxy",
|
||||
"Authentication": "Authentifizierung",
|
||||
"HTTP Basic Auth": "HTTP Basisauthentifizierung",
|
||||
"New Status Page": "Neue Status-Seite",
|
||||
"Page Not Found": "Seite nicht gefunden",
|
||||
"Reverse Proxy": "Reverse Proxy",
|
||||
"Backup": "Sicherung",
|
||||
"About": "Über",
|
||||
"wayToGetCloudflaredURL": "(Lade cloudflared von {0} herunter)",
|
||||
"cloudflareWebsite": "Cloudflare Website",
|
||||
"Message:": "Nachricht:",
|
||||
"Don't know how to get the token? Please read the guide:": "Du weißt nicht, wie man den Token bekommt? Lies die Anleitung dazu:",
|
||||
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Die aktuelle Verbindung kann unterbrochen werden, wenn du aktuell über Cloudflare Tunnel verbunden bist. Bist du sicher, dass du es stoppen willst? Gib zur Bestätigung dein aktuelles Passwort ein.",
|
||||
"Other Software": "Andere Software",
|
||||
"For example: nginx, Apache and Traefik.": "Zum Beispiel: nginx, Apache und Traefik.",
|
||||
"Please read": "Bitte lesen",
|
||||
"Subject:": "Betreff:",
|
||||
"Valid To:": "Gültig bis:",
|
||||
"Days Remaining:": "Tage verbleibend:",
|
||||
"Issuer:": "Aussteller:",
|
||||
"Fingerprint:": "Fingerabdruck:",
|
||||
"No status pages": "Keine Status-Seiten",
|
||||
"Domain Name Expiry Notification": "Benachrichtigung bei Ablauf des Domainnamens",
|
||||
"Customize": "Anpassen",
|
||||
"Custom Footer": "Eigener Footer",
|
||||
"Custom CSS": "Eigenes CSS",
|
||||
"Footer Text": "Fußzeile",
|
||||
"Show Powered By": "Zeige 'Powered By'",
|
||||
"Date Created": "Erstellt am",
|
||||
"Domain Names": "Domainnamen",
|
||||
"signedInDisp": "Angemeldet als {0}",
|
||||
"signedInDispDisabled": "Authentifizierung deaktiviert.",
|
||||
"dnsPortDescription": "DNS server port. Standard ist 53. Der Port kann jederzeit geändert werden.",
|
||||
"topic": "Thema",
|
||||
"topicExplanation": "MQTT Thema für den monitor",
|
||||
"successMessage": "Erfolgsnachricht",
|
||||
"successMessageExplanation": "MQTT Nachricht, die als Erfolg angesehen wird",
|
||||
"error": "Fehler",
|
||||
"critical": "kritisch",
|
||||
"wayToGetPagerDutyKey": "Dieser kann unter Service -> Service Directory -> (Select a service) -> Integrations -> Add integration gefunden werden. Hier muss nach \"Events API V2\" gesucht werden. Mehr informationen {0}",
|
||||
"Integration Key": "Schlüssel der Integration",
|
||||
"Integration URL": "URL der Integration",
|
||||
"Auto resolve or acknowledged": "Automatisch lösen oder bestätigen",
|
||||
"do nothing": "nichts tun",
|
||||
"auto acknowledged": "automatisch bestätigen",
|
||||
"auto resolve": "automatisch lösen",
|
||||
"Bark Group": "Bark Gruppe",
|
||||
"Bark Sound": "Bark Klang",
|
||||
"HTTP Headers": "HTTP Kopfzeilen",
|
||||
"Trust Proxy": "Vertrauenswürdiger Proxy",
|
||||
"Proxy": "Proxy",
|
||||
"HomeAssistant": "Home Assistant",
|
||||
"onebotHttpAddress": "OneBot HTTP Adresse",
|
||||
"onebotMessageType": "OneBot Nachrichtentyp",
|
||||
"onebotGroupMessage": "Gruppe",
|
||||
"onebotPrivateMessage": "Privat",
|
||||
"onebotUserOrGroupId": "Gruppe/Nutzer ID",
|
||||
"onebotSafetyTips": "Zur Sicherheit ein access token setzen",
|
||||
"PushDeer Key": "PushDeer Schlüssel",
|
||||
"RadiusSecret": "Radius Geheimnis",
|
||||
"RadiusSecretDescription": "Geteiltes Geheimnis zwischen Client und Server",
|
||||
"RadiusCalledStationId": "ID der angesprochenen Station",
|
||||
"RadiusCalledStationIdDescription": "Identifikation des angesprochenen Geräts",
|
||||
"RadiusCallingStationId": "ID der ansprechenden Station",
|
||||
"RadiusCallingStationIdDescription": "Identifikation des ansprechenden Geräts",
|
||||
"Certificate Expiry Notification": "Benachrichtigung ablaufendes Zertifikat",
|
||||
"API Username": "API Nutzername",
|
||||
"API Key": "API Schlüssel",
|
||||
"Recipient Number": "Empfängernummer",
|
||||
"From Name/Number": "Von Name/Nummer",
|
||||
"Leave blank to use a shared sender number.": "Leer lassen um eine geteilte Absendernummer zu nutzen.",
|
||||
"Octopush API Version": "Octopush API Version",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"endpoint": "Endpunkt",
|
||||
"octopushAPIKey": "\"API Schlüssel\" der HTTP API Zugangsdaten im control panel",
|
||||
"octopushLogin": "\"Login\" der HTTP API Zugangsdaten im control panel",
|
||||
"promosmsLogin": "API Login Name",
|
||||
"promosmsPassword": "API Password",
|
||||
"pushoversounds pushover": "Pushover (Standard)",
|
||||
"pushoversounds bike": "Fahrrad",
|
||||
"pushoversounds bugle": "Signalhorn",
|
||||
"pushoversounds cashregister": "Kasse",
|
||||
"pushoversounds classical": "Klassisch",
|
||||
"pushoversounds cosmic": "Kosmisch",
|
||||
"pushoversounds falling": "Abfallend",
|
||||
"pushoversounds gamelan": "Gamelan",
|
||||
"pushoversounds incoming": "Eingang",
|
||||
"pushoversounds intermission": "Pause",
|
||||
"pushoversounds magic": "Magisch",
|
||||
"pushoversounds mechanical": "Mechanisch",
|
||||
"pushoversounds pianobar": "Piano Bar",
|
||||
"pushoversounds siren": "Sirene",
|
||||
"pushoversounds spacealarm": "Space Alarm",
|
||||
"pushoversounds tugboat": "Schlepper Horn",
|
||||
"pushoversounds alien": "Außerirdisch (lang)",
|
||||
"pushoversounds climb": "Ansteigende (lang)",
|
||||
"pushoversounds persistent": "Hartnäckig (lang)",
|
||||
"pushoversounds echo": "Pushover Echo (lang)",
|
||||
"pushoversounds updown": "Auf und Ab (lang)",
|
||||
"pushoversounds vibrate": "Nur vibrieren",
|
||||
"pushoversounds none": "Nichts (Stille)",
|
||||
"pushyAPIKey": "Geheimer API Schlüssel",
|
||||
"pushyToken": "Gerätetoken",
|
||||
"Show update if available": "Verfügbare Updates anzeigen",
|
||||
"Also check beta release": "Auch nach Beta Versionen schauen",
|
||||
"Using a Reverse Proxy?": "Wird ein Reverse Proxy genutzt?",
|
||||
"Check how to config it for WebSocket": "Prüfen, wie er für die Nutzung mit WebSocket konfiguriert wird",
|
||||
"Steam Game Server": "Steam Game Server",
|
||||
"Most likely causes:": "Wahrscheinliche Ursachen:",
|
||||
"The resource is no longer available.": "Die Quelle ist nicht mehr verfügbar.",
|
||||
"There might be a typing error in the address.": "Es gibt einen Tippfehler in der Adresse.",
|
||||
"What you can try:": "Was du versuchen kannst:",
|
||||
"Retype the address.": "Schreibe die Adresse erneut.",
|
||||
"Go back to the previous page.": "Gehe zur vorigen Seite.",
|
||||
"Coming Soon": "Kommt bald",
|
||||
"wayToGetClickSendSMSToken": "Du kannst einen API Nutzernamen und Schlüssel unter {0} erhalten.",
|
||||
"Connection String": "Verbindungstext",
|
||||
"Query": "Abfrage",
|
||||
"settingsCertificateExpiry": "TLS Zertifikatsablauf",
|
||||
"certificationExpiryDescription": "HTTPS Monitore senden eine Benachrichtigung, wenn das Zertifikat abläuft in:",
|
||||
"Setup Docker Host": "Docker Host einrichten",
|
||||
"Connection Type": "Verbindungstyp",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
"deleteDockerHostMsg": "Bist du sicher diesen docker host für alle Monitore zu löschen?",
|
||||
"socket": "Socket",
|
||||
"tcp": "TCP / HTTP",
|
||||
"Docker Container": "Docker Container",
|
||||
"Container Name / ID": "Container Name / ID",
|
||||
"Docker Host": "Docker Host",
|
||||
"Docker Hosts": "Docker Hosts",
|
||||
"ntfy Topic": "ntfy Thema",
|
||||
"Domain": "Domain",
|
||||
"Workstation": "Workstation",
|
||||
"disableCloudflaredNoAuthMsg": "Du bist im nicht-authentifizieren Modus, ein Passwort wird nicht benötigt.",
|
||||
"trustProxyDescription": "Vertraue 'X-Forwarded-*' headern. Wenn man die richtige client IP haben möchte und Uptime Kuma hinter einem Proxy wie Nginx or Apache läuft, wollte dies aktiviert werden.",
|
||||
"wayToGetLineNotifyToken": "Du kannst hier ein Token erhalten: {0}",
|
||||
"Examples": "Beispiele",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "Lange gültiges Access Token",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Lange gültige Access Token können durch klicken auf den Profilnamen (unten links) und dann einen Klick auf Create Token am Ende erstellt werden. ",
|
||||
"Notification Service": "Benachrichtigungsdienst",
|
||||
"default: notify all devices": "standard: Alle Geräte benachrichtigen",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Eine Liste der Benachrichtigungsdienste kann im Home Assistant unter \"Developer Tools > Services\" gefunden werden, wnen man nach \"notification\" sucht um den Geräte-/Telefonnamen zu finden.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Automatisierungen können optional im Home Assistant ausgelöst werden:",
|
||||
"Trigger type:": "Auslöser:",
|
||||
"Event type:": "Ereignistyp:",
|
||||
"Event data:": "Ereignis daten:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.",
|
||||
"Frontend Version": "Frontend Version",
|
||||
"Frontend Version do not match backend version!": "Die Frontend Version stimmt nicht mit der backend version überein!",
|
||||
"Maintenance": "Wartung",
|
||||
"statusMaintenance": "Wartung",
|
||||
"Schedule maintenance": "Geplante Wartung",
|
||||
"Affected Monitors": "Betroffene Monitore",
|
||||
"Pick Affected Monitors...": "Wähle betroffene Monitore…",
|
||||
"Start of maintenance": "Beginn der Wartung",
|
||||
"All Status Pages": "Alle Status Seiten",
|
||||
"Select status pages...": "Statusseiten auswählen…",
|
||||
"recurringIntervalMessage": "Einmal pro Tag ausgeführt | Wird alle {0} Tage ausgführt",
|
||||
"affectedMonitorsDescription": "Wähle Monitore aus, die von der aktuellen Wartung betroffen sind",
|
||||
"affectedStatusPages": "Diese Wartungsmeldung auf ausgewählten Statusseiten anzeigen",
|
||||
"atLeastOneMonitor": "Wähle mindestens einen Monitor",
|
||||
"deleteMaintenanceMsg": "Möchtest du diese Wartung löschen?",
|
||||
"Base URL": "Basis URL",
|
||||
"goAlertInfo": "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt. {0}",
|
||||
"goAlertIntegrationKeyInfo": "Bekommt einen generischen API Schlüssel in folgenden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise entspricht dies dem Wert des Token aus der URL.",
|
||||
"goAlert": "GoAlert",
|
||||
"backupOutdatedWarning": "Veraltet: Da viele Funktionen hinzugefügt wurden und diese Sicherungsfunktion nicht mehr gepflegt wird, kann sie keine vollständige Sicherung erstellen oder wiederherstellen.",
|
||||
"backupRecommend": "Bitte sichere stattdessen das Volume oder den Datenordner (./data/) direkt.",
|
||||
"Optional": "Optional",
|
||||
"squadcast": "Squadcast",
|
||||
"SendKey": "SendKey",
|
||||
"SMSManager API Docs": "SMSManager API Dokumente",
|
||||
"Gateway Type": "Gateway Type",
|
||||
"SMSManager": "SMSManager",
|
||||
"You can divide numbers with": "Du kannst Zahlen teilen mit",
|
||||
"or": "oder",
|
||||
"recurringInterval": "Intervall",
|
||||
"Recurring": "Wiederkehrend",
|
||||
"Single Maintenance Window": "Einzigartiges Wartungsfenster",
|
||||
"Maintenance Time Window of a Day": "Zeitfenster für die Wartung",
|
||||
"Effective Date Range": "Bereich der Wirksamkeitsdaten",
|
||||
"strategyManual": "Aktiv/Inaktiv Manuell",
|
||||
"warningTimezone": "Es wird die Zeitzone des Servers verwendet",
|
||||
"weekdayShortMon": "Mo",
|
||||
"weekdayShortTue": "Di",
|
||||
"weekdayShortWed": "Mi",
|
||||
"weekdayShortThu": "Do",
|
||||
"weekdayShortFri": "Fr",
|
||||
"weekdayShortSat": "Sa",
|
||||
"weekdayShortSun": "So",
|
||||
"dayOfWeek": "Tag der Woche",
|
||||
"dayOfMonth": "Tag im Monat",
|
||||
"lastDay": "Letzter Tag",
|
||||
"lastDay1": "Letzter Tag im Monat",
|
||||
"lastDay2": "Vorletzer Tag im Monat",
|
||||
"lastDay3": "3. letzter Tag im Monat",
|
||||
"lastDay4": "4. letzter Tag im Monat",
|
||||
"No Maintenance": "Keine Wartung",
|
||||
"Schedule Maintenance": "Wartung planen",
|
||||
"pauseMaintenanceMsg": "Möchtest du wirklich pausieren?",
|
||||
"maintenanceStatus-under-maintenance": "Unter Wartung",
|
||||
"maintenanceStatus-inactive": "Inaktiv",
|
||||
"maintenanceStatus-scheduled": "Geplant",
|
||||
"maintenanceStatus-ended": "Ende",
|
||||
"maintenanceStatus-unknown": "Unbekannt",
|
||||
"Display Timezone": "Zeitzone anzeigen",
|
||||
"Server Timezone": "Server Zeitzone",
|
||||
"Date and Time": "Datum und Zeit",
|
||||
"DateTime Range": "Datums- und Zeitbereich",
|
||||
"Strategy": "Strategie",
|
||||
"statusPageMaintenanceEndDate": "Ende",
|
||||
"Help": "Hilfe",
|
||||
"Game": "Spiel",
|
||||
"Custom": "Benutzerdefiniert",
|
||||
"Enable DNS Cache": "DNS Cache aktivieren",
|
||||
"Enable": "Aktivieren",
|
||||
"Disable": "Deaktivieren"
|
||||
}
|
587
src/lang/el-GR.json
Normal file
587
src/lang/el-GR.json
Normal file
@@ -0,0 +1,587 @@
|
||||
{
|
||||
"languageName": "Ελληνικά",
|
||||
"checkEverySecond": "Έλεγχος κάθε {0} δευτερόλεπτα",
|
||||
"retryCheckEverySecond": "Επανάληψη κάθε {0} δευτερόλεπτα",
|
||||
"resendEveryXTimes": "Επανάληψη αποστολής ειδοποίησης κάθε {0} φορές",
|
||||
"resendDisabled": "Η επανάληψη αποστολής ειδοποίησης είναι απενεργοποιημένη",
|
||||
"retriesDescription": "Μέγιστες επαναλήψεις προτού η υπηρεσία επισημανθεί ως κατω και σταλεί μια ειδοποίηση",
|
||||
"ignoreTLSError": "Παράβλεψη σφάλματος TLS/SSL για ιστότοπους HTTPS",
|
||||
"upsideDownModeDescription": "Αναποδογυρίστε την κατάσταση. Εάν η υπηρεσία είναι προσβάσιμη, είναι ΚΑΤΩ.",
|
||||
"maxRedirectDescription": "Μέγιστος αριθμός redirect που θα ακολουθήσουν. Ρυθμίστε το 0 για να απενεργοποιήσετε τα redirect.",
|
||||
"acceptedStatusCodesDescription": "Επιλέξτε κωδικούς κατάστασης που θεωρούνται επιτυχή.",
|
||||
"passwordNotMatchMsg": "Ο κωδικός δεν ταιριάζει.",
|
||||
"notificationDescription": "Οι ειδοποιήσεις πρέπει να εκχωρηθούν σε μια παρακολούθηση για να λειτουργήσουν.",
|
||||
"keywordDescription": "Αναζήτηση λέξης-κλειδιού σε απλή απόκριση HTML ή JSON. Η αναζήτηση είναι διάκριση πεζών-κεφαλαίων.",
|
||||
"pauseDashboardHome": "Παύση",
|
||||
"deleteMonitorMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την παρακολούθηση;",
|
||||
"deleteNotificationMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την ειδοποίηση για όλες τις παρακολούθησης?",
|
||||
"dnsPortDescription": "Θύρα διακομιστή DNS. Προεπιλογή σε 53. Μπορείτε να αλλάξετε τη θύρα ανά πάσα στιγμή.",
|
||||
"resolverserverDescription": "Το Cloudflare είναι ο προεπιλεγμένος διακομιστής. Μπορείτε να αλλάξετε τον διακομιστή επίλυσης ανά πάσα στιγμήhe default server. You can change the resolver server anytime.",
|
||||
"rrtypeDescription": "Επιλέξτε τον τύπο RR που θέλετε να παρακολουθήσετε",
|
||||
"pauseMonitorMsg": "Είστε βέβαιοι ότι θέλετε να κάνετε παύση;",
|
||||
"enableDefaultNotificationDescription": "Αυτή η ειδοποίηση θα είναι ενεργοποιημένη από προεπιλογή για νέες παρακολούθησης. Μπορείτε ακόμα να απενεργοποιήσετε την ειδοποίηση ξεχωριστά για κάθε παρακολούθηση.",
|
||||
"clearEventsMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε όλα τα συμβάντα για αυτήν την παρακολούθηση;",
|
||||
"clearHeartbeatsMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε όλους τους καρδιακούς παλμούς για αυτήν την παρακολούθηση;",
|
||||
"confirmClearStatisticsMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε ΟΛΑ τα στατιστικά στοιχεία;?",
|
||||
"importHandleDescription": "Επιλέξτε «Παράλειψη υπάρχοντος» εάν θέλετε να παραλείψετε κάθε παρακολούθηση ή ειδοποίηση με το ίδιο όνομα. Το 'Overwrite' θα διαγράψει κάθε υπάρχουσα παρακολούθηση και ειδοποίηση.",
|
||||
"confirmImportMsg": "Είστε βέβαιοι ότι θέλετε να εισαγάγετε το αντίγραφο ασφαλείας; Επαληθεύστε ότι έχετε επιλέξει τη σωστή επιλογή.",
|
||||
"twoFAVerifyLabel": "Εισαγάγετε το 2FA κωδικό για να επαληθεύσετε: ",
|
||||
"tokenValidSettingsMsg": "Ο κωδικός 2FA είναι έγκυρο! Τώρα μπορείτε να αποθηκεύσετε τις ρυθμίσεις 2FA",
|
||||
"confirmEnableTwoFAMsg": "Είστε βέβαιοι ότι θέλετε να ενεργοποιήσετε το 2FA;",
|
||||
"confirmDisableTwoFAMsg": "Είστε βέβαιοι ότι θέλετε να απενεργοποιήσετε το 2FA;",
|
||||
"Settings": "Ρυθμίσεις",
|
||||
"Dashboard": "Πίνακας",
|
||||
"New Update": "Νέα αναβάθμιση",
|
||||
"Language": "Γλώσσα",
|
||||
"Appearance": "Εμφάνιση",
|
||||
"Theme": "Θέμα",
|
||||
"General": "Γενικά",
|
||||
"Primary Base URL": "Κύρια βασική διεύθυνση URL",
|
||||
"Version": "Εκδοχή",
|
||||
"Check Update On GitHub": "Ελέγξτε για Ενημέρωση στο GitHub",
|
||||
"List": "Λίστα",
|
||||
"Add": "Προσθήκη",
|
||||
"Add New Monitor": "Προσθήκη νέας παρακολούθησης",
|
||||
"Quick Stats": "Γρήγορα στατιστικά",
|
||||
"Up": "Πάνω",
|
||||
"Down": "Κάτω",
|
||||
"Pending": "Εκκρεμεί",
|
||||
"Unknown": "Άγνωστο",
|
||||
"Pause": "Παύση",
|
||||
"Name": "Ονομα",
|
||||
"Status": "Κατάσταση",
|
||||
"DateTime": "ΗμερομηνίαΏρα",
|
||||
"Message": "Μήνυμα",
|
||||
"No important events": "Δεν υπάρχουν σημαντικά γεγονότα",
|
||||
"Resume": "Συνέχιση",
|
||||
"Edit": "Επεξεργασία",
|
||||
"Delete": "Διαγράφη",
|
||||
"Current": "Current",
|
||||
"Uptime": "Χρόνος λειτουργίας",
|
||||
"Cert Exp.": "Cert Exp.",
|
||||
"day": "ημέρα | ημέρες",
|
||||
"-day": "-ημέρα",
|
||||
"hour": "ώρα",
|
||||
"-hour": "-ώρα",
|
||||
"Response": "Απάντηση",
|
||||
"Ping": "Ping",
|
||||
"Monitor Type": "Τύπος παρακολούθησης",
|
||||
"Keyword": "Λέξη-κλειδί",
|
||||
"Friendly Name": "Φιλικό όνομα",
|
||||
"URL": "URL",
|
||||
"Hostname": "Hostname",
|
||||
"Port": "Port",
|
||||
"Heartbeat Interval": "Διάστημα καρδιακών παλμών",
|
||||
"Retries": "Επαναλήψεις",
|
||||
"Heartbeat Retry Interval": "Διάστημα επανάληψης παλμών καρδιάς",
|
||||
"Resend Notification if Down X times consequently": "Αποστολή νέας ειδοποίησης εάν κατω X φορές κατά συνέχεια",
|
||||
"Advanced": "Προχωρημένα",
|
||||
"Upside Down Mode": "Ανάποδη λειτουργία",
|
||||
"Max. Redirects": "Μέγιστη. Ανακατευθύνσεις",
|
||||
"Accepted Status Codes": "Αποδεκτοί Κωδικοί Κατάστασης",
|
||||
"Push URL": "Push URL",
|
||||
"needPushEvery": "Θα πρέπει να καλείτε αυτήν τη διεύθυνση URL κάθε {0} δευτερόλεπτα.",
|
||||
"pushOptionalParams": "Προαιρετικές παράμετροι: {0}",
|
||||
"Save": "Αποθηκεύση",
|
||||
"Notifications": "Ειδοποιήσεις",
|
||||
"Not available, please setup.": "Μη διαθέσιμο, παρακαλώ ρυθμίστε.",
|
||||
"Setup Notification": "Δημιουργία ειδοποίησης",
|
||||
"Light": "Φωτεινό",
|
||||
"Dark": "Σκοτεινό",
|
||||
"Auto": "Αυτόματο",
|
||||
"Theme - Heartbeat Bar": "Θέμα - Μπάρα καρδιακών παλμών",
|
||||
"Normal": "Κανονικό",
|
||||
"Bottom": "Κάτω μέρος",
|
||||
"None": "Τίποτα",
|
||||
"Timezone": "Ζώνη ώρας",
|
||||
"Search Engine Visibility": "Ορατότητα μηχανών αναζήτησης",
|
||||
"Allow indexing": "Να επιτρέπεται η ευρετηρίαση",
|
||||
"Discourage search engines from indexing site": "Αποθαρρύνετε τις μηχανές αναζήτησης από την ευρετηρίαση ιστότοπου",
|
||||
"Change Password": "Αλλαγή κωδικού πρόσβασης",
|
||||
"Current Password": "Τρέχων κωδικός πρόσβασης",
|
||||
"New Password": "Νέος κωδικός πρόσβασης",
|
||||
"Repeat New Password": "Επαναλάβετε τον νέο κωδικό πρόσβασης",
|
||||
"Update Password": "Ενημέρωση κωδικού πρόσβασης",
|
||||
"Disable Auth": "Απενεργοποίηση ελέγχου ταυτότητας",
|
||||
"Enable Auth": "Ενεργοποίηση ελέγχου ταυτότητας",
|
||||
"disableauth.message1": "Είστε βέβαιοι ότι θέλετε να <strong>απενεργοποιήσετε τον έλεγχο ταυτότητας</strong>;",
|
||||
"disableauth.message2": "Έχει σχεδιαστεί για σενάρια <strong>όπου σκοπεύετε να εφαρμόσετε έλεγχο ταυτότητας τρίτου μέρους</strong> μπροστά από το Uptime Kuma, όπως το Cloudflare Access, Authelia ή άλλους μηχανισμούς ελέγχου ταυτότητας.",
|
||||
"Please use this option carefully!": "Χρησιμοποιήστε αυτή την επιλογή προσεκτικά!",
|
||||
"Logout": "Αποσύνδεση",
|
||||
"Leave": "Φύγετε",
|
||||
"I understand, please disable": "Καταλαβαίνω, απενεργοποιήστε",
|
||||
"Confirm": "Επιβεβαίωση",
|
||||
"Yes": "Ναί",
|
||||
"No": "Οχι",
|
||||
"Username": "Όνομα χρήστη",
|
||||
"Password": "Κωδικός πρόσβασης",
|
||||
"Remember me": "Θυμήσου με",
|
||||
"Login": "Σύνδεση",
|
||||
"No Monitors, please": "Δεν υπάρχουν παρακολούθησης παρακαλώ",
|
||||
"add one": "προσθέστε ένα",
|
||||
"Notification Type": "Είδος ειδοποίησης",
|
||||
"Email": "Email",
|
||||
"Test": "Δοκιμή",
|
||||
"Certificate Info": "Πληροφορίες πιστοποιητικού",
|
||||
"Resolver Server": "Διακομιστής επίλυσης",
|
||||
"Resource Record Type": "Τύπος εγγραφής πόρων",
|
||||
"Last Result": "Τελευταίο Αποτέλεσμα",
|
||||
"Create your admin account": "Δημιουργήστε τον λογαριασμό διαχειριστή σας",
|
||||
"Repeat Password": "Επαναλάβετε τον κωδικό πρόσβασης",
|
||||
"Import Backup": "Εισαγωγή αντιγράφων ασφαλείας",
|
||||
"Export Backup": "Εξαγωγή αντιγράφων ασφαλείας",
|
||||
"Export": "Εξαγωγή",
|
||||
"Import": "Εισαγωγή",
|
||||
"respTime": "Χρόν. Aπό (ms)",
|
||||
"notAvailableShort": "N/A",
|
||||
"Default enabled": "Προεπιλογή ενεργοποιημένη",
|
||||
"Apply on all existing monitors": "Εφαρμόστε σε όλες τις υπάρχουσες παρακολούθησης",
|
||||
"Create": "Δημιουργία",
|
||||
"Clear Data": "Καθαρισμός δεδομένων",
|
||||
"Events": "Γεγονότα",
|
||||
"Heartbeats": "Παλμοι καρδιας",
|
||||
"Auto Get": "Αυτόματη λήψη",
|
||||
"backupDescription": "Μπορείτε να δημιουργήσετε αντίγραφα ασφαλείας γία ολλες της παρακολούθησης και ειδοποιήσης σε ένα αρχείο JSON.",
|
||||
"backupDescription2": "Σημείωση: δεν περιλαμβάνονται δεδομένα ιστορικού και συμβάντων.",
|
||||
"backupDescription3": "Στο αρχείο εξαγωγής περιλαμβάνονται ευαίσθητα δεδομένα, όπως token ειδοποιήσεων. Aποθηκεύστε την εξαγωγή με ασφάλεια.",
|
||||
"alertNoFile": "Επιλέξτε ένα αρχείο για εισαγωγή.",
|
||||
"alertWrongFileType": "Επιλέξτε ένα αρχείο JSON.",
|
||||
"Clear all statistics": "Εκκαθάριση όλων των στατιστικών",
|
||||
"Skip existing": "Παράβλεψη υπάρχοντος",
|
||||
"Overwrite": "Αντικατάσταση",
|
||||
"Options": "Επιλογές",
|
||||
"Keep both": "Κράτα και τα δύο",
|
||||
"Verify Token": "Επαλήθευση Token",
|
||||
"Setup 2FA": "Ρύθμιση 2FA",
|
||||
"Enable 2FA": "Ενεργοποίηση 2FA",
|
||||
"Disable 2FA": "Απενεργοποίηση 2FA",
|
||||
"2FA Settings": "Ρυθμίσεις 2FA",
|
||||
"Two Factor Authentication": "Έλεγχος ταυτότητας δύο παραγόντων",
|
||||
"Active": "Ενεργός",
|
||||
"Inactive": "Ανενεργό",
|
||||
"Token": "Token",
|
||||
"Show URI": "Εμφάνιση URI",
|
||||
"Tags": "Ετικέτες",
|
||||
"Add New below or Select...": "Προσθήκη νέου παρακάτω ή Επιλέξτε...",
|
||||
"Tag with this name already exist.": "Υπάρχει ήδη η ετικέτα με αυτό το όνομα.",
|
||||
"Tag with this value already exist.": "Υπάρχει ήδη ετικέτα με αυτό το value.",
|
||||
"color": "χρώμα",
|
||||
"value (optional)": "value (optional)",
|
||||
"Gray": "Γκρί",
|
||||
"Red": "Κόκκινο",
|
||||
"Orange": "Πορτοκάλι",
|
||||
"Green": "Πράσινο",
|
||||
"Blue": "Μπλε",
|
||||
"Indigo": "Indigo",
|
||||
"Purple": "Μωβ",
|
||||
"Pink": "Ροζ",
|
||||
"Search...": "Αναζήτηση...",
|
||||
"Avg. Ping": "Μέσo.Ping",
|
||||
"Avg. Response": "Μέσo. Aπάντηση",
|
||||
"Entry Page": "Σελίδα εισαγωγής",
|
||||
"statusPageNothing": "Δεν υπάρχει τίποτα εδώ, προσθέστε μια ομάδα ή μια παρακολούθηση.",
|
||||
"No Services": "Δεν υπάρχουν υπηρεσίες",
|
||||
"All Systems Operational": "Όλα τα συστήματα λειτουργούν",
|
||||
"Partially Degraded Service": "Μερικώς υποβαθμισμένη υπηρεσία",
|
||||
"Degraded Service": "Υποβαθμισμένη υπηρεσία",
|
||||
"Add Group": "Προσθήκη γρουπ",
|
||||
"Add a monitor": "Προσθήκη παρακολούθησης",
|
||||
"Edit Status Page": "Επεξεργασία σελίδας κατάστασης",
|
||||
"Go to Dashboard": "Μεταβείτε στον Πίνακα ελέγχου",
|
||||
"Status Page": "Σελίδα κατάστασης",
|
||||
"Status Pages": "Σελίδες κατάστασης",
|
||||
"defaultNotificationName": "Η ειδοποίηση μου {notification} ({number})",
|
||||
"here": "εδώ",
|
||||
"Required": "Απαιτείται",
|
||||
"telegram": "Telegram",
|
||||
"ZohoCliq": "ZohoCliq",
|
||||
"Bot Token": "Διακριτικό Bot",
|
||||
"wayToGetTelegramToken": "Μπορείτε να πάρετε ένα διακριτικό από {0}.",
|
||||
"Chat ID": "Chat ID",
|
||||
"supportTelegramChatID": "Support Direct Chat / Group / Channel's Chat ID",
|
||||
"wayToGetTelegramChatID": "Μπορείτε να λάβετε το αναγνωριστικό συνομιλίας σας στέλνοντας ένα μήνυμα στο bot και μεταβαίνοντας σε αυτήν τη διεύθυνση URL για να προβάλετε το chat_id:",
|
||||
"YOUR BOT TOKEN HERE": "ΤΟ BOT ΣΑΣ ΔΙΑΚΡΙΤΙΚΌ ΕΔΩ",
|
||||
"chatIDNotFound": "Το Chat ID δεν βρέθηκε. Στείλτε πρώτα ένα μήνυμα σε αυτό το bot",
|
||||
"webhook": "Webhook",
|
||||
"Post URL": "Post URL",
|
||||
"Content Type": "Τύπος περιεχομένου",
|
||||
"webhookJsonDesc": "{0} είναι καλό για οποιονδήποτε σύγχρονο διακομιστή HTTP όπως το Express.js",
|
||||
"webhookFormDataDesc": "{multipart} είναι καλό για την PHP. Το JSON θα πρέπει να αναλυθεί με {decodeFunction}",
|
||||
"smtp": "Email (SMTP)",
|
||||
"secureOptionNone": "None / STARTTLS (25, 587)",
|
||||
"secureOptionTLS": "TLS (465)",
|
||||
"Ignore TLS Error": "Παράβλεψη σφάλματος TLS",
|
||||
"From Email": "Από Email",
|
||||
"emailCustomSubject": "Προσαρμοσμένο θέμα",
|
||||
"To Email": "Προς Email",
|
||||
"smtpCC": "CC",
|
||||
"smtpBCC": "BCC",
|
||||
"discord": "Discord",
|
||||
"Discord Webhook URL": "Discord Webhook URL",
|
||||
"wayToGetDiscordURL": "Μπορείτε να το αποκτήσετε μεταβαίνοντας στις Ρυθμίσεις διακομιστή -> Ενσωματώσεις -> Δημιουργία Webhook",
|
||||
"Bot Display Name": "Εμφανιζόμενο όνομα bot",
|
||||
"Prefix Custom Message": "Προσαρμοσμένο μήνυμα",
|
||||
"Hello @everyone is...": "Γεια {'@'}everyone ειναι...",
|
||||
"teams": "Microsoft Teams",
|
||||
"Webhook URL": "Webhook URL",
|
||||
"wayToGetTeamsURL": "Μπορείτε να μάθετε πώς να δημιουργείτε μια διεύθυνση URL webhook {0}.",
|
||||
"wayToGetZohoCliqURL": "Μπορείτε να μάθετε πώς να δημιουργείτε μια διεύθυνση URL webhook {0}.",
|
||||
"signal": "Signal",
|
||||
"Number": "Αριθμός",
|
||||
"Recipients": "Αποδέκτες",
|
||||
"needSignalAPI": "Πρέπει να έχετε ένα signal client με REST API..",
|
||||
"wayToCheckSignalURL": "Μπορείτε να ελέγξετε αυτό το URL για να δείτε πώς να ρυθμίσετε ένα:",
|
||||
"signalImportant": "ΣΗΜΑΝΤΙΚΟ: Δεν μπορείτε να συνδυάσετε ομάδες και αριθμούς στους παραλήπτες!",
|
||||
"gotify": "Gotify",
|
||||
"Application Token": "Token εφαρμογής",
|
||||
"Server URL": "URL διακομιστή",
|
||||
"Priority": "Προτεραιότητα",
|
||||
"slack": "Slack",
|
||||
"Icon Emoji": "Εικονίδιο Emoji",
|
||||
"Channel Name": "Όνομα καναλιού",
|
||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||
"aboutWebhooks": "Περισσότερες πληροφορίες σχετικά με τα Webhooks στο: {0}",
|
||||
"aboutChannelName": "Εισαγάγετε το όνομα του καναλιού στο {0} Όνομα καναλιού εάν θέλετε να παρακάμψετε το κανάλι Webhook. Π.χ.: #other-channel",
|
||||
"aboutKumaURL": "Εάν αφήσετε κενό το πεδίο URL Uptime Kuma, θα είναι προεπιλεγμένο στη σελίδα Project GitHub..",
|
||||
"emojiCheatSheet": "Φύλλο εξαπάτησης emoji: {0}",
|
||||
"rocket.chat": "Rocket.Chat",
|
||||
"pushover": "Pushover",
|
||||
"pushy": "Pushy",
|
||||
"PushByTechulus": "Push by Techulus",
|
||||
"octopush": "Octopush",
|
||||
"promosms": "PromoSMS",
|
||||
"clicksendsms": "ClickSend SMS",
|
||||
"lunasea": "LunaSea",
|
||||
"apprise": "Apprise (Support 50+ Notification services)",
|
||||
"GoogleChat": "Google Chat (Google Workspace only)",
|
||||
"pushbullet": "Pushbullet",
|
||||
"line": "Line Messenger",
|
||||
"mattermost": "Mattermost",
|
||||
"User Key": "Κλειδί χρήστη",
|
||||
"Device": "Συσκευή",
|
||||
"Message Title": "Τίτλος μηνύματος",
|
||||
"Notification Sound": "Ήχος ειδοποίησης",
|
||||
"More info on:": "Περισσότερες πληροφορίες στο: {0}",
|
||||
"pushoverDesc1": "Η προτεραιότητα έκτακτης ανάγκης (2) έχει προεπιλεγμένο χρονικό όριο 30 δευτερολέπτων μεταξύ των επαναλήψεων και θα λήξει μετά από 1 ώρα.",
|
||||
"pushoverDesc2": "Εάν θέλετε να στέλνετε ειδοποιήσεις σε διαφορετικές συσκευές, συμπληρώστε το πεδίο Συσκευή.",
|
||||
"SMS Type": "Τύπος SMS",
|
||||
"octopushTypePremium": "Premium (Γρήγορη - συνιστάται για ειδοποίηση)",
|
||||
"octopushTypeLowCost": "Χαμηλό κόστος (Αργό - μερικές φορές μπλοκάρεται από τον χειριστή)",
|
||||
"checkPrice": "Ελέγξτε τις τιμές {0}:",
|
||||
"apiCredentials": "API credentials",
|
||||
"octopushLegacyHint": "Χρησιμοποιείτε την παλαιού τύπου έκδοση του Octopush (2011-2020) ή τη νέα έκδοση;",
|
||||
"Check octopush prices": "Ελέγξτε τις τιμές OctoPush {0}.",
|
||||
"octopushPhoneNumber": "Αριθμός τηλεφώνου (διεθνής μορφή, π.χ.: +30694345678)",
|
||||
"octopushSMSSender": "Όνομα αποστολέα SMS: 3-11 αλφαριθμητικοί χαρακτήρες και διάστημα (a-zA-Z0-9)",
|
||||
"LunaSea Device ID": "LunaSea Device ID",
|
||||
"Apprise URL": "Apprise URL",
|
||||
"Example:": "Παράδειγμα: {0}",
|
||||
"Read more:": "Διαβάστε περισσότερα: {0}",
|
||||
"Status:": "Κατάσταση: {0}",
|
||||
"Read more": "Διαβάστε περισσότερα",
|
||||
"appriseInstalled": "Το Apprise έχει εγκατασταθεί.",
|
||||
"appriseNotInstalled": "Το Apprise δεν έχει εγκατασταθεί. {0}",
|
||||
"Access Token": "Access Token",
|
||||
"Channel access token": "Channel Access Token",
|
||||
"Line Developers Console": "Line Developers Console",
|
||||
"lineDevConsoleTo": "Line Developers Console - {0}",
|
||||
"Basic Settings": "Βασικές ρυθμίσεις",
|
||||
"User ID": "User ID",
|
||||
"Messaging API": "Messaging API",
|
||||
"wayToGetLineChannelToken": "Πρώτα αποκτήστε πρόσβαση στο {0}, δημιουργήστε έναν πάροχο και ένα κανάλι (Messanging API) και, στη συνέχεια, μπορείτε να λάβετε το channel access token και το user ID από τα παραπάνω στοιχεία μενού.",
|
||||
"Icon URL": "Διεύθυνση URL εικονιδίου",
|
||||
"aboutIconURL": "Μπορείτε να παρέχετε έναν σύνδεσμο προς μια εικόνα στο \"Icon URL\" για να παρακάμψετε την προεπιλεγμένη εικόνα προφίλ. Δεν θα χρησιμοποιηθεί εάν έχει οριστεί το εικονίδιο Emoji.",
|
||||
"aboutMattermostChannelName": "Μπορείτε να παρακάμψετε το προεπιλεγμένο κανάλι στο οποίο δημοσιεύει το Webhook εισάγοντας το όνομα του καναλιού στο πεδίο \"Όνομα καναλιού\". Αυτό πρέπει να ενεργοποιηθεί στις ρυθμίσεις του Mattermost Webhook. Π.χ.: #other-channel",
|
||||
"matrix": "Matrix",
|
||||
"promosmsTypeEco": "SMS ECO - φθηνό αλλά αργό και συχνά υπερφορτωμένο. Περιορίζεται μόνο σε Πολωνούς παραλήπτες.",
|
||||
"promosmsTypeFlash": "SMS FLASH - Το μήνυμα θα εμφανίζεται αυτόματα στη συσκευή του παραλήπτη. Περιορίζεται μόνο σε Πολωνούς παραλήπτες.",
|
||||
"promosmsTypeFull": "SMS FULL - Premium επίπεδο SMS, Μπορείτε να χρησιμοποιήσετε το Όνομα Αποστολέα σας (Πρέπει πρώτα να καταχωρήσετε το όνομα). Αξιόπιστο για ειδοποιήσεις.",
|
||||
"promosmsTypeSpeed": "SMS SPEED - Υψηλότερη προτεραιότητα στο σύστημα. Πολύ γρήγορο και αξιόπιστο αλλά ακριβό (περίπου διπλάσια τιμή SMS FULL).",
|
||||
"promosmsPhoneNumber": "Αριθμός τηλεφώνου (για πολωνούς παραλήπτες Μπορείτε να παραλείψετε τους κωδικούς περιοχής)",
|
||||
"promosmsSMSSender": "Όνομα αποστολέα SMS: Προεγγεγραμμένο όνομα ή ένα από τα προεπιλεγμένα: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||
"Feishu WebHookUrl": "Feishu WebHookURL",
|
||||
"matrixHomeserverURL": "Homeserver URL (με http(s):// και προαιρετικά θύρα)",
|
||||
"Internal Room Id": "Internal Room ID",
|
||||
"matrixDesc1": "Μπορείτε να βρείτε το internal room ID ανατρέχοντας στην ενότητα για προχωρημένους των ρυθμίσεων δωματίου στο πρόγραμμα-πελάτη Matrix. Θα πρέπει να μοιάζει με !QMdRCpUIfLwsfjxye6:home.server.",
|
||||
"matrixDesc2": "Συνιστάται ανεπιφύλακτα να δημιουργήσετε έναν νέο χρήστη και να μην χρησιμοποιήσετε το διακριτικό πρόσβασης του χρήστη Matrix, καθώς θα επιτρέψει την πλήρη πρόσβαση στον λογαριασμό σας και σε όλα τα δωμάτια στα οποία συμμετέχετε. Αντίθετα, δημιουργήστε έναν νέο χρήστη και προσκαλέστε τον μόνο στο δωμάτιο στο οποίο θέλετε να λαμβάνετε την ειδοποίηση. Μπορείτε να λάβετε το access token εκτελώντας {0}",
|
||||
"Method": "Μέθοδος",
|
||||
"Body": "Σώμα",
|
||||
"Headers": "Headers",
|
||||
"PushUrl": "Push URL",
|
||||
"HeadersInvalidFormat": "The request headers are not valid JSON: ",
|
||||
"BodyInvalidFormat": "The request body is not valid JSON: ",
|
||||
"Monitor History": "Ιστορικο Παρακολούθησης",
|
||||
"clearDataOlderThan": "Διατηρήστε τα δεδομένα ιστορικού παρακολούθησης για {0} ημέρες.",
|
||||
"PasswordsDoNotMatch": "Οι κωδικοί πρόσβασης δεν ταιριάζουν.",
|
||||
"records": "εγγραφές",
|
||||
"One record": "Μία εγγραφή",
|
||||
"steamApiKeyDescription": "Για την παρακολούθηση ενός διακομιστή παιχνιδιών Steam χρειάζεστε ένα κλειδί Steam Web-API. Μπορείτε να καταχωρήσετε το κλειδί API σας εδώ: ",
|
||||
"Current User": "Τρέχων χρήστης",
|
||||
"topic": "Θέμα",
|
||||
"topicExplanation": "Θέμα MQTT προς παρακολούθηση",
|
||||
"successMessage": "Μήνυμα επιτυχίας",
|
||||
"successMessageExplanation": "Μήνυμα MQTT που θα θεωρηθεί επιτυχές",
|
||||
"recent": "Πρόσφατος",
|
||||
"Done": "Ολοκληρώθηκε",
|
||||
"Info": "Πληροφορίες",
|
||||
"Security": "Ασφάλεια",
|
||||
"Steam API Key": "Steam API Key",
|
||||
"Shrink Database": "Συρρίκνωση βάσης δεδομένων",
|
||||
"Pick a RR-Type...": "Επιλέξτε έναν τύπο RR...",
|
||||
"Pick Accepted Status Codes...": "Επιλέξτε Αποδεκτούς κωδικούς κατάστασης...",
|
||||
"Default": "Προκαθορισμένο",
|
||||
"HTTP Options": "Επιλογές HTTP",
|
||||
"Create Incident": "Δημιουργία περιστατικού",
|
||||
"Title": "Τίτλος",
|
||||
"Content": "Περιεχόμενο",
|
||||
"Style": "Στυλ",
|
||||
"info": "πληροφορίες",
|
||||
"warning": "προειδοποίηση",
|
||||
"danger": "κίνδυνος",
|
||||
"error": "σφάλμα",
|
||||
"critical": "κριτικό",
|
||||
"primary": "primary",
|
||||
"light": "light",
|
||||
"dark": "dark",
|
||||
"Post": "Δημοσίευση",
|
||||
"Please input title and content": "Παρακαλούμε εισαγάγετε τίτλο και περιεχόμενο",
|
||||
"Created": "Δημιουργήθηκε",
|
||||
"Last Updated": "Τελευταία ενημέρωση",
|
||||
"Unpin": "Ξεκαρφιτσώστε",
|
||||
"Switch to Light Theme": "Μετάβαση σε Ανιχτό θέμα",
|
||||
"Switch to Dark Theme": "Μετάβαση σε Σκούρο θέμα",
|
||||
"Show Tags": "Εμφάνιση ετικετών",
|
||||
"Hide Tags": "Απόκρυψη ετικετών",
|
||||
"Description": "Περιγραφή",
|
||||
"No monitors available.": "Δεν υπάρχουν διαθέσιμες παρακολουθήσεις.",
|
||||
"Add one": "Προσθέστε ένα",
|
||||
"No Monitors": "Χωρίς παρακολουθήσεις",
|
||||
"Untitled Group": "Ομάδα χωρίς τίτλο",
|
||||
"Services": "Υπηρεσίες",
|
||||
"Discard": "Απορρίψει",
|
||||
"Cancel": "Ακυρο",
|
||||
"Powered by": "Με την υποστήριξη του",
|
||||
"shrinkDatabaseDescription": "Ενεργοποίηση βάσης δεδομένων VACUUM για SQLite. Εάν η βάση δεδομένων σας έχει δημιουργηθεί μετά την έκδοση 1.10.0, το AUTO_VACUUM είναι ήδη ενεργοποιημένο και αυτή η ενέργεια δεν χρειάζεται.",
|
||||
"serwersms": "SerwerSMS.pl",
|
||||
"serwersmsAPIUser": "API Username (incl. webapi_ prefix)",
|
||||
"serwersmsAPIPassword": "API κωδικός πρόσβασης",
|
||||
"serwersmsPhoneNumber": "Αριθμός τηλεφώνου",
|
||||
"serwersmsSenderName": "Όνομα αποστολέα SMS (καταχωρήθηκε μέσω της πύλης πελατών)",
|
||||
"stackfield": "Stackfield",
|
||||
"Customize": "Προσαρμογή",
|
||||
"Custom Footer": "Προσαρμογή Footer",
|
||||
"Custom CSS": "Προσαρμογή CSS",
|
||||
"smtpDkimSettings": "Ρυθμίσεις DKIM",
|
||||
"smtpDkimDesc": "Ανατρέξτε στο Nodemailer DKIM {0} για χρήση.",
|
||||
"documentation": "documentation",
|
||||
"smtpDkimDomain": "Domain Name",
|
||||
"smtpDkimKeySelector": "Key Selector",
|
||||
"smtpDkimPrivateKey": "Private Key",
|
||||
"smtpDkimHashAlgo": "Hash Algorithm (Optional)",
|
||||
"smtpDkimheaderFieldNames": "Header Keys to sign (Optional)",
|
||||
"smtpDkimskipFields": "Header Keys not to sign (Optional)",
|
||||
"wayToGetPagerDutyKey": "Μπορείτε να το λάβετε μεταβαίνοντας στο Service -> Service Directory -> (Επιλέξτε μια υπηρεσία) -> Integrations -> Add integration. Εδώ μπορείτε να κάνετε αναζήτηση για \"Events API V2\". Περισσότερες πληροφορίες {0}",
|
||||
"Integration Key": "Integration Key",
|
||||
"Integration URL": "Integration URL",
|
||||
"Auto resolve or acknowledged": "Αυτόματη επίλυση ή αναγνώριση",
|
||||
"do nothing": "μην κάνεις τίποτα",
|
||||
"auto acknowledged": "αυτόματη αναγνώριση",
|
||||
"auto resolve": "αυτόματη επίλυση",
|
||||
"gorush": "Gorush",
|
||||
"alerta": "Alerta",
|
||||
"alertaApiEndpoint": "API Endpoint",
|
||||
"alertaEnvironment": "Environment",
|
||||
"alertaApiKey": "API Key",
|
||||
"alertaAlertState": "Alert State",
|
||||
"alertaRecoverState": "Recover State",
|
||||
"deleteStatusPageMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν τη σελίδα κατάστασης?",
|
||||
"Proxies": "Proxies",
|
||||
"default": "Προκαθορισμένο",
|
||||
"enabled": "Ενεργοποιημένο",
|
||||
"setAsDefault": "Ορίσετε ως προεπιλογή",
|
||||
"deleteProxyMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το proxy για όλες τις παρακολουθήσεις;",
|
||||
"proxyDescription": "Πρέπει να εκχωρηθούν proxies σε μια οθπαρακολουθή για να λειτουργήσουν..",
|
||||
"enableProxyDescription": "Το proxy δεν θα επηρεάσει τα αιτήματα της παρακολουθήσεις μέχρι να ενεργοποιηθεί. Μπορείτε να ελέγξετε την προσωρινή απενεργοποίηση του proxy από όλες τις παρακολουθήσεις βάσει κατάστασης ενεργοποίησης.",
|
||||
"setAsDefaultProxyDescription": "Αυτός το proxy θα είναι ενεργοποιημένο από προεπιλογή για νέες παρακολουθήσεις. Μπορείτε ακόμα να απενεργοποιήσετε το proxy ξεχωριστά για κάθε οθόνη.",
|
||||
"Certificate Chain": "Certificate Chain",
|
||||
"Valid": "Εγκυρο",
|
||||
"Invalid": "Μη έγκυρο",
|
||||
"AccessKeyId": "AccessKey ID",
|
||||
"SecretAccessKey": "AccessKey Secret",
|
||||
"PhoneNumbers": "PhoneNumbers",
|
||||
"TemplateCode": "TemplateCode",
|
||||
"SignName": "SignName",
|
||||
"Sms template must contain parameters: ": "Το πρότυπο SMS πρέπει να περιέχει παραμέτρους: ",
|
||||
"Bark Endpoint": "Bark Endpoint",
|
||||
"Bark Group": "Bark Ομάδα",
|
||||
"Bark Sound": "Bark Ήχος",
|
||||
"WebHookUrl": "WebHookUrl",
|
||||
"SecretKey": "SecretKey",
|
||||
"For safety, must use secret key": "Για ασφάλεια, πρέπει να χρησιμοποιήσετε secret key",
|
||||
"Device Token": "Device Token",
|
||||
"Platform": "Platform",
|
||||
"iOS": "iOS",
|
||||
"Android": "Android",
|
||||
"Huawei": "Huawei",
|
||||
"High": "High",
|
||||
"Retry": "Ξαναδοκιμάσετε",
|
||||
"Topic": "Θέμα",
|
||||
"WeCom Bot Key": "WeCom Bot Key",
|
||||
"Setup Proxy": "Ρύθμιση Proxy",
|
||||
"Proxy Protocol": "Πρωτόκολλο Proxy",
|
||||
"Proxy Server": "Proxy Server",
|
||||
"Proxy server has authentication": "Το Proxy διαθέτει έλεγχο ταυτότητας",
|
||||
"User": "Χρήστης",
|
||||
"Installed": "Εγκατεστημένο",
|
||||
"Not installed": "Μη εγκατεστημενο",
|
||||
"Running": "Τρέχη",
|
||||
"Not running": "Δεν τρεχη",
|
||||
"Remove Token": "Κατάργηση Token",
|
||||
"Start": "Αρχή",
|
||||
"Stop": "Στάση",
|
||||
"Uptime Kuma": "Uptime Kuma",
|
||||
"Add New Status Page": "Προσθήκη νέας σελίδας κατάστασης",
|
||||
"Slug": "Slug",
|
||||
"Accept characters:": "Αποδοχή χαρακτήρων:",
|
||||
"startOrEndWithOnly": "Ξεκινήστε ή τελειώστε μόνο με {0}",
|
||||
"No consecutive dashes": "Χωρίς διαδοχικές παύλες",
|
||||
"Next": "Επόμενο",
|
||||
"The slug is already taken. Please choose another slug.": "Ο slug έχει ήδη πιαστεί. Επιλέξτε άλλο slug.",
|
||||
"No Proxy": "Οχι Proxy",
|
||||
"Authentication": "Authentication",
|
||||
"HTTP Basic Auth": "HTTP Basic Auth",
|
||||
"New Status Page": "Νέας Σελίδα κατάστασης",
|
||||
"Page Not Found": "Η σελίδα δεν βρέθηκε",
|
||||
"Reverse Proxy": "Αντίστροφο Proxy",
|
||||
"Backup": "Αντιγράφων ασφαλείας",
|
||||
"About": "Σχετικά με το Uptime Kuma",
|
||||
"wayToGetCloudflaredURL": "(Λήψη cloudflared από {0})",
|
||||
"cloudflareWebsite": "Ιστοσελίδα Cloudflare",
|
||||
"Message:": "Μήνυμα:",
|
||||
"Don't know how to get the token? Please read the guide:": "Δεν ξέρετε πώς να αποκτήσετε το token; Διαβάστε τον οδηγό:",
|
||||
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Η τρέχουσα σύνδεση μπορεί να χαθεί εάν αυτή τη στιγμή συνδέεστε μέσω του Cloudflare Tunnel. Θέλετε σίγουρα να το σταματήσετε; Πληκτρολογήστε τον τρέχοντα κωδικό πρόσβασής σας για να τον επιβεβαιώσετε.",
|
||||
"HTTP Headers": "HTTP Headers",
|
||||
"Trust Proxy": "Εμπιστοσύνη του Proxy",
|
||||
"Other Software": "Other Software",
|
||||
"For example: nginx, Apache and Traefik.": "Για παράδειγμα: nginx, Apache και Traefik.",
|
||||
"Please read": "Παρακαλώ διαβάστε",
|
||||
"Subject:": "Θέμα:",
|
||||
"Valid To:": "Εγκυρο για:",
|
||||
"Days Remaining:": "Ημέρες που απομένουν:",
|
||||
"Issuer:": "Εκδότης:",
|
||||
"Fingerprint:": "Δακτυλικό αποτύπωμα:",
|
||||
"No status pages": "Δεν υπάρχουν σελίδες κατάστασης",
|
||||
"Domain Name Expiry Notification": "Ειδοποίηση λήξης ονόματος τομέα",
|
||||
"Proxy": "Proxy",
|
||||
"Date Created": "Ημερομηνία Δημιουργίας",
|
||||
"HomeAssistant": "Home Assistant",
|
||||
"onebotHttpAddress": "OneBot HTTP Address",
|
||||
"onebotMessageType": "OneBot Message Type",
|
||||
"onebotGroupMessage": "Group",
|
||||
"onebotPrivateMessage": "Private",
|
||||
"onebotUserOrGroupId": "Group/User ID",
|
||||
"onebotSafetyTips": "Για ασφάλεια, πρέπει να ορίσετε το acess token",
|
||||
"PushDeer Key": "PushDeer Key",
|
||||
"Footer Text": "Κείμενο υποσέλιδου",
|
||||
"Show Powered By": "Εμφάνιση Powered By",
|
||||
"Domain Names": "Ονόματα Τομέα",
|
||||
"signedInDisp": "Συνδεθήκατε ως {0}",
|
||||
"signedInDispDisabled": "Εξουσιοδότηση είναι απενεργοποιημένη.",
|
||||
"RadiusSecret": "Radius Secret",
|
||||
"RadiusSecretDescription": "Shared Secret μεταξύ client και το server",
|
||||
"RadiusCalledStationId": "Called Station Id",
|
||||
"RadiusCalledStationIdDescription": "Identifier της καλούμενης συσκευής",
|
||||
"RadiusCallingStationId": "Calling Station Id",
|
||||
"RadiusCallingStationIdDescription": "Identifier oτης συσκευής κλήσης",
|
||||
"Certificate Expiry Notification": "Ειδοποίηση Λήξης Πιστοποιητικού",
|
||||
"API Username": "API Username",
|
||||
"API Key": "API Key",
|
||||
"Recipient Number": "Αριθμός Παραλήπτη",
|
||||
"From Name/Number": "Από Όνομα/Αριθμός",
|
||||
"Leave blank to use a shared sender number.": "Αφήστε το κενό για να χρησιμοποιήσετε έναν κοινόχρηστο αριθμό αποστολέα.",
|
||||
"Octopush API Version": "Octopush API Version",
|
||||
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||
"endpoint": "endpoint",
|
||||
"octopushAPIKey": "\"API key\" από το HTTP API credentials στον πίνακα ελέγχου",
|
||||
"octopushLogin": "\"Login\" από το HTTP API credentials στον πίνακα ελέγχου",
|
||||
"promosmsLogin": "API Login Name",
|
||||
"promosmsPassword": "API Password",
|
||||
"pushoversounds pushover": "Pushover (default)",
|
||||
"pushoversounds bike": "Bike",
|
||||
"pushoversounds bugle": "Bugle",
|
||||
"pushoversounds cashregister": "Cash Register",
|
||||
"pushoversounds classical": "Classical",
|
||||
"pushoversounds cosmic": "Cosmic",
|
||||
"pushoversounds falling": "Falling",
|
||||
"pushoversounds gamelan": "Gamelan",
|
||||
"pushoversounds incoming": "Incoming",
|
||||
"pushoversounds intermission": "Intermission",
|
||||
"pushoversounds magic": "Magic",
|
||||
"pushoversounds mechanical": "Mechanical",
|
||||
"pushoversounds pianobar": "Piano Bar",
|
||||
"pushoversounds siren": "Siren",
|
||||
"pushoversounds spacealarm": "Space Alarm",
|
||||
"pushoversounds tugboat": "Tug Boat",
|
||||
"pushoversounds alien": "Alien Alarm (long)",
|
||||
"pushoversounds climb": "Climb (long)",
|
||||
"pushoversounds persistent": "Persistent (long)",
|
||||
"pushoversounds echo": "Pushover Echo (long)",
|
||||
"pushoversounds updown": "Up Down (long)",
|
||||
"pushoversounds vibrate": "Vibrate Only",
|
||||
"pushoversounds none": "None (silent)",
|
||||
"pushyAPIKey": "Μυστικό API Key",
|
||||
"pushyToken": "Τoken Συσκευής",
|
||||
"Show update if available": "Εμφάνιση ενημέρωσης εάν είναι διαθέσιμη",
|
||||
"Also check beta release": "Ελέγξτε επίσης την έκδοση beta",
|
||||
"Using a Reverse Proxy?": "Χρησιμοποιείτε reverse proxy;",
|
||||
"Check how to config it for WebSocket": "Ελέγξτε πώς να το ρυθμίσετε για το WebSocket",
|
||||
"Steam Game Server": "Διακομιστής παιχνιδιών Steam",
|
||||
"Most likely causes:": "Πιο πιθανές αιτίες:",
|
||||
"The resource is no longer available.": "Ο πόρος δεν είναι πλέον διαθέσιμος.",
|
||||
"There might be a typing error in the address.": "Μπορεί να υπάρχει σφάλμα πληκτρολόγησης στη διεύθυνση.",
|
||||
"What you can try:": "Τι μπορείτε να δοκιμάσετε:",
|
||||
"Retype the address.": "Πληκτρολογήστε ξανά τη διεύθυνση.",
|
||||
"Go back to the previous page.": "Επιστρέψτε στην προηγούμενη σελίδα.",
|
||||
"Coming Soon": "Ερχεται σύντομα",
|
||||
"wayToGetClickSendSMSToken": "Μπορείτε να πάρετε το API Username και API Key απο {0} .",
|
||||
"Connection String": "Connection String",
|
||||
"Query": "Query",
|
||||
"settingsCertificateExpiry": "Λήξη πιστοποιητικού TLS",
|
||||
"certificationExpiryDescription": "Οι παρακολουθήσεις HTTPS ενεργοποιούν ειδοποίηση όταν λήξει το πιστοποιητικό TLS σε:",
|
||||
"Setup Docker Host": "Ρύθμιση Docker Host",
|
||||
"Connection Type": "Τύπος σύνδεσης",
|
||||
"Docker Daemon": "Docker Daemon",
|
||||
"deleteDockerHostMsg": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον κεντρικό υπολογιστή βάσης για όλες τις παρακολουθήσεις;",
|
||||
"socket": "Socket",
|
||||
"tcp": "TCP / HTTP",
|
||||
"Docker Container": "Docker Container",
|
||||
"Container Name / ID": "Container Name / ID",
|
||||
"Docker Host": "Docker Host",
|
||||
"Docker Hosts": "Docker Hosts",
|
||||
"ntfy Topic": "ntfy Topic",
|
||||
"Domain": "Domain",
|
||||
"Workstation": "Workstation",
|
||||
"disableCloudflaredNoAuthMsg": "Βρίσκεστε σε λειτουργία No Auth, δεν απαιτείται κωδικός πρόσβασης.",
|
||||
"trustProxyDescription": "Εμπιστευτείτε τις κεφαλίδες 'X-Forwarded-*'. Εάν θέλετε να λάβετε τη σωστή IP πελάτη και το Uptime Kuma σας βρίσκεται πίσω το Nginx ή το Apache, θα πρέπει να το ενεργοποιήσετε.",
|
||||
"wayToGetLineNotifyToken": "Μπορείτε να λάβετε ένα access token από το {0}",
|
||||
"Examples": "Παραδείγματα",
|
||||
"Home Assistant URL": "Home Assistant URL",
|
||||
"Long-Lived Access Token": "Long-Lived Access Token",
|
||||
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Long-Lived Access Token μπορεί να δημιουργηθεί κάνοντας κλικ στο όνομα του προφίλ σας (κάτω αριστερά) και κάνοντας κύλιση προς τα κάτω και, στη συνέχεια, κάντε κλικ στο Create Token. ",
|
||||
"Notification Service": "Υπηρεσία ειδοποιήσεων",
|
||||
"default: notify all devices": "προεπιλογή: ειδοποίηση όλων των συσκευών",
|
||||
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Μπορείτε να βρείτε μια λίστα με τις Υπηρεσίες ειδοποιήσεων στον Home assistant στην περιοχή \"Developer Tools > Services\" αναζήτηση για \"notification\" για να βρείτε το όνομα της συσκευής/τηλεφώνου σας.",
|
||||
"Automations can optionally be triggered in Home Assistant:": "Οι αυτοματισμοί μπορούν προαιρετικά να ενεργοποιηθούν στο Home Assistant:",
|
||||
"Trigger type:": "Τύπος ενεργοποίησης:",
|
||||
"Event type:": "Τύπος συμβάντος:",
|
||||
"Event data:": "Δεδομένα συμβάντος:",
|
||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Στη συνέχεια, επιλέξτε μια ενέργεια, για παράδειγμα αλλάξτε τη σκηνή στο σημείο όπου ένα φως RGB είναι κόκκινο.",
|
||||
"Frontend Version": "Έκδοση Frontend",
|
||||
"Frontend Version do not match backend version!": "Η Frontend έκδοση δεν ταιριάζει με την έκδοση backend!",
|
||||
"Base URL": "Βασική διεύθυνση URL",
|
||||
"goAlertInfo": "Το GoAlert είναι μια εφαρμογή ανοιχτού κώδικα για προγραμματισμό κλήσεων, αυτοματοποιημένες κλιμακώσεις και ειδοποιήσεις (όπως SMS ή φωνητικές κλήσεις). Αλληλεπιδράστε αυτόματα με το σωστό άτομο, με τον σωστό τρόπο και τη σωστή στιγμή! {0}",
|
||||
"goAlertIntegrationKeyInfo": "Λάβετε το generic API integration key για την υπηρεσία σε αυτήν τη μορφή \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" συνήθως την τιμή της παραμέτρου διακριτικού της αντιγραμμένης διεύθυνσης URL.",
|
||||
"goAlert": "GoAlert",
|
||||
"backupOutdatedWarning": "Καταργήθηκε: Επειδή προστέθηκαν πολλές δυνατότητες και αυτή η δυνατότητα δημιουργίας αντιγράφων ασφαλείας δεν διατηρείται πολη, δεν μπορεί να δημιουργήσει ή να επαναφέρει ένα πλήρες αντίγραφο ασφαλείας.",
|
||||
"backupRecommend": "Παρακαλούμε δημιουργήστε αντίγραφα ασφαλείας του volume ή του φακέλου δεδομένων (./data/) απευθείας."
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user