mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-11 22:06:59 +08:00
Compare commits
424 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
bf64095cea | ||
|
2333d1c7a7 | ||
|
95bae8289d | ||
|
45f7c647a6 | ||
|
733d0af75f | ||
|
b88e74fad8 | ||
|
734762b773 | ||
|
0275d7a42b | ||
|
41a6d1b701 | ||
|
c92153c97e | ||
|
ad82ab0305 | ||
|
f952d283c6 | ||
|
e164fabf81 | ||
|
bc69a331ee | ||
|
e4506963d9 | ||
|
8f44b9f618 | ||
|
210566c7af | ||
|
c5e6628803 | ||
|
3a1d8ddc11 | ||
|
bc5f61b3ec | ||
|
57389fab2c | ||
|
ee2c54cfd1 | ||
|
82cde7c847 | ||
|
1ba2034701 | ||
|
dee131c25d | ||
|
e5d6410caf | ||
|
e496c3b3be | ||
|
69f5112b38 | ||
|
c094dc0c5b | ||
|
1fb9b25d13 | ||
|
9a135deac2 | ||
|
8e6173c05e | ||
|
dec84282ed | ||
|
df80f413b5 | ||
|
17e59f1d8d | ||
|
973c2bb429 | ||
|
da0eaddeb8 | ||
|
b2bc8d9db9 | ||
|
541068ff3b | ||
|
83ee46454a | ||
|
75b21c905f | ||
|
60e12f4bfa | ||
|
191b81ee07 | ||
|
f3651a1219 | ||
|
12ef9f39c5 | ||
|
4004926e64 | ||
|
4d3d6d6e25 | ||
|
d06e5ef6fa | ||
|
b12b848d97 | ||
|
bb96a577ca | ||
|
8840ca618b | ||
|
8ec858fd14 | ||
|
124c98ce76 | ||
|
61135e8500 | ||
|
08a58dec2b | ||
|
741ed548da | ||
|
52d80d3a5d | ||
|
586c748d44 | ||
|
b5d6e96b1d | ||
|
68b74f07e4 | ||
|
bc615c2dd8 | ||
|
e7104737e7 | ||
|
1dbf1c3dea | ||
|
74688e69aa | ||
|
b32bfb3ff1 | ||
|
24664cde2c | ||
|
348c5ec995 | ||
|
9143b73f84 | ||
|
5e6d945095 | ||
|
ba93129b18 | ||
|
cf548df15f | ||
|
caa2a34177 | ||
|
69aa60d1fb | ||
|
eaecd6e571 | ||
|
f2a27a2cf1 | ||
|
d4c9431142 | ||
|
d7f7dba13f | ||
|
3e5ae00d25 | ||
|
5311bef3eb | ||
|
c400595f67 | ||
|
e84f7dac60 | ||
|
67a22399bc | ||
|
947fc6001e | ||
|
c87e67ad1b | ||
|
6f92774a8f | ||
|
6e76ab7426 | ||
|
b2fbd7e263 | ||
|
199e6ec82b | ||
|
18a99c2016 | ||
|
e261a27ebe | ||
|
de5cce9d90 | ||
|
b85c9186f9 | ||
|
eb22ad5ffe | ||
|
f5f4835b74 | ||
|
44c1b336dc | ||
|
110ec491ee | ||
|
640b6e5b1c | ||
|
234fba3978 | ||
|
1285ccb537 | ||
|
6c542edfc9 | ||
|
767807dd22 | ||
|
546402f3d2 | ||
|
698a38e773 | ||
|
71884cf42a | ||
|
d676c782bb | ||
|
dd773aa5a2 | ||
|
2852e59ffb | ||
|
cb3da50e7e | ||
|
f25653d778 | ||
|
2e7ad1b7b2 | ||
|
e0e1ab6fa6 | ||
|
8d984881c9 | ||
|
955f9ae20a | ||
|
a9e319517a | ||
|
39ad8b4bb7 | ||
|
8fb8cbdaf3 | ||
|
3f3d8b4eb3 | ||
|
9123e9461f | ||
|
77addfebc8 | ||
|
16846c7c6d | ||
|
d1c4d13903 | ||
|
7cd4bfc11d | ||
|
1d5c0502ab | ||
|
a1cda93ad5 | ||
|
3bd420f0e0 | ||
|
78424b4f2d | ||
|
f8055ed03d | ||
|
fe4724fc53 | ||
|
7f0dda6a44 | ||
|
43791ee97e | ||
|
6362ef6a9c | ||
|
9d3a4e9d1e | ||
|
6c60096f56 | ||
|
ba1e025353 | ||
|
a41a081727 | ||
|
a5f15f2319 | ||
|
e69799f613 | ||
|
3c795bebe3 | ||
|
3a43fec666 | ||
|
24c645e437 | ||
|
9d31da1fe8 | ||
|
2e4c42941a | ||
|
4fc2603818 | ||
|
7bc38d4231 | ||
|
daad63d70b | ||
|
9ddd2c7365 | ||
|
fa5ba12e14 | ||
|
85053f865e | ||
|
1239f6d1a2 | ||
|
fed611d1b9 | ||
|
bc68088350 | ||
|
90200958cd | ||
|
aa13d74d7a | ||
|
d82f305f6e | ||
|
7c63cbfd84 | ||
|
c7e1267779 | ||
|
5d0b54c292 | ||
|
b50b390048 | ||
|
65158cb06b | ||
|
8fe5e4e605 | ||
|
ab5ddae2ee | ||
|
89c64f4ea2 | ||
|
40a1ebecc5 | ||
|
e1793596fe | ||
|
c489058a57 | ||
|
95342ec006 | ||
|
bdebbf8e40 | ||
|
9a9fca67d5 | ||
|
665bae0806 | ||
|
e4be28a9e7 | ||
|
445674aacb | ||
|
2f7b60f5e5 | ||
|
b83c59e308 | ||
|
ce852dfa02 | ||
|
c9549c0de2 | ||
|
957c292307 | ||
|
b5eb17ed93 | ||
|
d578300104 | ||
|
b77b33e790 | ||
|
4becb97a5d | ||
|
85e2b36424 | ||
|
abdf1ae90a | ||
|
606c967985 | ||
|
93c231b4d9 | ||
|
9ad8e5f56a | ||
|
8a481a1be0 | ||
|
657987a013 | ||
|
d74577608b | ||
|
20a399c557 | ||
|
060dde9827 | ||
|
1d1601cf24 | ||
|
ff5f2e8dfb | ||
|
5451fb7672 | ||
|
56094a43d7 | ||
|
68bbe8944a | ||
|
8f1da6aa22 | ||
|
c0d6fe0d76 | ||
|
29e4e41215 | ||
|
7a1bb964e9 | ||
|
3fe0e9bf1e | ||
|
9982887783 | ||
|
c31efc0ef4 | ||
|
6463d4b209 | ||
|
acada8028a | ||
|
d0b0c64b81 | ||
|
cd04ac4557 | ||
|
d7d2f7b7fc | ||
|
5a05d135b8 | ||
|
e03ee593e2 | ||
|
6c1ee70e15 | ||
|
5c3892313e | ||
|
c57c94642c | ||
|
62f168a2a5 | ||
|
c808f78f09 | ||
|
9c80e1c732 | ||
|
acc2995d86 | ||
|
7def9dcec7 | ||
|
a35569481d | ||
|
9ddffc0f7f | ||
|
76e7c8b276 | ||
|
572a5300aa | ||
|
e1f1d4a959 | ||
|
c6fc385289 | ||
|
c645658161 | ||
|
182597944d | ||
|
8eaa8116c3 | ||
|
3512faad14 | ||
|
f11417e854 | ||
|
b5857f7c0c | ||
|
6277babf25 | ||
|
5f36d2acda | ||
|
cc36ff5210 | ||
|
c363d3374e | ||
|
65a8cb5307 | ||
|
f74b2662c5 | ||
|
300a95d779 | ||
|
23714ab688 | ||
|
16b44001e7 | ||
|
f2f8f33b86 | ||
|
6e18f39eb4 | ||
|
68d44dd9b3 | ||
|
20d59e5a13 | ||
|
ae31eb6ba9 | ||
|
df4682d19b | ||
|
11a1f35cc5 | ||
|
2a3ce15328 | ||
|
7cb25255bf | ||
|
c622f7958f | ||
|
df5efcc71c | ||
|
4cd66b20b1 | ||
|
1276102c18 | ||
|
6944b35ea7 | ||
|
88757ebbbe | ||
|
0a73b84ae6 | ||
|
15f36f96c3 | ||
|
edcaf93446 | ||
|
dec175d55f | ||
|
9a60f69f66 | ||
|
53a008ae2b | ||
|
1d63dd9ddd | ||
|
61627545a5 | ||
|
176fa6b60d | ||
|
cb43ecb46e | ||
|
2e24312f67 | ||
|
6ff3cb275e | ||
|
9d364b28b1 | ||
|
bc3e3f9118 | ||
|
0f3ab7b1d8 | ||
|
8cb26d2b31 | ||
|
d94fbede32 | ||
|
76e619c066 | ||
|
4e4f94ab98 | ||
|
ed3a558397 | ||
|
a419aa527f | ||
|
4d26825cbe | ||
|
7276f34d90 | ||
|
e1eeb44e7f | ||
|
f4b8da0a5c | ||
|
4178983df3 | ||
|
7ac0ab2e34 | ||
|
cd211a6be7 | ||
|
4e71ab7406 | ||
|
76c68071f1 | ||
|
bda481c61e | ||
|
8242a1586d | ||
|
c593a962c2 | ||
|
c9b4d2ae2a | ||
|
37105d720b | ||
|
3b74b727f2 | ||
|
2f0119bc3f | ||
|
a7d2a34dae | ||
|
60acb91fc8 | ||
|
f51156f18e | ||
|
8338881927 | ||
|
674b387c95 | ||
|
5ff9a64e5e | ||
|
4bee57ea7f | ||
|
f75c9e4f0c | ||
|
8ab4788f80 | ||
|
4e4ab0577e | ||
|
6e04ec436e | ||
|
2d471a5e84 | ||
|
cae194f58f | ||
|
655ccc86b9 | ||
|
e2dbacb383 | ||
|
89b34b5748 | ||
|
86dcc9bc8f | ||
|
9b05e86c25 | ||
|
145b722aec | ||
|
2ff7c4de5d | ||
|
79c81395bc | ||
|
178e5cd2c0 | ||
|
84507268ad | ||
|
843992c410 | ||
|
33f773fcd0 | ||
|
26841a64f0 | ||
|
89c0f8b734 | ||
|
57a76e6129 | ||
|
dc805cff97 | ||
|
3fe3450533 | ||
|
330cd6e058 | ||
|
a2f2253221 | ||
|
1e5ce92917 | ||
|
0d7c2960b0 | ||
|
82343de972 | ||
|
521d57c483 | ||
|
281671b938 | ||
|
30d8aadf12 | ||
|
2939bd4138 | ||
|
dcf15c3eb7 | ||
|
7c9ed98408 | ||
|
4b9f0a3fe6 | ||
|
5b67fec084 | ||
|
407581ee07 | ||
|
11c3c636e0 | ||
|
911d4ea37b | ||
|
4039c6549e | ||
|
d733ec018e | ||
|
03b07730d3 | ||
|
dbc87d8ab3 | ||
|
05b691d4c9 | ||
|
029d6412da | ||
|
9f12f95cce | ||
|
c1112a32df | ||
|
efc78acfeb | ||
|
9e01959d15 | ||
|
3fe91c52cb | ||
|
5269dcec60 | ||
|
a2cc7d1db9 | ||
|
18c5a16783 | ||
|
2538bd04ce | ||
|
b7528b9a4e | ||
|
9c058054b9 | ||
|
c6683e2a9b | ||
|
b558708be2 | ||
|
fd0dd2d284 | ||
|
1bc77a06e5 | ||
|
69c623ac2b | ||
|
69ffee55dd | ||
|
d769c4426c | ||
|
ebf0671fef | ||
|
97af09fd50 | ||
|
5b19e3f025 | ||
|
ce2df137e6 | ||
|
6d9b71c054 | ||
|
a433de74e6 | ||
|
8e3f43d60b | ||
|
2a1fd93444 | ||
|
dc1de50a02 | ||
|
e223e826a3 | ||
|
0e6d7694ce | ||
|
503d1f0a91 | ||
|
11bcd1e2ed | ||
|
06310423f4 | ||
|
e127e168b6 | ||
|
b5b391c73b | ||
|
075535ba46 | ||
|
13cf6891ac | ||
|
ad0cde6554 | ||
|
25d18f0da3 | ||
|
e9445bb2e3 | ||
|
ecc25ba596 | ||
|
e5286b0973 | ||
|
4e94cb9aad | ||
|
037fdd73a3 | ||
|
bb9a936658 | ||
|
5445c2a2ff | ||
|
dc08510e72 | ||
|
62805014df | ||
|
c79e80442a | ||
|
f0ff96afd9 | ||
|
8083368a81 | ||
|
afb75e07d5 | ||
|
efd3822930 | ||
|
2adac64c83 | ||
|
cee225bcb2 | ||
|
8958c21736 | ||
|
4ba2025451 | ||
|
5137c80c07 | ||
|
792f3c7c5c | ||
|
8a739af5ad | ||
|
edb75808d8 | ||
|
5e3ea3293c | ||
|
ac80631bcd | ||
|
8caf47988c | ||
|
6cf2eb036d | ||
|
dca5a59dbc | ||
|
656a4d6270 | ||
|
d71d27220b | ||
|
fba4f86552 | ||
|
b8093e909b | ||
|
c3c273f9df | ||
|
daab2a05f5 | ||
|
ec4b7e4064 | ||
|
8be4bf0e16 | ||
|
162ef04c41 | ||
|
a0ffa42b42 | ||
|
550825927c | ||
|
afeb424dc0 | ||
|
6b44116245 | ||
|
7ee89fab5c | ||
|
3f0b85e5a8 | ||
|
efbadd0737 | ||
|
b67b4d5afd |
@@ -1,5 +1,4 @@
|
|||||||
/.idea
|
/.idea
|
||||||
/dist
|
|
||||||
/node_modules
|
/node_modules
|
||||||
/data
|
/data
|
||||||
/out
|
/out
|
||||||
|
22
.github/ISSUE_TEMPLATE/ask-for-help.md
vendored
22
.github/ISSUE_TEMPLATE/ask-for-help.md
vendored
@@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
name: Ask for help
|
|
||||||
about: You can ask any question related to Uptime Kuma.
|
|
||||||
title: ''
|
|
||||||
labels: help
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
**Is it a duplicate question?**
|
|
||||||
Please search in Issues without filters: https://github.com/louislam/uptime-kuma/issues?q=
|
|
||||||
|
|
||||||
|
|
||||||
**Describe your problem**
|
|
||||||
|
|
||||||
|
|
||||||
**Info**
|
|
||||||
Uptime Kuma Version:
|
|
||||||
Using Docker?: Yes/No
|
|
||||||
Docker Version:
|
|
||||||
Node.js Version (Without Docker only):
|
|
||||||
OS:
|
|
||||||
Browser:
|
|
68
.github/ISSUE_TEMPLATE/ask-for-help.yaml
vendored
Normal file
68
.github/ISSUE_TEMPLATE/ask-for-help.yaml
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
name: "❓ Ask for help"
|
||||||
|
description: "Submit any question related to Uptime Kuma"
|
||||||
|
#title: "[Help] "
|
||||||
|
labels: [help]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "⚠️ Please verify that this bug has NOT been raised before."
|
||||||
|
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)"
|
||||||
|
options:
|
||||||
|
- label: "I checked and didn't find similar issue"
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: "🛡️ Security Policy"
|
||||||
|
description: Please review the security policy before reporting security related issues/bugs.
|
||||||
|
options:
|
||||||
|
- label: I agree to have read this project [Security Policy](https://github.com/louislam/uptime-kuma/security/policy)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: steps-to-reproduce
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "📝 Describe your problem"
|
||||||
|
description: "Please walk us through it step by step."
|
||||||
|
placeholder: "Describe what are you asking for..."
|
||||||
|
- type: input
|
||||||
|
id: uptime-kuma-version
|
||||||
|
attributes:
|
||||||
|
label: "🐻 Uptime-Kuma Version"
|
||||||
|
description: "Which version of Uptime-Kuma are you running? Please do NOT provide the docker tag such as latest or 1"
|
||||||
|
placeholder: "Ex. 1.10.0"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: operating-system
|
||||||
|
attributes:
|
||||||
|
label: "💻 Operating System and Arch"
|
||||||
|
description: "Which OS is your server/device running on?"
|
||||||
|
placeholder: "Ex. Ubuntu 20.04 x86"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: browser-vendor
|
||||||
|
attributes:
|
||||||
|
label: "🌐 Browser"
|
||||||
|
description: "Which browser are you running on?"
|
||||||
|
placeholder: "Ex. Google Chrome 95.0.4638.69"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: docker-version
|
||||||
|
attributes:
|
||||||
|
label: "🐋 Docker Version"
|
||||||
|
description: "If running with Docker, which version are you running?"
|
||||||
|
placeholder: "Ex. Docker 20.10.9 / K8S / Podman"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: input
|
||||||
|
id: nodejs-version
|
||||||
|
attributes:
|
||||||
|
label: "🟩 NodeJS Version"
|
||||||
|
description: "If running with Node.js? which version are you running?"
|
||||||
|
placeholder: "Ex. 14.18.0"
|
||||||
|
validations:
|
||||||
|
required: false
|
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is it a duplicate question?**
|
|
||||||
Please search in Issues without filters: https://github.com/louislam/uptime-kuma/issues?q=
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Info**
|
|
||||||
Uptime Kuma Version:
|
|
||||||
Using Docker?: Yes/No
|
|
||||||
Docker Version:
|
|
||||||
Node.js Version (Without Docker only):
|
|
||||||
OS:
|
|
||||||
Browser:
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Error Log**
|
|
||||||
It is easier for us to find out the problem.
|
|
||||||
|
|
||||||
Docker: `docker logs <container id>`
|
|
||||||
PM2: `~/.pm2/logs/` (e.g. `/home/ubuntu/.pm2/logs`)
|
|
99
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
99
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
name: "🐛 Bug Report"
|
||||||
|
description: "Submit a bug report to help us improve"
|
||||||
|
#title: "[Bug] "
|
||||||
|
labels: [bug]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "⚠️ Please verify that this bug has NOT been raised before."
|
||||||
|
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)"
|
||||||
|
options:
|
||||||
|
- label: "I checked and didn't find similar issue"
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: "🛡️ Security Policy"
|
||||||
|
description: Please review the security policy before reporting security related issues/bugs.
|
||||||
|
options:
|
||||||
|
- label: I agree to have read this project [Security Policy](https://github.com/louislam/uptime-kuma/security/policy)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "Description"
|
||||||
|
description: "You could also upload screenshots"
|
||||||
|
- type: textarea
|
||||||
|
id: steps-to-reproduce
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "👟 Reproduction steps"
|
||||||
|
description: "How do you trigger this bug? Please walk us through it step by step."
|
||||||
|
placeholder: "..."
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "👀 Expected behavior"
|
||||||
|
description: "What did you think would happen?"
|
||||||
|
placeholder: "..."
|
||||||
|
- type: textarea
|
||||||
|
id: actual-behavior
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "😓 Actual Behavior"
|
||||||
|
description: "What actually happen?"
|
||||||
|
placeholder: "..."
|
||||||
|
- type: input
|
||||||
|
id: uptime-kuma-version
|
||||||
|
attributes:
|
||||||
|
label: "🐻 Uptime-Kuma Version"
|
||||||
|
description: "Which version of Uptime-Kuma are you running? Please do NOT provide the docker tag such as latest or 1"
|
||||||
|
placeholder: "Ex. 1.10.0"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: operating-system
|
||||||
|
attributes:
|
||||||
|
label: "💻 Operating System and Arch"
|
||||||
|
description: "Which OS is your server/device running on?"
|
||||||
|
placeholder: "Ex. Ubuntu 20.04 x86"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: browser-vendor
|
||||||
|
attributes:
|
||||||
|
label: "🌐 Browser"
|
||||||
|
description: "Which browser are you running on?"
|
||||||
|
placeholder: "Ex. Google Chrome 95.0.4638.69"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: docker-version
|
||||||
|
attributes:
|
||||||
|
label: "🐋 Docker Version"
|
||||||
|
description: "If running with Docker, which version are you running?"
|
||||||
|
placeholder: "Ex. Docker 20.10.9 / K8S / Podman"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: input
|
||||||
|
id: nodejs-version
|
||||||
|
attributes:
|
||||||
|
label: "🟩 NodeJS Version"
|
||||||
|
description: "If running with Node.js? which version are you running?"
|
||||||
|
placeholder: "Ex. 14.18.0"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: "📝 Relevant log output"
|
||||||
|
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: false
|
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: ''
|
|
||||||
labels: enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
**Is it a duplicate question?**
|
|
||||||
Please search in Issues without filters: https://github.com/louislam/uptime-kuma/issues?q=
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
59
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
name: 🚀 Feature Request
|
||||||
|
description: "Submit a proposal for a new feature"
|
||||||
|
#title: "[Feature] "
|
||||||
|
labels: [feature-request]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "⚠️ Please verify that this feature request has NOT been suggested before."
|
||||||
|
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)"
|
||||||
|
options:
|
||||||
|
- label: "I checked and didn't find similar feature request"
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: feature-area
|
||||||
|
attributes:
|
||||||
|
label: "🏷️ Feature Request Type"
|
||||||
|
description: "What kind of feature request is this?"
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- API
|
||||||
|
- New Notification
|
||||||
|
- New Monitor
|
||||||
|
- UI Feature
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: feature-description
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "🔖 Feature description"
|
||||||
|
description: "A clear and concise description of what the feature request is."
|
||||||
|
placeholder: "You should add ..."
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "✔️ Solution"
|
||||||
|
description: "A clear and concise description of what you want to happen."
|
||||||
|
placeholder: "In my use-case, ..."
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "❓ Alternatives"
|
||||||
|
description: "A clear and concise description of any alternative solutions or features you've considered."
|
||||||
|
placeholder: "I have considered ..."
|
||||||
|
- type: textarea
|
||||||
|
id: additional-context
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "📝 Additional Context"
|
||||||
|
description: "Add any other context or screenshots about the feature request here."
|
||||||
|
placeholder: "..."
|
28
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
28
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Description
|
||||||
|
|
||||||
|
Fixes #(issue)
|
||||||
|
|
||||||
|
## Type of change
|
||||||
|
|
||||||
|
Please delete options that are not relevant.
|
||||||
|
|
||||||
|
- Bug fix (non-breaking change which fixes an issue)
|
||||||
|
- User Interface
|
||||||
|
- 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
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] My code follows the style guidelines of this project
|
||||||
|
- [ ] I ran ESLint and other linters for modified files
|
||||||
|
- [ ] I have performed a self-review of my own code and test it
|
||||||
|
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||||
|
- [ ] My changes generate no new warnings
|
||||||
|
- [ ] My code needed automated testing. I have added them (this is optional task)
|
||||||
|
|
||||||
|
## Screenshots (if any)
|
||||||
|
|
||||||
|
Please do not use any external image service. Instead, just paste in or drag and drop the image here and it will be uploaded automatically.
|
2
.github/workflows/auto-test.yml
vendored
2
.github/workflows/auto-test.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||||
node-version: [14.x, 16.x]
|
node-version: [14.x, 16.x, 17.x]
|
||||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
22
.github/workflows/stale-bot.yml
vendored
Normal file
22
.github/workflows/stale-bot.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: 'Automatically close stale issues and PRs'
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
#Run once a day at midnight
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v4
|
||||||
|
with:
|
||||||
|
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
||||||
|
stale-pr-message: 'We are clearing up our old Pull Requests and yours has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
||||||
|
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
|
||||||
|
close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
|
||||||
|
days-before-stale: 180
|
||||||
|
days-before-close: 7
|
||||||
|
exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,'
|
||||||
|
exempt-pr-labels: 'awaiting-approval,work-in-progress,enhancement,'
|
||||||
|
exempt-issue-assignees: 'louislam'
|
||||||
|
exempt-pr-assignees: 'louislam'
|
@@ -60,7 +60,7 @@ representative at an online or offline event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement at
|
reported to the community leaders responsible for enforcement at
|
||||||
louis@uptimekuma.louislam.net.
|
uptime@kuma.pet.
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
130
CONTRIBUTING.md
130
CONTRIBUTING.md
@@ -6,7 +6,7 @@ The project was created with vite.js (vue3). Then I created a sub-directory call
|
|||||||
|
|
||||||
The frontend code build into "dist" directory. The server (express.js) exposes the "dist" directory as root of the endpoint. This is how production is working.
|
The frontend code build into "dist" directory. The server (express.js) exposes the "dist" directory as root of the endpoint. This is how production is working.
|
||||||
|
|
||||||
# Key Technical Skills
|
## Key Technical Skills
|
||||||
|
|
||||||
- Node.js (You should know what are promise, async/await and arrow function etc.)
|
- Node.js (You should know what are promise, async/await and arrow function etc.)
|
||||||
- Socket.io
|
- Socket.io
|
||||||
@@ -15,7 +15,7 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
|
|||||||
- Bootstrap
|
- Bootstrap
|
||||||
- SQLite
|
- SQLite
|
||||||
|
|
||||||
# Directories
|
## Directories
|
||||||
|
|
||||||
- data (App data)
|
- data (App data)
|
||||||
- dist (Frontend build)
|
- dist (Frontend build)
|
||||||
@@ -25,50 +25,80 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
|
|||||||
- src (Frontend source code)
|
- src (Frontend source code)
|
||||||
- test (unit test)
|
- test (unit test)
|
||||||
|
|
||||||
# Can I create a pull request for Uptime Kuma?
|
## Can I create a pull request for Uptime Kuma?
|
||||||
|
|
||||||
Generally, if the pull request is working fine and it do not affect any existing logic, workflow and perfomance, I will merge into the master branch once it is tested.
|
Generally, if the pull request is working fine and it do not affect any existing logic, workflow and perfomance, I will merge into the master branch once it is tested.
|
||||||
|
|
||||||
If you are not sure, feel free to create an empty pull request draft first.
|
If you are not sure whether I will accept your pull request, feel free to create an empty pull request draft first.
|
||||||
|
|
||||||
## Pull Request Examples
|
|
||||||
|
|
||||||
### ✅ High - Medium Priority
|
### Recommended Pull Request Guideline
|
||||||
|
|
||||||
|
1. Fork the project
|
||||||
|
1. Clone your fork repo to local
|
||||||
|
1. Create a new branch
|
||||||
|
1. Create an empty commit
|
||||||
|
`git commit -m "[empty commit] pull request for <YOUR TASK NAME>" --allow-empty`
|
||||||
|
1. Push to your fork repo
|
||||||
|
1. Create a pull request: https://github.com/louislam/uptime-kuma/compare
|
||||||
|
1. Write a proper description
|
||||||
|
1. Click "Change to draft"
|
||||||
|
|
||||||
|
### Pull Request Examples
|
||||||
|
|
||||||
|
Here are some example situations in the past.
|
||||||
|
|
||||||
|
#### ✅ High - Medium Priority
|
||||||
|
|
||||||
|
Easy to review, no breaking change and not touching the existing code
|
||||||
|
|
||||||
- Add a new notification
|
- Add a new notification
|
||||||
- Add a chart
|
- Add a chart
|
||||||
- Fix a bug
|
- Fix a bug
|
||||||
- Translations
|
- Translations
|
||||||
|
- Add a independent new feature
|
||||||
|
|
||||||
### *️⃣ Requires one more reviewer
|
#### *️⃣ Requires one more reviewer
|
||||||
|
|
||||||
I do not have such knowledge to test it.
|
I do not have such knowledge to test it.
|
||||||
|
|
||||||
- Add k8s supports
|
- Add k8s supports
|
||||||
|
|
||||||
### *️⃣ Low Priority
|
#### ⚠ Low Priority - Harsh Mode
|
||||||
|
|
||||||
|
Some pull requests are required to modifiy the core. To be honest, I do not want anyone to try to do that, because it would spend a lot of your time. I will review your pull request harshly. Also you may need to write a lot of unit tests to ensure that there is no breaking change.
|
||||||
|
|
||||||
|
- Touch large parts of code of any very important features
|
||||||
|
- Touch monitoring logic
|
||||||
|
- Drop a table or drop a column for any reason
|
||||||
|
- Touch the entry point of Docker or Node.js
|
||||||
|
- Modifiy auth
|
||||||
|
|
||||||
|
|
||||||
|
#### *️⃣ Low Priority
|
||||||
|
|
||||||
It changed my current workflow and require further studies.
|
It changed my current workflow and require further studies.
|
||||||
|
|
||||||
- Change my release approach
|
- Change my release approach
|
||||||
|
|
||||||
### ❌ Won't Merge
|
#### ❌ Won't Merge
|
||||||
|
|
||||||
|
- Any breaking changes
|
||||||
- Duplicated pull request
|
- Duplicated pull request
|
||||||
- Buggy
|
- Buggy
|
||||||
- Existing logic is completely modified or deleted
|
- Existing logic is completely modified or deleted
|
||||||
- A function that is completely out of scope
|
- A function that is completely out of scope
|
||||||
|
|
||||||
# Project Styles
|
## 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 need to learn so much and need to config so much before you can finally start the 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 (at least for x86_64), no extra config, no extra effort to get it run
|
||||||
- Single container for Docker users, no very complex docker-composer file. Just map the volume and expose the port, then good to go
|
- 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. Env var is not encouraged.
|
- Settings should be configurable in the frontend. Env var is not encouraged.
|
||||||
- Easy to use
|
- Easy to use
|
||||||
|
|
||||||
# Coding Styles
|
## Coding Styles
|
||||||
|
|
||||||
- 4 spaces indentation
|
- 4 spaces indentation
|
||||||
- Follow `.editorconfig`
|
- Follow `.editorconfig`
|
||||||
@@ -80,20 +110,20 @@ I personally do not like something need to learn so much and need to config so m
|
|||||||
- SQLite: underscore_type
|
- SQLite: underscore_type
|
||||||
- CSS/SCSS: dash-type
|
- CSS/SCSS: dash-type
|
||||||
|
|
||||||
# Tools
|
## Tools
|
||||||
|
|
||||||
- Node.js >= 14
|
- Node.js >= 14
|
||||||
- Git
|
- Git
|
||||||
- IDE that supports ESLint and EditorConfig (I am using Intellji Idea)
|
- IDE that supports ESLint and EditorConfig (I am using Intellji Idea)
|
||||||
- A SQLite tool (SQLite Expert Personal is suggested)
|
- A SQLite tool (SQLite Expert Personal is suggested)
|
||||||
|
|
||||||
# Install dependencies
|
## Install dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm ci
|
npm ci
|
||||||
```
|
```
|
||||||
|
|
||||||
# How to start the Backend Dev Server
|
## How to start the Backend Dev Server
|
||||||
|
|
||||||
(2021-09-23 Update)
|
(2021-09-23 Update)
|
||||||
|
|
||||||
@@ -103,7 +133,7 @@ npm run start-server-dev
|
|||||||
|
|
||||||
It binds to `0.0.0.0:3001` by default.
|
It binds to `0.0.0.0:3001` by default.
|
||||||
|
|
||||||
## Backend Details
|
### Backend Details
|
||||||
|
|
||||||
It is mainly a socket.io app + express.js.
|
It is mainly a socket.io app + express.js.
|
||||||
|
|
||||||
@@ -116,24 +146,26 @@ express.js is just used for serving the frontend built files (index.html, .js an
|
|||||||
- scoket-handler (Socket.io Handlers)
|
- scoket-handler (Socket.io Handlers)
|
||||||
- server.js (Server main logic)
|
- server.js (Server main logic)
|
||||||
|
|
||||||
# How to start the Frontend Dev Server
|
## How to start the Frontend Dev Server
|
||||||
|
|
||||||
1. Set the env var `NODE_ENV` to "development".
|
1. Set the env var `NODE_ENV` to "development".
|
||||||
2. Start the frontend dev server by the following command.
|
2. Start the frontend dev server by the following command.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
It binds to `0.0.0.0:3000` by default.
|
It binds to `0.0.0.0:3000` by default.
|
||||||
|
|
||||||
You can use Vue.js devtools Chrome extension for debugging.
|
You can use Vue.js devtools Chrome extension for debugging.
|
||||||
|
|
||||||
## Build the frontend
|
### Build the frontend
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Frontend Details
|
### Frontend Details
|
||||||
|
|
||||||
Uptime Kuma Frontend is a single page application (SPA). Most paths are handled by Vue Router.
|
Uptime Kuma Frontend is a single page application (SPA). Most paths are handled by Vue Router.
|
||||||
|
|
||||||
@@ -143,24 +175,23 @@ As you can see, most data in frontend is stored in root level, even though you c
|
|||||||
|
|
||||||
The data and socket logic are in `src/mixins/socket.js`.
|
The data and socket logic are in `src/mixins/socket.js`.
|
||||||
|
|
||||||
|
## Database Migration
|
||||||
# Database Migration
|
|
||||||
|
|
||||||
1. Create `patch-{name}.sql` in `./db/`
|
1. Create `patch-{name}.sql` in `./db/`
|
||||||
2. Add your patch filename in the `patchList` list in `./server/database.js`
|
2. Add your patch filename in the `patchList` list in `./server/database.js`
|
||||||
|
|
||||||
# Unit Test
|
## Unit Test
|
||||||
|
|
||||||
It is an end-to-end testing. It is using Jest and Puppeteer.
|
It is an end-to-end testing. It is using Jest and Puppeteer.
|
||||||
|
|
||||||
```
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, the Chromium window will be shown up during the test. Specifying `HEADLESS_TEST=1` for terminal environments.
|
By default, the Chromium window will be shown up during the test. Specifying `HEADLESS_TEST=1` for terminal environments.
|
||||||
|
|
||||||
# Update Dependencies
|
## Update Dependencies
|
||||||
|
|
||||||
Install `ncu`
|
Install `ncu`
|
||||||
https://github.com/raineorshine/npm-check-updates
|
https://github.com/raineorshine/npm-check-updates
|
||||||
@@ -170,10 +201,55 @@ ncu -u -t patch
|
|||||||
npm install
|
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.
|
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
|
Patch release = the third digit ([Semantic Versioning](https://semver.org/))
|
||||||
|
|
||||||
# Translations
|
## Translations
|
||||||
|
|
||||||
Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
|
Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
|
||||||
|
|
||||||
|
|
||||||
|
## Wiki
|
||||||
|
|
||||||
|
Since there is no way to make a pull request to wiki's repo, I have setup another repo to do that.
|
||||||
|
|
||||||
|
https://github.com/louislam/uptime-kuma-wiki
|
||||||
|
|
||||||
|
|
||||||
|
## Maintainer
|
||||||
|
|
||||||
|
Check the latest issues and pull requests:
|
||||||
|
https://github.com/louislam/uptime-kuma/issues?q=sort%3Aupdated-desc
|
||||||
|
|
||||||
|
### Release Procedures
|
||||||
|
1. Draft a release note
|
||||||
|
1. Make sure the repo is cleared
|
||||||
|
1. `npm run update-version 1.X.X`
|
||||||
|
1. `npm run build`
|
||||||
|
1. `npm run build-docker`
|
||||||
|
1. `git push`
|
||||||
|
1. Publish the release note as 1.X.X
|
||||||
|
1. `npm run upload-artifacts`
|
||||||
|
1. SSH to demo site server and update to 1.X.X
|
||||||
|
|
||||||
|
Checking:
|
||||||
|
- Check all tags is fine on https://hub.docker.com/r/louislam/uptime-kuma/tags
|
||||||
|
- Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 / armv7)
|
||||||
|
- Try clean install with Node.js
|
||||||
|
|
||||||
|
### Release Wiki
|
||||||
|
|
||||||
|
#### Setup Repo
|
||||||
|
```
|
||||||
|
git clone https://github.com/louislam/uptime-kuma-wiki.git
|
||||||
|
cd uptime-kuma-wiki
|
||||||
|
git remote add production https://github.com/louislam/uptime-kuma.wiki.git
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Push to Production Wiki
|
||||||
|
```
|
||||||
|
git pull
|
||||||
|
git push production master
|
||||||
|
```
|
||||||
|
|
||||||
|
27
README.md
27
README.md
@@ -1,7 +1,7 @@
|
|||||||
# Uptime Kuma
|
# 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=Backers&color=brightgreen" /></a>
|
<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)
|
||||||
|
|
||||||
<div align="center" width="100%">
|
<div align="center" width="100%">
|
||||||
<img src="./public/icon.svg" width="128" alt="" />
|
<img src="./public/icon.svg" width="128" alt="" />
|
||||||
@@ -17,17 +17,20 @@ Try it!
|
|||||||
|
|
||||||
https://demo.uptime.kuma.pet
|
https://demo.uptime.kuma.pet
|
||||||
|
|
||||||
It is a 5 minutes live demo, all data will be deleted after that. The server is located at Tokyo, if you live far away from here, it may affact your experience. I suggest that you should install to try it.
|
It is a temporary live demo, all data will be deleted after 10 minutes. The server is located at Tokyo, so if you live far from there it may affect your experience. I suggest that you should install and try it out for the best demo experience.
|
||||||
|
|
||||||
VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollective.com/uptime-kuma)! Thank you so much!
|
VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollective.com/uptime-kuma)! Thank you so much!
|
||||||
|
|
||||||
## ⭐ Features
|
## ⭐ Features
|
||||||
|
|
||||||
* Monitoring uptime for HTTP(s) / TCP / Ping / DNS Record.
|
* Monitoring uptime for HTTP(s) / TCP / Ping / DNS Record / Push.
|
||||||
* Fancy, Reactive, Fast UI/UX.
|
* Fancy, Reactive, Fast UI/UX.
|
||||||
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [70+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/issues/284).
|
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [70+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications).
|
||||||
* 20 seconds interval.
|
* 20 second intervals.
|
||||||
* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/languages)
|
* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/languages)
|
||||||
|
* Simple Status Page
|
||||||
|
* Ping Chart
|
||||||
|
* Certificate Info
|
||||||
|
|
||||||
## 🔧 How to Install
|
## 🔧 How to Install
|
||||||
|
|
||||||
@@ -38,9 +41,9 @@ docker volume create uptime-kuma
|
|||||||
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
|
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
|
||||||
```
|
```
|
||||||
|
|
||||||
Browse to http://localhost:3001 after started.
|
Browse to http://localhost:3001 after starting.
|
||||||
|
|
||||||
### 💪🏻 Without Docker
|
### 💪🏻 Non-Docker
|
||||||
|
|
||||||
Required Tools: Node.js >= 14, git and pm2.
|
Required Tools: Node.js >= 14, git and pm2.
|
||||||
|
|
||||||
@@ -56,11 +59,11 @@ npm run setup
|
|||||||
node server/server.js
|
node server/server.js
|
||||||
|
|
||||||
# (Recommended) Option 2. Run in background using PM2
|
# (Recommended) Option 2. Run in background using PM2
|
||||||
# Install PM2 if you don't have: npm install pm2 -g
|
# Install PM2 if you don't have it: npm install pm2 -g
|
||||||
pm2 start server/server.js --name uptime-kuma
|
pm2 start server/server.js --name uptime-kuma
|
||||||
```
|
```
|
||||||
|
|
||||||
Browse to http://localhost:3001 after started.
|
Browse to http://localhost:3001 after starting.
|
||||||
|
|
||||||
### Advanced Installation
|
### Advanced Installation
|
||||||
|
|
||||||
@@ -116,11 +119,13 @@ If you love this project, please consider giving me a ⭐.
|
|||||||
## 🗣️ Discussion
|
## 🗣️ Discussion
|
||||||
|
|
||||||
### Issues Page
|
### Issues Page
|
||||||
|
|
||||||
You can discuss or ask for help in [Issues](https://github.com/louislam/uptime-kuma/issues).
|
You can discuss or ask for help in [Issues](https://github.com/louislam/uptime-kuma/issues).
|
||||||
|
|
||||||
### Subreddit
|
### Subreddit
|
||||||
|
|
||||||
My Reddit account: louislamlam
|
My Reddit account: louislamlam
|
||||||
You can mention me if you ask question on Reddit.
|
You can mention me if you ask a question on Reddit.
|
||||||
https://www.reddit.com/r/UptimeKuma/
|
https://www.reddit.com/r/UptimeKuma/
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
21
SECURITY.md
21
SECURITY.md
@@ -1,17 +1,25 @@
|
|||||||
# Security Policy
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Please report security issues to uptime@kuma.pet.
|
||||||
|
|
||||||
|
Do not use the issue tracker or discuss it in the public as it will cause more damage.
|
||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
Use this section to tell people about which versions of your project are
|
Use this section to tell people about which versions of your project are
|
||||||
currently being supported with security updates.
|
currently being supported with security updates.
|
||||||
|
|
||||||
#### Uptime Kuma Versions:
|
### Uptime Kuma Versions
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
| 1.7.X | :white_check_mark: |
|
| 1.9.X | :white_check_mark: |
|
||||||
| < 1.7 | ❌ |
|
| <= 1.8.X | ❌ |
|
||||||
|
|
||||||
|
### Upgradable Docker Tags
|
||||||
|
|
||||||
#### Upgradable Docker Tags:
|
|
||||||
| Tag | Supported |
|
| Tag | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
| 1 | :white_check_mark: |
|
| 1 | :white_check_mark: |
|
||||||
@@ -21,8 +29,3 @@ currently being supported with security updates.
|
|||||||
| debian | :white_check_mark: |
|
| debian | :white_check_mark: |
|
||||||
| alpine | :white_check_mark: |
|
| alpine | :white_check_mark: |
|
||||||
| All other tags | ❌ |
|
| All other tags | ❌ |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
Please report security issues to uptime@kuma.pet.
|
|
||||||
|
|
||||||
Do not use the issue tracker or discuss it in the public as it will cause more damage.
|
|
||||||
|
@@ -4,4 +4,8 @@ if (process.env.TEST_FRONTEND) {
|
|||||||
config.presets = ["@babel/preset-env"];
|
config.presets = ["@babel/preset-env"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.TEST_BACKEND) {
|
||||||
|
config.plugins = ["babel-plugin-rewire"];
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
5
config/jest-backend.config.js
Normal file
5
config/jest-backend.config.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
"rootDir": "..",
|
||||||
|
"testRegex": "./test/backend.spec.js",
|
||||||
|
};
|
||||||
|
|
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
"rootDir": ".",
|
"rootDir": "..",
|
||||||
"testRegex": "./test/frontend.spec.js",
|
"testRegex": "./test/frontend.spec.js",
|
||||||
};
|
};
|
||||||
|
|
@@ -5,7 +5,7 @@ module.exports = {
|
|||||||
"__DEV__": true
|
"__DEV__": true
|
||||||
},
|
},
|
||||||
"testRegex": "./test/e2e.spec.js",
|
"testRegex": "./test/e2e.spec.js",
|
||||||
"rootDir": ".",
|
"rootDir": "..",
|
||||||
"testTimeout": 30000,
|
"testTimeout": 30000,
|
||||||
};
|
};
|
||||||
|
|
@@ -1,9 +1,9 @@
|
|||||||
import legacy from "@vitejs/plugin-legacy"
|
import legacy from "@vitejs/plugin-legacy";
|
||||||
import vue from "@vitejs/plugin-vue"
|
import vue from "@vitejs/plugin-vue";
|
||||||
import { defineConfig } from "vite"
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
const postCssScss = require("postcss-scss")
|
const postCssScss = require("postcss-scss");
|
||||||
const postcssRTLCSS = require('postcss-rtlcss');
|
const postcssRTLCSS = require("postcss-rtlcss");
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -20,5 +20,5 @@ export default defineConfig({
|
|||||||
"map": false,
|
"map": false,
|
||||||
"plugins": [postcssRTLCSS]
|
"plugins": [postcssRTLCSS]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
});
|
7
db/patch-2fa-invalidate-used-token.sql
Normal file
7
db/patch-2fa-invalidate-used-token.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE user
|
||||||
|
ADD twofa_last_token VARCHAR(6);
|
||||||
|
|
||||||
|
COMMIT;
|
13
db/patch-http-monitor-method-body-and-headers.sql
Normal file
13
db/patch-http-monitor-method-body-and-headers.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD method TEXT default 'GET' not null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD body TEXT default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD headers TEXT default null;
|
||||||
|
|
||||||
|
COMMIT;
|
18
db/patch-notification_sent_history.sql
Normal file
18
db/patch-notification_sent_history.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TABLE [notification_sent_history] (
|
||||||
|
[id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
[type] VARCHAR(50) NOT NULL,
|
||||||
|
[monitor_id] INTEGER NOT NULL,
|
||||||
|
[days] INTEGER NOT NULL,
|
||||||
|
UNIQUE([type], [monitor_id], [days])
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX [good_index] ON [notification_sent_history] (
|
||||||
|
[type],
|
||||||
|
[monitor_id],
|
||||||
|
[days]
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
@@ -4,9 +4,7 @@ WORKDIR /app
|
|||||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
|
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm ci && \
|
RUN npm ci --production && \
|
||||||
npm run build && \
|
|
||||||
npm prune --production && \
|
|
||||||
chmod +x /app/extra/entrypoint.sh
|
chmod +x /app/extra/entrypoint.sh
|
||||||
|
|
||||||
|
|
||||||
@@ -22,23 +20,26 @@ HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD nod
|
|||||||
ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"]
|
||||||
CMD ["node", "server/server.js"]
|
CMD ["node", "server/server.js"]
|
||||||
|
|
||||||
|
|
||||||
FROM release AS nightly
|
FROM release AS nightly
|
||||||
RUN npm run mark-as-nightly
|
RUN npm run mark-as-nightly
|
||||||
|
|
||||||
|
|
||||||
# Upload the artifact to Github
|
# Upload the artifact to Github
|
||||||
FROM louislam/uptime-kuma:base-debian AS upload-artifact
|
FROM louislam/uptime-kuma:base-debian AS upload-artifact
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
apt --yes install curl file
|
apt --yes install curl file
|
||||||
|
|
||||||
|
COPY --from=build /app /app
|
||||||
|
|
||||||
|
ARG VERSION=1.9.1
|
||||||
ARG GITHUB_TOKEN
|
ARG GITHUB_TOKEN
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG PLATFORM=debian
|
ARG PLATFORM=debian
|
||||||
ARG VERSION
|
|
||||||
ARG FILE=$PLATFORM-$TARGETARCH-$VERSION.tar.gz
|
ARG FILE=$PLATFORM-$TARGETARCH-$VERSION.tar.gz
|
||||||
ARG DIST=dist.tar.gz
|
ARG DIST=dist.tar.gz
|
||||||
|
|
||||||
COPY --from=build /app /app
|
|
||||||
RUN chmod +x /app/extra/upload-github-release-asset.sh
|
RUN chmod +x /app/extra/upload-github-release-asset.sh
|
||||||
|
|
||||||
# Full Build
|
# Full Build
|
||||||
@@ -47,5 +48,5 @@ RUN chmod +x /app/extra/upload-github-release-asset.sh
|
|||||||
|
|
||||||
# Dist only
|
# Dist only
|
||||||
RUN cd /app && tar -zcvf $DIST dist
|
RUN cd /app && tar -zcvf $DIST dist
|
||||||
RUN /app/extra/upload-github-release-asset.sh github_api_token=$GITHUB_TOKEN owner=louislam repo=uptime-kuma tag=$VERSION filename=$DIST
|
RUN /app/extra/upload-github-release-asset.sh github_api_token=$GITHUB_TOKEN owner=louislam repo=uptime-kuma tag=$VERSION filename=/app/$DIST
|
||||||
|
|
@@ -4,9 +4,7 @@ WORKDIR /app
|
|||||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
|
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm ci && \
|
RUN npm ci --production && \
|
||||||
npm run build && \
|
|
||||||
npm prune --production && \
|
|
||||||
chmod +x /app/extra/entrypoint.sh
|
chmod +x /app/extra/entrypoint.sh
|
||||||
|
|
||||||
|
|
||||||
@@ -22,5 +20,6 @@ HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD nod
|
|||||||
ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"]
|
||||||
CMD ["node", "server/server.js"]
|
CMD ["node", "server/server.js"]
|
||||||
|
|
||||||
|
|
||||||
FROM release AS nightly
|
FROM release AS nightly
|
||||||
RUN npm run mark-as-nightly
|
RUN npm run mark-as-nightly
|
6
ecosystem.config.js
Normal file
6
ecosystem.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [{
|
||||||
|
name: "uptime-kuma",
|
||||||
|
script: "./server/server.js",
|
||||||
|
}]
|
||||||
|
}
|
@@ -34,9 +34,11 @@ function download(url) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
tarStream.on("close", () => {
|
tarStream.on("close", () => {
|
||||||
fs.rmdirSync("./dist-backup", {
|
if (fs.existsSync("./dist-backup")) {
|
||||||
recursive: true
|
fs.rmdirSync("./dist-backup", {
|
||||||
});
|
recursive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
console.log("Done");
|
console.log("Done");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@ function download(url) {
|
|||||||
if (fs.existsSync("./dist-backup")) {
|
if (fs.existsSync("./dist-backup")) {
|
||||||
fs.renameSync("./dist-backup", "./dist");
|
fs.renameSync("./dist-backup", "./dist");
|
||||||
}
|
}
|
||||||
console.log("Done");
|
console.error("Error from tarStream");
|
||||||
});
|
});
|
||||||
|
|
||||||
response.pipe(tarStream);
|
response.pipe(tarStream);
|
||||||
|
@@ -1,25 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This script should be run after a period of time (180s), because the server may need some time to prepare.
|
* 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");
|
||||||
|
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
|
|
||||||
let client;
|
let client;
|
||||||
|
|
||||||
if (process.env.SSL_KEY && process.env.SSL_CERT) {
|
const sslKey = process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined;
|
||||||
|
const sslCert = process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined;
|
||||||
|
|
||||||
|
if (sslKey && sslCert) {
|
||||||
client = require("https");
|
client = require("https");
|
||||||
} else {
|
} else {
|
||||||
client = require("http");
|
client = require("http");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Also read HOST if not FreeBSD, 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);
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
host: process.env.HOST || "127.0.0.1",
|
host: hostname || "127.0.0.1",
|
||||||
port: parseInt(process.env.PORT) || 3001,
|
port: port,
|
||||||
timeout: 28 * 1000,
|
timeout: 28 * 1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
let request = client.request(options, (res) => {
|
let request = client.request(options, (res) => {
|
||||||
console.log(`Health Check OK [Res Code: ${res.statusCode}]`);
|
console.log(`Health Check OK [Res Code: ${res.statusCode}]`);
|
||||||
if (res.statusCode === 200) {
|
if (res.statusCode === 302) {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
@@ -12,50 +12,59 @@ const rl = readline.createInterface({
|
|||||||
output: process.stdout
|
output: process.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
const main = async () => {
|
||||||
Database.init(args);
|
Database.init(args);
|
||||||
await Database.connect();
|
await Database.connect();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const user = await R.findOne("user");
|
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
|
||||||
|
if (!process.env.TEST_BACKEND) {
|
||||||
if (! user) {
|
const user = await R.findOne("user");
|
||||||
throw new Error("user not found, have you installed?");
|
if (! user) {
|
||||||
}
|
throw new Error("user not found, have you installed?");
|
||||||
|
|
||||||
console.log("Found user: " + user.username);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
let password = await question("New Password: ");
|
|
||||||
let confirmPassword = await question("Confirm New Password: ");
|
|
||||||
|
|
||||||
if (password === confirmPassword) {
|
|
||||||
await user.resetPassword(password);
|
|
||||||
|
|
||||||
// Reset all sessions by reset jwt secret
|
|
||||||
await initJWTSecret();
|
|
||||||
|
|
||||||
rl.close();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
console.log("Passwords do not match, please try again.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Password reset successfully.");
|
console.log("Found user: " + user.username);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
let password = await question("New Password: ");
|
||||||
|
let confirmPassword = await question("Confirm New Password: ");
|
||||||
|
|
||||||
|
if (password === confirmPassword) {
|
||||||
|
await user.resetPassword(password);
|
||||||
|
|
||||||
|
// Reset all sessions by reset jwt secret
|
||||||
|
await initJWTSecret();
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
console.log("Passwords do not match, please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("Password reset successfully.");
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error: " + e.message);
|
console.error("Error: " + e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Database.close();
|
await Database.close();
|
||||||
|
rl.close();
|
||||||
|
|
||||||
console.log("Finished. You should restart the Uptime Kuma server.")
|
console.log("Finished.");
|
||||||
})();
|
};
|
||||||
|
|
||||||
function question(question) {
|
function question(question) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
rl.question(question, (answer) => {
|
rl.question(question, (answer) => {
|
||||||
resolve(answer);
|
resolve(answer);
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!process.env.TEST_BACKEND) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
main,
|
||||||
|
};
|
||||||
|
@@ -26,10 +26,12 @@ const copyRecursiveSync = function (src, dest) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("Arguments:", process.argv)
|
console.log("Arguments:", process.argv);
|
||||||
const baseLangCode = process.argv[2] || "en";
|
const baseLangCode = process.argv[2] || "en";
|
||||||
console.log("Base Lang: " + baseLangCode);
|
console.log("Base Lang: " + baseLangCode);
|
||||||
fs.rmdirSync("./languages", { recursive: true });
|
if (fs.existsSync("./languages")) {
|
||||||
|
fs.rmdirSync("./languages", { recursive: true });
|
||||||
|
}
|
||||||
copyRecursiveSync("../../src/languages", "./languages");
|
copyRecursiveSync("../../src/languages", "./languages");
|
||||||
|
|
||||||
const en = (await import("./languages/en.js")).default;
|
const en = (await import("./languages/en.js")).default;
|
||||||
@@ -39,7 +41,7 @@ console.log("Files:", files);
|
|||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if (!file.endsWith(".js")) {
|
if (!file.endsWith(".js")) {
|
||||||
console.log("Skipping " + file)
|
console.log("Skipping " + file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||||
<link rel="manifest" href="manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<meta name="theme-color" id="theme-color" content="" />
|
<meta name="theme-color" id="theme-color" content="" />
|
||||||
<meta name="description" content="Uptime Kuma monitoring tool" />
|
<meta name="description" content="Uptime Kuma monitoring tool" />
|
||||||
<title>Uptime Kuma</title>
|
<title>Uptime Kuma</title>
|
||||||
|
@@ -1,32 +0,0 @@
|
|||||||
# Uptime-Kuma K8s Deployment
|
|
||||||
|
|
||||||
⚠ Warning: K8s deployment is provided by contributors. I have no experience with K8s and I can't fix error in the future. I only test Docker and Node.js. Use at your own risk.
|
|
||||||
|
|
||||||
## How does it work?
|
|
||||||
|
|
||||||
Kustomize is a tool which builds a complete deployment file for all config elements.
|
|
||||||
You can edit the files in the ```uptime-kuma``` folder except the ```kustomization.yml``` until you know what you're doing.
|
|
||||||
If you want to choose another namespace you can edit the ```kustomization.yml``` in the ```kubernetes```-Folder and change the ```namespace: uptime-kuma``` to something you like.
|
|
||||||
|
|
||||||
It creates a certificate with the specified Issuer and creates the Ingress for the Uptime-Kuma ClusterIP-Service.
|
|
||||||
|
|
||||||
## What do I have to edit?
|
|
||||||
|
|
||||||
You have to edit the ```ingressroute.yml``` to your needs.
|
|
||||||
This ingressroute.yml is for the [nginx-ingress-controller](https://kubernetes.github.io/ingress-nginx/) in combination with the [cert-manager](https://cert-manager.io/).
|
|
||||||
|
|
||||||
- Host
|
|
||||||
- Secrets and secret names
|
|
||||||
- (Cluster)Issuer (optional)
|
|
||||||
- The Version in the Deployment-File
|
|
||||||
- Update:
|
|
||||||
- Change to newer version and run the above commands, it will update the pods one after another
|
|
||||||
|
|
||||||
## How To use
|
|
||||||
|
|
||||||
- Install [kustomize](https://kubectl.docs.kubernetes.io/installation/kustomize/)
|
|
||||||
- Edit files mentioned above to your needs
|
|
||||||
- Run ```kustomize build > apply.yml```
|
|
||||||
- Run ```kubectl apply -f apply.yml```
|
|
||||||
|
|
||||||
Now you should see some k8s magic and Uptime-Kuma should be available at the specified address.
|
|
@@ -1,10 +0,0 @@
|
|||||||
namespace: uptime-kuma
|
|
||||||
namePrefix: uptime-kuma-
|
|
||||||
|
|
||||||
commonLabels:
|
|
||||||
app: uptime-kuma
|
|
||||||
|
|
||||||
bases:
|
|
||||||
- uptime-kuma
|
|
||||||
|
|
||||||
|
|
@@ -1,45 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
component: uptime-kuma
|
|
||||||
name: deployment
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
component: uptime-kuma
|
|
||||||
replicas: 1
|
|
||||||
strategy:
|
|
||||||
type: Recreate
|
|
||||||
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
component: uptime-kuma
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: app
|
|
||||||
image: louislam/uptime-kuma:1
|
|
||||||
ports:
|
|
||||||
- containerPort: 3001
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /app/data
|
|
||||||
name: storage
|
|
||||||
livenessProbe:
|
|
||||||
exec:
|
|
||||||
command:
|
|
||||||
- node
|
|
||||||
- extra/healthcheck.js
|
|
||||||
initialDelaySeconds: 180
|
|
||||||
periodSeconds: 60
|
|
||||||
timeoutSeconds: 30
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /
|
|
||||||
port: 3001
|
|
||||||
scheme: HTTP
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
- name: storage
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: pvc
|
|
@@ -1,39 +0,0 @@
|
|||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
kubernetes.io/ingress.class: nginx
|
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
||||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
|
||||||
nginx.ingress.kubernetes.io/server-snippets: |
|
|
||||||
location / {
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header X-Forwarded-Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_cache_bypass $http_upgrade;
|
|
||||||
}
|
|
||||||
name: ingress
|
|
||||||
spec:
|
|
||||||
tls:
|
|
||||||
- hosts:
|
|
||||||
- example.com
|
|
||||||
secretName: example-com-tls
|
|
||||||
rules:
|
|
||||||
- host: example.com
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: /
|
|
||||||
pathType: Prefix
|
|
||||||
backend:
|
|
||||||
service:
|
|
||||||
name: service
|
|
||||||
port:
|
|
||||||
number: 3001
|
|
@@ -1,5 +0,0 @@
|
|||||||
resources:
|
|
||||||
- deployment.yml
|
|
||||||
- service.yml
|
|
||||||
- ingressroute.yml
|
|
||||||
- pvc.yml
|
|
@@ -1,10 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: pvc
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 4Gi
|
|
@@ -1,13 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: service
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
component: uptime-kuma
|
|
||||||
type: ClusterIP
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 3001
|
|
||||||
targetPort: 3001
|
|
||||||
protocol: TCP
|
|
8464
package-lock.json
generated
8464
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
52
package.json
52
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.8.0",
|
"version": "1.10.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -15,27 +15,28 @@
|
|||||||
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
||||||
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
||||||
"lint": "npm run lint:js && npm run lint:style",
|
"lint": "npm run lint:js && npm run lint:style",
|
||||||
"dev": "vite --host",
|
"dev": "vite --host --config ./config/vite.config.js",
|
||||||
"start": "npm run start-server",
|
"start": "npm run start-server",
|
||||||
"start-server": "node server/server.js",
|
"start-server": "node server/server.js",
|
||||||
"start-server-dev": "cross-env NODE_ENV=development node server/server.js",
|
"start-server-dev": "cross-env NODE_ENV=development node server/server.js",
|
||||||
"build": "vite build",
|
"build": "vite build --config ./config/vite.config.js",
|
||||||
"test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --test",
|
"test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --test",
|
||||||
"test-with-build": "npm run build && npm test",
|
"test-with-build": "npm run build && npm test",
|
||||||
"jest": "node test/prepare-jest.js && npm run jest-frontend && jest ",
|
"jest": "node test/prepare-jest.js && npm run jest-frontend && npm run jest-backend && jest --config=./config/jest.config.js",
|
||||||
"jest-frontend": "cross-env TEST_FRONTEND=1 jest --config=./jest-frontend.config.js",
|
"jest-frontend": "cross-env TEST_FRONTEND=1 jest --config=./config/jest-frontend.config.js",
|
||||||
|
"jest-backend": "cross-env TEST_BACKEND=1 jest --config=./config/jest-backend.config.js",
|
||||||
"tsc": "tsc",
|
"tsc": "tsc",
|
||||||
"vite-preview-dist": "vite preview --host",
|
"vite-preview-dist": "vite preview --host --config ./config/vite.config.js",
|
||||||
"build-docker": "npm run build-docker-debian && npm run build-docker-alpine",
|
"build-docker": "npm run build-docker-debian && npm run build-docker-alpine",
|
||||||
"build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push",
|
"build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push",
|
||||||
"build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push",
|
"build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push",
|
||||||
"build-docker-alpine": "docker buildx build -f dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.8.0-alpine --target release . --push",
|
"build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.10.2-alpine --target release . --push",
|
||||||
"build-docker-debian": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.8.0 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.8.0-debian --target release . --push",
|
"build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.10.2 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.10.2-debian --target release . --push",
|
||||||
"build-docker-nightly": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
|
"build-docker-nightly": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
|
||||||
"build-docker-nightly-alpine": "docker buildx build -f dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push",
|
"build-docker-nightly-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push",
|
||||||
"build-docker-nightly-amd64": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
|
"build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
|
||||||
"upload-artifacts": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
|
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
|
||||||
"setup": "git checkout 1.8.0 && npm ci --production && npm run download-dist",
|
"setup": "git checkout 1.10.2 && npm ci --production && npm run download-dist",
|
||||||
"download-dist": "node extra/download-dist.js",
|
"download-dist": "node extra/download-dist.js",
|
||||||
"update-version": "node extra/update-version.js",
|
"update-version": "node extra/update-version.js",
|
||||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||||
@@ -60,9 +61,12 @@
|
|||||||
"args-parser": "~1.3.0",
|
"args-parser": "~1.3.0",
|
||||||
"axios": "~0.21.4",
|
"axios": "~0.21.4",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
"bootstrap": "~5.1.1",
|
"bootstrap": "5.1.3",
|
||||||
"chart.js": "~3.5.1",
|
"bree": "~6.3.1",
|
||||||
|
"chardet": "^1.3.0",
|
||||||
|
"chart.js": "~3.6.0",
|
||||||
"chartjs-adapter-dayjs": "~1.0.0",
|
"chartjs-adapter-dayjs": "~1.0.0",
|
||||||
|
"check-password-strength": "^2.0.3",
|
||||||
"command-exists": "~1.2.9",
|
"command-exists": "~1.2.9",
|
||||||
"compare-versions": "~3.6.0",
|
"compare-versions": "~3.6.0",
|
||||||
"dayjs": "~1.10.7",
|
"dayjs": "~1.10.7",
|
||||||
@@ -70,7 +74,10 @@
|
|||||||
"express-basic-auth": "~1.2.0",
|
"express-basic-auth": "~1.2.0",
|
||||||
"form-data": "~4.0.0",
|
"form-data": "~4.0.0",
|
||||||
"http-graceful-shutdown": "~3.1.4",
|
"http-graceful-shutdown": "~3.1.4",
|
||||||
|
"iconv-lite": "^0.6.3",
|
||||||
"jsonwebtoken": "~8.5.1",
|
"jsonwebtoken": "~8.5.1",
|
||||||
|
"jwt-decode": "^3.1.2",
|
||||||
|
"limiter": "^2.1.0",
|
||||||
"nodemailer": "~6.6.5",
|
"nodemailer": "~6.6.5",
|
||||||
"notp": "~2.0.3",
|
"notp": "~2.0.3",
|
||||||
"password-hash": "~1.2.2",
|
"password-hash": "~1.2.2",
|
||||||
@@ -79,16 +86,16 @@
|
|||||||
"prom-client": "~13.2.0",
|
"prom-client": "~13.2.0",
|
||||||
"prometheus-api-metrics": "~3.2.0",
|
"prometheus-api-metrics": "~3.2.0",
|
||||||
"qrcode": "~1.4.4",
|
"qrcode": "~1.4.4",
|
||||||
"redbean-node": "0.1.2",
|
"redbean-node": "0.1.3",
|
||||||
"socket.io": "~4.2.0",
|
"socket.io": "~4.2.0",
|
||||||
"socket.io-client": "~4.2.0",
|
"socket.io-client": "~4.2.0",
|
||||||
"tar": "^6.1.11",
|
"tar": "^6.1.11",
|
||||||
"tcp-ping": "~0.1.1",
|
"tcp-ping": "~0.1.1",
|
||||||
"thirty-two": "~1.0.2",
|
"thirty-two": "~1.0.2",
|
||||||
"timezones-list": "~3.0.1",
|
"timezones-list": "~3.0.1",
|
||||||
"v-pagination-3": "~0.1.6",
|
"v-pagination-3": "~0.1.7",
|
||||||
"vue": "next",
|
"vue": "next",
|
||||||
"vue-chart-3": "~0.5.8",
|
"vue-chart-3": "~0.5.11",
|
||||||
"vue-confirm-dialog": "~1.0.2",
|
"vue-confirm-dialog": "~1.0.2",
|
||||||
"vue-contenteditable": "~3.0.4",
|
"vue-contenteditable": "~3.0.4",
|
||||||
"vue-i18n": "~9.1.9",
|
"vue-i18n": "~9.1.9",
|
||||||
@@ -103,9 +110,10 @@
|
|||||||
"@babel/eslint-parser": "~7.15.7",
|
"@babel/eslint-parser": "~7.15.7",
|
||||||
"@babel/preset-env": "^7.15.8",
|
"@babel/preset-env": "^7.15.8",
|
||||||
"@types/bootstrap": "~5.1.6",
|
"@types/bootstrap": "~5.1.6",
|
||||||
"@vitejs/plugin-legacy": "~1.6.1",
|
"@vitejs/plugin-legacy": "~1.6.2",
|
||||||
"@vitejs/plugin-vue": "~1.9.2",
|
"@vitejs/plugin-vue": "~1.9.4",
|
||||||
"@vue/compiler-sfc": "~3.2.19",
|
"@vue/compiler-sfc": "~3.2.20",
|
||||||
|
"babel-plugin-rewire": "~1.2.0",
|
||||||
"core-js": "~3.18.1",
|
"core-js": "~3.18.1",
|
||||||
"cross-env": "~7.0.3",
|
"cross-env": "~7.0.3",
|
||||||
"dns2": "~2.0.1",
|
"dns2": "~2.0.1",
|
||||||
@@ -118,6 +126,6 @@
|
|||||||
"stylelint": "~13.13.1",
|
"stylelint": "~13.13.1",
|
||||||
"stylelint-config-standard": "~22.0.0",
|
"stylelint-config-standard": "~22.0.0",
|
||||||
"typescript": "~4.4.3",
|
"typescript": "~4.4.3",
|
||||||
"vite": "~2.6.4"
|
"vite": "~2.6.13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
const basicAuth = require("express-basic-auth")
|
const basicAuth = require("express-basic-auth");
|
||||||
const passwordHash = require("./password-hash");
|
const passwordHash = require("./password-hash");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { setting } = require("./util-server");
|
const { setting } = require("./util-server");
|
||||||
const { debug } = require("../src/util");
|
const { debug } = require("../src/util");
|
||||||
|
const { loginRateLimiter } = require("./rate-limiter");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -13,7 +14,7 @@ const { debug } = require("../src/util");
|
|||||||
exports.login = async function (username, password) {
|
exports.login = async function (username, password) {
|
||||||
let user = await R.findOne("user", " username = ? AND active = 1 ", [
|
let user = await R.findOne("user", " username = ? AND active = 1 ", [
|
||||||
username,
|
username,
|
||||||
])
|
]);
|
||||||
|
|
||||||
if (user && passwordHash.verify(password, user.password)) {
|
if (user && passwordHash.verify(password, user.password)) {
|
||||||
// Upgrade the hash to bcrypt
|
// Upgrade the hash to bcrypt
|
||||||
@@ -27,21 +28,30 @@ exports.login = async function (username, password) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
function myAuthorizer(username, password, callback) {
|
function myAuthorizer(username, password, callback) {
|
||||||
|
|
||||||
setting("disableAuth").then((result) => {
|
setting("disableAuth").then((result) => {
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
callback(null, true)
|
callback(null, true);
|
||||||
} else {
|
} else {
|
||||||
exports.login(username, password).then((user) => {
|
// Login Rate Limit
|
||||||
callback(null, user != null)
|
loginRateLimiter.pass(null, 0).then((pass) => {
|
||||||
})
|
if (pass) {
|
||||||
}
|
exports.login(username, password).then((user) => {
|
||||||
})
|
callback(null, user != null);
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
loginRateLimiter.removeTokens(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback(null, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.basicAuth = basicAuth({
|
exports.basicAuth = basicAuth({
|
||||||
|
@@ -9,18 +9,17 @@ let interval;
|
|||||||
exports.startInterval = () => {
|
exports.startInterval = () => {
|
||||||
let check = async () => {
|
let check = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get("https://raw.githubusercontent.com/louislam/uptime-kuma/master/package.json");
|
const res = await axios.get("https://uptime.kuma.pet/version");
|
||||||
|
|
||||||
if (typeof res.data === "string") {
|
|
||||||
res.data = JSON.parse(res.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For debug
|
// For debug
|
||||||
if (process.env.TEST_CHECK_VERSION === "1") {
|
if (process.env.TEST_CHECK_VERSION === "1") {
|
||||||
res.data.version = "1000.0.0";
|
res.data.slow = "1000.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.data.slow) {
|
||||||
|
exports.latestVersion = res.data.slow;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.latestVersion = res.data.version;
|
|
||||||
} catch (_) { }
|
} catch (_) { }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
7
server/config.js
Normal file
7
server/config.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const args = require("args-parser")(process.argv);
|
||||||
|
const demoMode = args["demo"] || false;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
args,
|
||||||
|
demoMode
|
||||||
|
};
|
@@ -49,10 +49,13 @@ class Database {
|
|||||||
"patch-incident-table.sql": true,
|
"patch-incident-table.sql": true,
|
||||||
"patch-group-table.sql": true,
|
"patch-group-table.sql": true,
|
||||||
"patch-monitor-push_token.sql": true,
|
"patch-monitor-push_token.sql": true,
|
||||||
|
"patch-http-monitor-method-body-and-headers.sql": true,
|
||||||
|
"patch-2fa-invalidate-used-token.sql": true,
|
||||||
|
"patch-notification_sent_history.sql": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The finally version should be 10 after merged tag feature
|
* The final version should be 10 after merged tag feature
|
||||||
* @deprecated Use patchList for any new feature
|
* @deprecated Use patchList for any new feature
|
||||||
*/
|
*/
|
||||||
static latestVersion = 10;
|
static latestVersion = 10;
|
||||||
@@ -112,6 +115,7 @@ class Database {
|
|||||||
// Change to WAL
|
// Change to WAL
|
||||||
await R.exec("PRAGMA journal_mode = WAL");
|
await R.exec("PRAGMA journal_mode = WAL");
|
||||||
await R.exec("PRAGMA cache_size = -12000");
|
await R.exec("PRAGMA cache_size = -12000");
|
||||||
|
await R.exec("PRAGMA auto_vacuum = FULL");
|
||||||
|
|
||||||
console.log("SQLite config:");
|
console.log("SQLite config:");
|
||||||
console.log(await R.getAll("PRAGMA journal_mode"));
|
console.log(await R.getAll("PRAGMA journal_mode"));
|
||||||
@@ -130,7 +134,7 @@ class Database {
|
|||||||
console.info("Latest database version: " + this.latestVersion);
|
console.info("Latest database version: " + this.latestVersion);
|
||||||
|
|
||||||
if (version === this.latestVersion) {
|
if (version === this.latestVersion) {
|
||||||
console.info("Database no need to patch");
|
console.info("Database patch not needed");
|
||||||
} else if (version > this.latestVersion) {
|
} else if (version > this.latestVersion) {
|
||||||
console.info("Warning: Database version is newer than expected");
|
console.info("Warning: Database version is newer than expected");
|
||||||
} else {
|
} else {
|
||||||
@@ -151,8 +155,8 @@ class Database {
|
|||||||
await Database.close();
|
await Database.close();
|
||||||
|
|
||||||
console.error(ex);
|
console.error(ex);
|
||||||
console.error("Start Uptime-Kuma failed due to patch db failed");
|
console.error("Start Uptime-Kuma failed due to issue patching the database");
|
||||||
console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
|
console.error("Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
|
||||||
|
|
||||||
this.restore();
|
this.restore();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@@ -190,7 +194,7 @@ class Database {
|
|||||||
await Database.close();
|
await Database.close();
|
||||||
|
|
||||||
console.error(ex);
|
console.error(ex);
|
||||||
console.error("Start Uptime-Kuma failed due to patch db failed");
|
console.error("Start Uptime-Kuma failed due to issue patching the database");
|
||||||
console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
|
console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
|
||||||
|
|
||||||
this.restore();
|
this.restore();
|
||||||
@@ -231,7 +235,7 @@ class Database {
|
|||||||
this.patched = true;
|
this.patched = true;
|
||||||
await this.importSQLFile("./db/" + sqlFilename);
|
await this.importSQLFile("./db/" + sqlFilename);
|
||||||
databasePatchedFiles[sqlFilename] = true;
|
databasePatchedFiles[sqlFilename] = true;
|
||||||
console.log(sqlFilename + " is patched successfully");
|
console.log(sqlFilename + " was patched successfully");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
debug(sqlFilename + " is already patched, skip");
|
debug(sqlFilename + " is already patched, skip");
|
||||||
@@ -286,7 +290,7 @@ class Database {
|
|||||||
};
|
};
|
||||||
process.addListener("unhandledRejection", listener);
|
process.addListener("unhandledRejection", listener);
|
||||||
|
|
||||||
console.log("Closing DB");
|
console.log("Closing the database");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
Database.noReject = true;
|
Database.noReject = true;
|
||||||
@@ -296,7 +300,7 @@ class Database {
|
|||||||
if (Database.noReject) {
|
if (Database.noReject) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
console.log("Waiting to close the db");
|
console.log("Waiting to close the database");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("SQLite closed");
|
console.log("SQLite closed");
|
||||||
@@ -311,7 +315,7 @@ class Database {
|
|||||||
*/
|
*/
|
||||||
static backup(version) {
|
static backup(version) {
|
||||||
if (! this.backupPath) {
|
if (! this.backupPath) {
|
||||||
console.info("Backup the db");
|
console.info("Backing up the database");
|
||||||
this.backupPath = this.dataDir + "kuma.db.bak" + version;
|
this.backupPath = this.dataDir + "kuma.db.bak" + version;
|
||||||
fs.copyFileSync(Database.path, this.backupPath);
|
fs.copyFileSync(Database.path, this.backupPath);
|
||||||
|
|
||||||
@@ -334,7 +338,7 @@ class Database {
|
|||||||
*/
|
*/
|
||||||
static restore() {
|
static restore() {
|
||||||
if (this.backupPath) {
|
if (this.backupPath) {
|
||||||
console.error("Patch db failed!!! Restoring the backup");
|
console.error("Patching the database failed!!! Restoring the backup");
|
||||||
|
|
||||||
const shmPath = Database.path + "-shm";
|
const shmPath = Database.path + "-shm";
|
||||||
const walPath = Database.path + "-wal";
|
const walPath = Database.path + "-wal";
|
||||||
@@ -353,7 +357,7 @@ class Database {
|
|||||||
fs.unlinkSync(walPath);
|
fs.unlinkSync(walPath);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Restore failed, you may need to restore the backup manually");
|
console.log("Restore failed; you may need to restore the backup manually");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,6 +376,17 @@ class Database {
|
|||||||
console.log("Nothing to restore");
|
console.log("Nothing to restore");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getSize() {
|
||||||
|
debug("Database.getSize()");
|
||||||
|
let stats = fs.statSync(Database.path);
|
||||||
|
debug(stats);
|
||||||
|
return stats.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async shrink() {
|
||||||
|
await R.exec("VACUUM");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Database;
|
module.exports = Database;
|
||||||
|
31
server/jobs.js
Normal file
31
server/jobs.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const Bree = require("bree");
|
||||||
|
const { SHARE_ENV } = require("worker_threads");
|
||||||
|
|
||||||
|
const jobs = [
|
||||||
|
{
|
||||||
|
name: "clear-old-data",
|
||||||
|
interval: "at 03:14",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const initBackgroundJobs = function (args) {
|
||||||
|
const bree = new Bree({
|
||||||
|
root: path.resolve("server", "jobs"),
|
||||||
|
jobs,
|
||||||
|
worker: {
|
||||||
|
env: SHARE_ENV,
|
||||||
|
workerData: args,
|
||||||
|
},
|
||||||
|
workerMessageHandler: (message) => {
|
||||||
|
console.log("[Background Job]:", message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bree.start();
|
||||||
|
return bree;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
initBackgroundJobs
|
||||||
|
};
|
40
server/jobs/clear-old-data.js
Normal file
40
server/jobs/clear-old-data.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
const { log, exit, connectDb } = require("./util-worker");
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
const { setSetting, setting } = require("../util-server");
|
||||||
|
|
||||||
|
const DEFAULT_KEEP_PERIOD = 180;
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await connectDb();
|
||||||
|
|
||||||
|
let period = await setting("keepDataPeriodDays");
|
||||||
|
|
||||||
|
// Set Default Period
|
||||||
|
if (period == null) {
|
||||||
|
await setSetting("keepDataPeriodDays", DEFAULT_KEEP_PERIOD, "general");
|
||||||
|
period = DEFAULT_KEEP_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try parse setting
|
||||||
|
let parsedPeriod;
|
||||||
|
try {
|
||||||
|
parsedPeriod = parseInt(period);
|
||||||
|
} catch (_) {
|
||||||
|
log("Failed to parse setting, resetting to default..");
|
||||||
|
await setSetting("keepDataPeriodDays", DEFAULT_KEEP_PERIOD, "general");
|
||||||
|
parsedPeriod = DEFAULT_KEEP_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
})();
|
39
server/jobs/util-worker.js
Normal file
39
server/jobs/util-worker.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const { parentPort, workerData } = require("worker_threads");
|
||||||
|
const Database = require("../database");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const log = function (any) {
|
||||||
|
if (parentPort) {
|
||||||
|
parentPort.postMessage(any);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const exit = function (error) {
|
||||||
|
if (error && error != 0) {
|
||||||
|
process.exit(error);
|
||||||
|
} else {
|
||||||
|
if (parentPort) {
|
||||||
|
parentPort.postMessage("done");
|
||||||
|
} else {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const connectDb = async function () {
|
||||||
|
const dbPath = path.join(
|
||||||
|
process.env.DATA_DIR || workerData["data-dir"] || "./data/"
|
||||||
|
);
|
||||||
|
|
||||||
|
Database.init({
|
||||||
|
"data-dir": dbPath,
|
||||||
|
});
|
||||||
|
|
||||||
|
await Database.connect();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
log,
|
||||||
|
exit,
|
||||||
|
connectDb,
|
||||||
|
};
|
@@ -7,11 +7,11 @@ dayjs.extend(timezone);
|
|||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const { Prometheus } = require("../prometheus");
|
const { Prometheus } = require("../prometheus");
|
||||||
const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
|
const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
|
||||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom } = require("../util-server");
|
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog } = require("../util-server");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
const { Notification } = require("../notification");
|
const { Notification } = require("../notification");
|
||||||
const { demoMode } = require("../server");
|
const { demoMode } = require("../config");
|
||||||
const version = require("../../package.json").version;
|
const version = require("../../package.json").version;
|
||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
|
|
||||||
@@ -55,6 +55,9 @@ class Monitor extends BeanModel {
|
|||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
url: this.url,
|
url: this.url,
|
||||||
|
method: this.method,
|
||||||
|
body: this.body,
|
||||||
|
headers: this.headers,
|
||||||
hostname: this.hostname,
|
hostname: this.hostname,
|
||||||
port: this.port,
|
port: this.port,
|
||||||
maxretries: this.maxretries,
|
maxretries: this.maxretries,
|
||||||
@@ -138,11 +141,16 @@ class Monitor extends BeanModel {
|
|||||||
// Do not do any queries/high loading things before the "bean.ping"
|
// Do not do any queries/high loading things before the "bean.ping"
|
||||||
let startTime = dayjs().valueOf();
|
let startTime = dayjs().valueOf();
|
||||||
|
|
||||||
let res = await axios.get(this.url, {
|
debug(`[${this.name}] Prepare Options for axios`);
|
||||||
|
const options = {
|
||||||
|
url: this.url,
|
||||||
|
method: (this.method || "get").toLowerCase(),
|
||||||
|
...(this.body ? { data: JSON.parse(this.body) } : {}),
|
||||||
timeout: this.interval * 1000 * 0.8,
|
timeout: this.interval * 1000 * 0.8,
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "*/*",
|
"Accept": "*/*",
|
||||||
"User-Agent": "Uptime-Kuma/" + version,
|
"User-Agent": "Uptime-Kuma/" + version,
|
||||||
|
...(this.headers ? JSON.parse(this.headers) : {}),
|
||||||
},
|
},
|
||||||
httpsAgent: new https.Agent({
|
httpsAgent: new https.Agent({
|
||||||
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
|
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
|
||||||
@@ -152,15 +160,26 @@ class Monitor extends BeanModel {
|
|||||||
validateStatus: (status) => {
|
validateStatus: (status) => {
|
||||||
return checkStatusCode(status, this.getAcceptedStatuscodes());
|
return checkStatusCode(status, this.getAcceptedStatuscodes());
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
|
||||||
|
debug(`[${this.name}] Axios Request`);
|
||||||
|
let res = await axios.request(options);
|
||||||
bean.msg = `${res.status} - ${res.statusText}`;
|
bean.msg = `${res.status} - ${res.statusText}`;
|
||||||
bean.ping = dayjs().valueOf() - startTime;
|
bean.ping = dayjs().valueOf() - startTime;
|
||||||
|
|
||||||
// Check certificate if https is used
|
// Check certificate if https is used
|
||||||
let certInfoStartTime = dayjs().valueOf();
|
let certInfoStartTime = dayjs().valueOf();
|
||||||
if (this.getUrl()?.protocol === "https:") {
|
if (this.getUrl()?.protocol === "https:") {
|
||||||
|
debug(`[${this.name}] Check cert`);
|
||||||
try {
|
try {
|
||||||
tlsInfo = await this.updateTlsInfo(checkCertificate(res));
|
let tlsInfoObject = checkCertificate(res);
|
||||||
|
tlsInfo = await this.updateTlsInfo(tlsInfoObject);
|
||||||
|
|
||||||
|
if (!this.getIgnoreTls()) {
|
||||||
|
debug(`[${this.name}] call sendCertNotification`);
|
||||||
|
await this.sendCertNotification(tlsInfoObject);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message !== "No TLS certificate in response") {
|
if (e.message !== "No TLS certificate in response") {
|
||||||
console.error(e.message);
|
console.error(e.message);
|
||||||
@@ -172,6 +191,10 @@ class Monitor extends BeanModel {
|
|||||||
debug("Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
|
debug("Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID == this.id) {
|
||||||
|
console.log(res.data);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.type === "http") {
|
if (this.type === "http") {
|
||||||
bean.status = UP;
|
bean.status = UP;
|
||||||
} else {
|
} else {
|
||||||
@@ -260,6 +283,46 @@ class Monitor extends BeanModel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (this.type === "steam") {
|
||||||
|
const steamApiUrl = "https://api.steampowered.com/IGameServersService/GetServerList/v1/";
|
||||||
|
const steamAPIKey = await setting("steamAPIKey");
|
||||||
|
const filter = `addr\\${this.hostname}:${this.port}`;
|
||||||
|
|
||||||
|
if (!steamAPIKey) {
|
||||||
|
throw new Error("Steam API Key not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await axios.get(steamApiUrl, {
|
||||||
|
timeout: this.interval * 1000 * 0.8,
|
||||||
|
headers: {
|
||||||
|
"Accept": "*/*",
|
||||||
|
"User-Agent": "Uptime-Kuma/" + version,
|
||||||
|
},
|
||||||
|
httpsAgent: new https.Agent({
|
||||||
|
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
|
||||||
|
rejectUnauthorized: ! this.getIgnoreTls(),
|
||||||
|
}),
|
||||||
|
maxRedirects: this.maxredirects,
|
||||||
|
validateStatus: (status) => {
|
||||||
|
return checkStatusCode(status, this.getAcceptedStatuscodes());
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
filter: filter,
|
||||||
|
key: steamAPIKey,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.data.response && res.data.response.servers && res.data.response.servers.length > 0) {
|
||||||
|
bean.status = UP;
|
||||||
|
bean.msg = res.data.response.servers[0].name;
|
||||||
|
|
||||||
|
try {
|
||||||
|
bean.ping = await ping(this.hostname);
|
||||||
|
} catch (_) { }
|
||||||
|
} else {
|
||||||
|
throw new Error("Server not found on Steam");
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bean.msg = "Unknown Monitor Type";
|
bean.msg = "Unknown Monitor Type";
|
||||||
bean.status = PENDING;
|
bean.status = PENDING;
|
||||||
@@ -292,53 +355,20 @@ class Monitor extends BeanModel {
|
|||||||
|
|
||||||
let beatInterval = this.interval;
|
let beatInterval = this.interval;
|
||||||
|
|
||||||
// * ? -> ANY STATUS = important [isFirstBeat]
|
debug(`[${this.name}] Check isImportant`);
|
||||||
// UP -> PENDING = not important
|
let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status);
|
||||||
// * UP -> DOWN = important
|
|
||||||
// UP -> UP = not important
|
|
||||||
// PENDING -> PENDING = not important
|
|
||||||
// * PENDING -> DOWN = important
|
|
||||||
// PENDING -> UP = not important
|
|
||||||
// DOWN -> PENDING = this case not exists
|
|
||||||
// DOWN -> DOWN = not important
|
|
||||||
// * DOWN -> UP = important
|
|
||||||
let isImportant = isFirstBeat ||
|
|
||||||
(previousBeat.status === UP && bean.status === DOWN) ||
|
|
||||||
(previousBeat.status === DOWN && bean.status === UP) ||
|
|
||||||
(previousBeat.status === PENDING && bean.status === DOWN);
|
|
||||||
|
|
||||||
// Mark as important if status changed, ignore pending pings,
|
// Mark as important if status changed, ignore pending pings,
|
||||||
// Don't notify if disrupted changes to up
|
// Don't notify if disrupted changes to up
|
||||||
if (isImportant) {
|
if (isImportant) {
|
||||||
bean.important = true;
|
bean.important = true;
|
||||||
|
|
||||||
// Send only if the first beat is DOWN
|
debug(`[${this.name}] sendNotification`);
|
||||||
if (!isFirstBeat || bean.status === DOWN) {
|
await Monitor.sendNotification(isFirstBeat, this, bean);
|
||||||
let notificationList = await R.getAll("SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id ", [
|
|
||||||
this.id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
let text;
|
// Clear Status Page Cache
|
||||||
if (bean.status === UP) {
|
debug(`[${this.name}] apicache clear`);
|
||||||
text = "✅ Up";
|
apicache.clear();
|
||||||
} else {
|
|
||||||
text = "🔴 Down";
|
|
||||||
}
|
|
||||||
|
|
||||||
let msg = `[${this.name}] [${text}] ${bean.msg}`;
|
|
||||||
|
|
||||||
for (let notification of notificationList) {
|
|
||||||
try {
|
|
||||||
await Notification.send(JSON.parse(notification.config), msg, await this.toJSON(), bean.toJSON());
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Cannot send notification to " + notification.name);
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear Status Page Cache
|
|
||||||
apicache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bean.important = false;
|
bean.important = false;
|
||||||
@@ -355,10 +385,14 @@ class Monitor extends BeanModel {
|
|||||||
console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`);
|
console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug(`[${this.name}] Send to socket`);
|
||||||
io.to(this.user_id).emit("heartbeat", bean.toJSON());
|
io.to(this.user_id).emit("heartbeat", bean.toJSON());
|
||||||
Monitor.sendStats(io, this.id, this.user_id);
|
Monitor.sendStats(io, this.id, this.user_id);
|
||||||
|
|
||||||
|
debug(`[${this.name}] Store`);
|
||||||
await R.store(bean);
|
await R.store(bean);
|
||||||
|
|
||||||
|
debug(`[${this.name}] prometheus.update`);
|
||||||
prometheus.update(bean, tlsInfo);
|
prometheus.update(bean, tlsInfo);
|
||||||
|
|
||||||
previousBeat = bean;
|
previousBeat = bean;
|
||||||
@@ -372,18 +406,36 @@ class Monitor extends BeanModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.heartbeatInterval = setTimeout(beat, beatInterval * 1000);
|
debug(`[${this.name}] SetTimeout for next check.`);
|
||||||
|
this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000);
|
||||||
|
} else {
|
||||||
|
console.log(`[${this.name}] isStop = true, no next check.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const safeBeat = async () => {
|
||||||
|
try {
|
||||||
|
await beat();
|
||||||
|
} catch (e) {
|
||||||
|
console.trace(e);
|
||||||
|
errorLog(e, false);
|
||||||
|
console.error("Please report to https://github.com/louislam/uptime-kuma/issues");
|
||||||
|
|
||||||
|
if (! this.isStop) {
|
||||||
|
console.log("Try to restart the monitor");
|
||||||
|
this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Delay Push Type
|
// Delay Push Type
|
||||||
if (this.type === "push") {
|
if (this.type === "push") {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
beat();
|
safeBeat();
|
||||||
}, this.interval * 1000);
|
}, this.interval * 1000);
|
||||||
} else {
|
} else {
|
||||||
beat();
|
safeBeat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,10 +467,36 @@ class Monitor extends BeanModel {
|
|||||||
let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
|
let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
|
||||||
this.id,
|
this.id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (tls_info_bean == null) {
|
if (tls_info_bean == null) {
|
||||||
tls_info_bean = R.dispense("monitor_tls_info");
|
tls_info_bean = R.dispense("monitor_tls_info");
|
||||||
tls_info_bean.monitor_id = this.id;
|
tls_info_bean.monitor_id = this.id;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Clear sent history if the cert changed.
|
||||||
|
try {
|
||||||
|
let oldCertInfo = JSON.parse(tls_info_bean.info_json);
|
||||||
|
|
||||||
|
let isValidObjects = oldCertInfo && oldCertInfo.certInfo && checkCertificateResult && checkCertificateResult.certInfo;
|
||||||
|
|
||||||
|
if (isValidObjects) {
|
||||||
|
if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) {
|
||||||
|
debug("Resetting sent_history");
|
||||||
|
await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [
|
||||||
|
this.id
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
debug("No need to reset sent_history");
|
||||||
|
debug(oldCertInfo.certInfo.fingerprint256);
|
||||||
|
debug(checkCertificateResult.certInfo.fingerprint256);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug("Not valid object");
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_info_bean.info_json = JSON.stringify(checkCertificateResult);
|
tls_info_bean.info_json = JSON.stringify(checkCertificateResult);
|
||||||
await R.store(tls_info_bean);
|
await R.store(tls_info_bean);
|
||||||
|
|
||||||
@@ -546,6 +624,112 @@ class Monitor extends BeanModel {
|
|||||||
io.to(userID).emit("uptime", monitorID, duration, uptime);
|
io.to(userID).emit("uptime", monitorID, duration, uptime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isImportantBeat(isFirstBeat, previousBeatStatus, currentBeatStatus) {
|
||||||
|
// * ? -> ANY STATUS = important [isFirstBeat]
|
||||||
|
// UP -> PENDING = not important
|
||||||
|
// * UP -> DOWN = important
|
||||||
|
// UP -> UP = not important
|
||||||
|
// PENDING -> PENDING = not important
|
||||||
|
// * PENDING -> DOWN = important
|
||||||
|
// PENDING -> UP = not important
|
||||||
|
// DOWN -> PENDING = this case not exists
|
||||||
|
// DOWN -> DOWN = not important
|
||||||
|
// * DOWN -> UP = important
|
||||||
|
let isImportant = isFirstBeat ||
|
||||||
|
(previousBeatStatus === UP && currentBeatStatus === DOWN) ||
|
||||||
|
(previousBeatStatus === DOWN && currentBeatStatus === UP) ||
|
||||||
|
(previousBeatStatus === PENDING && currentBeatStatus === DOWN);
|
||||||
|
return isImportant;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async sendNotification(isFirstBeat, monitor, bean) {
|
||||||
|
if (!isFirstBeat || bean.status === DOWN) {
|
||||||
|
const notificationList = await Monitor.getNotificationList(monitor);
|
||||||
|
|
||||||
|
let text;
|
||||||
|
if (bean.status === UP) {
|
||||||
|
text = "✅ Up";
|
||||||
|
} else {
|
||||||
|
text = "🔴 Down";
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg = `[${monitor.name}] [${text}] ${bean.msg}`;
|
||||||
|
|
||||||
|
for (let notification of notificationList) {
|
||||||
|
try {
|
||||||
|
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON());
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Cannot send notification to " + notification.name);
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getNotificationList(monitor) {
|
||||||
|
let notificationList = await R.getAll("SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id ", [
|
||||||
|
monitor.id,
|
||||||
|
]);
|
||||||
|
return notificationList;
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendCertNotification(tlsInfoObject) {
|
||||||
|
if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) {
|
||||||
|
const notificationList = await Monitor.getNotificationList(this);
|
||||||
|
|
||||||
|
debug("call sendCertNotificationByTargetDays");
|
||||||
|
await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 21, notificationList);
|
||||||
|
await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 14, notificationList);
|
||||||
|
await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) {
|
||||||
|
|
||||||
|
if (daysRemaining > targetDays) {
|
||||||
|
debug(`No need to send cert notification. ${daysRemaining} > ${targetDays}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notificationList.length > 0) {
|
||||||
|
|
||||||
|
let row = await R.getRow("SELECT * FROM notification_sent_history WHERE type = ? AND monitor_id = ? AND days = ?", [
|
||||||
|
"certificate",
|
||||||
|
this.id,
|
||||||
|
targetDays,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Sent already, no need to send again
|
||||||
|
if (row) {
|
||||||
|
debug("Sent already, no need to send again");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sent = false;
|
||||||
|
debug("Send certificate notification");
|
||||||
|
|
||||||
|
for (let notification of notificationList) {
|
||||||
|
try {
|
||||||
|
debug("Sending to " + notification.name);
|
||||||
|
await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] Certificate will be expired in ${daysRemaining} days`);
|
||||||
|
sent = true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Cannot send cert notification to " + notification.name);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sent) {
|
||||||
|
await R.exec("INSERT INTO notification_sent_history (type, monitor_id, days) VALUES(?, ?, ?)", [
|
||||||
|
"certificate",
|
||||||
|
this.id,
|
||||||
|
targetDays,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug("No notification, no need to send cert notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Monitor;
|
module.exports = Monitor;
|
||||||
|
108
server/notification-providers/aliyun-sms.js
Normal file
108
server/notification-providers/aliyun-sms.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
const { default: axios } = require("axios");
|
||||||
|
const Crypto = require("crypto");
|
||||||
|
const qs = require("qs");
|
||||||
|
|
||||||
|
class AliyunSMS extends NotificationProvider {
|
||||||
|
name = "AliyunSMS";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON != null) {
|
||||||
|
let msgBody = JSON.stringify({
|
||||||
|
name: monitorJSON["name"],
|
||||||
|
time: heartbeatJSON["time"],
|
||||||
|
status: this.statusToString(heartbeatJSON["status"]),
|
||||||
|
msg: heartbeatJSON["msg"],
|
||||||
|
});
|
||||||
|
if (this.sendSms(notification, msgBody)) {
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let msgBody = JSON.stringify({
|
||||||
|
name: "",
|
||||||
|
time: "",
|
||||||
|
status: "",
|
||||||
|
msg: msg,
|
||||||
|
});
|
||||||
|
if (this.sendSms(notification, msgBody)) {
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendSms(notification, msgbody) {
|
||||||
|
let params = {
|
||||||
|
PhoneNumbers: notification.phonenumber,
|
||||||
|
TemplateCode: notification.templateCode,
|
||||||
|
SignName: notification.signName,
|
||||||
|
TemplateParam: msgbody,
|
||||||
|
AccessKeyId: notification.accessKeyId,
|
||||||
|
Format: "JSON",
|
||||||
|
SignatureMethod: "HMAC-SHA1",
|
||||||
|
SignatureVersion: "1.0",
|
||||||
|
SignatureNonce: Math.random().toString(),
|
||||||
|
Timestamp: new Date().toISOString(),
|
||||||
|
Action: "SendSms",
|
||||||
|
Version: "2017-05-25",
|
||||||
|
};
|
||||||
|
|
||||||
|
params.Signature = this.sign(params, notification.secretAccessKey);
|
||||||
|
let config = {
|
||||||
|
method: "POST",
|
||||||
|
url: "http://dysmsapi.aliyuncs.com/",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
data: qs.stringify(params),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await axios(config);
|
||||||
|
if (result.data.Message == "OK") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Aliyun request sign */
|
||||||
|
sign(param, AccessKeySecret) {
|
||||||
|
let param2 = {};
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
let oa = Object.keys(param).sort();
|
||||||
|
|
||||||
|
for (let i = 0; i < oa.length; i++) {
|
||||||
|
let key = oa[i];
|
||||||
|
param2[key] = param[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let key in param2) {
|
||||||
|
data.push(`${encodeURIComponent(key)}=${encodeURIComponent(param2[key])}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let StringToSign = `POST&${encodeURIComponent("/")}&${encodeURIComponent(data.join("&"))}`;
|
||||||
|
return Crypto
|
||||||
|
.createHmac("sha1", `${AccessKeySecret}&`)
|
||||||
|
.update(Buffer.from(StringToSign))
|
||||||
|
.digest("base64");
|
||||||
|
}
|
||||||
|
|
||||||
|
statusToString(status) {
|
||||||
|
switch (status) {
|
||||||
|
case DOWN:
|
||||||
|
return "DOWN";
|
||||||
|
case UP:
|
||||||
|
return "UP";
|
||||||
|
default:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AliyunSMS;
|
89
server/notification-providers/bark.js
Normal file
89
server/notification-providers/bark.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
//
|
||||||
|
// bark.js
|
||||||
|
// UptimeKuma
|
||||||
|
//
|
||||||
|
// Created by Lakr Aream on 2021/10/24.
|
||||||
|
// Copyright © 2021 Lakr Aream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
const { default: axios } = require("axios");
|
||||||
|
|
||||||
|
// bark is an APN bridge that sends notifications to Apple devices.
|
||||||
|
|
||||||
|
const barkNotificationGroup = "UptimeKuma";
|
||||||
|
const barkNotificationAvatar = "https://github.com/louislam/uptime-kuma/raw/master/public/icon.png";
|
||||||
|
const barkNotificationSound = "telegraph";
|
||||||
|
const successMessage = "Successes!";
|
||||||
|
|
||||||
|
class Bark extends NotificationProvider {
|
||||||
|
name = "Bark";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
try {
|
||||||
|
var barkEndpoint = notification.barkEndpoint;
|
||||||
|
|
||||||
|
// check if the endpoint has a "/" suffix, if so, delete it first
|
||||||
|
if (barkEndpoint.endsWith("/")) {
|
||||||
|
barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == UP) {
|
||||||
|
let title = "UptimeKuma Monitor Up";
|
||||||
|
return await this.postNotification(title, msg, barkEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == DOWN) {
|
||||||
|
let title = "UptimeKuma Monitor Down";
|
||||||
|
return await this.postNotification(title, msg, barkEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg != null) {
|
||||||
|
let title = "UptimeKuma Message";
|
||||||
|
return await this.postNotification(title, msg, barkEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add additional parameter for better on device styles (iOS 15 optimized)
|
||||||
|
appendAdditionalParameters(postUrl) {
|
||||||
|
// grouping all our notifications
|
||||||
|
postUrl += "?group=" + barkNotificationGroup;
|
||||||
|
// set icon to uptime kuma icon, 11kb should be fine
|
||||||
|
postUrl += "&icon=" + barkNotificationAvatar;
|
||||||
|
// picked a sound, this should follow system's mute status when arrival
|
||||||
|
postUrl += "&sound=" + barkNotificationSound;
|
||||||
|
return postUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thrown if failed to check result, result code should be in range 2xx
|
||||||
|
checkResult(result) {
|
||||||
|
if (result.status == null) {
|
||||||
|
throw new Error("Bark notification failed with invalid response!");
|
||||||
|
}
|
||||||
|
if (result.status < 200 || result.status >= 300) {
|
||||||
|
throw new Error("Bark notification failed with status code " + result.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async postNotification(title, subtitle, endpoint) {
|
||||||
|
// url encode title and subtitle
|
||||||
|
title = encodeURIComponent(title);
|
||||||
|
subtitle = encodeURIComponent(subtitle);
|
||||||
|
let postUrl = endpoint + "/" + title + "/" + subtitle;
|
||||||
|
postUrl = this.appendAdditionalParameters(postUrl);
|
||||||
|
let result = await axios.get(postUrl);
|
||||||
|
this.checkResult(result);
|
||||||
|
if (result.statusText != null) {
|
||||||
|
return "Bark notification succeed: " + result.statusText;
|
||||||
|
}
|
||||||
|
// because returned in range 200 ..< 300
|
||||||
|
return successMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Bark;
|
42
server/notification-providers/clicksendsms.js
Normal file
42
server/notification-providers/clicksendsms.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class ClickSendSMS extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "clicksendsms";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
try {
|
||||||
|
console.log({ notification });
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": "Basic " + Buffer.from(notification.clicksendsmsLogin + ":" + notification.clicksendsmsPassword).toString('base64'),
|
||||||
|
"Accept": "text/json",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = {
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
"body": msg.replace(/[^\x00-\x7F]/g, ""),
|
||||||
|
"to": notification.clicksendsmsToNumber,
|
||||||
|
"source": "uptime-kuma",
|
||||||
|
"from": notification.clicksendsmsSenderName,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
let resp = await axios.post("https://rest.clicksend.com/v3/sms/send", data, config);
|
||||||
|
if (resp.data.data.messages[0].status !== "SUCCESS") {
|
||||||
|
let error = "Something gone wrong. Api returned " + resp.data.data.messages[0].status + ".";
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ClickSendSMS;
|
79
server/notification-providers/dingding.js
Normal file
79
server/notification-providers/dingding.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
const { default: axios } = require("axios");
|
||||||
|
const Crypto = require("crypto");
|
||||||
|
|
||||||
|
class DingDing extends NotificationProvider {
|
||||||
|
name = "DingDing";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON != null) {
|
||||||
|
let params = {
|
||||||
|
msgtype: "markdown",
|
||||||
|
markdown: {
|
||||||
|
title: monitorJSON["name"],
|
||||||
|
text: `## [${this.statusToString(heartbeatJSON["status"])}] \n > ${heartbeatJSON["msg"]} \n > Time(UTC):${heartbeatJSON["time"]}`,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (this.sendToDingDing(notification, params)) {
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let params = {
|
||||||
|
msgtype: "text",
|
||||||
|
text: {
|
||||||
|
content: msg
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (this.sendToDingDing(notification, params)) {
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendToDingDing(notification, params) {
|
||||||
|
let timestamp = Date.now();
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
url: `${notification.webHookUrl}×tamp=${timestamp}&sign=${encodeURIComponent(this.sign(timestamp, notification.secretKey))}`,
|
||||||
|
data: JSON.stringify(params),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await axios(config);
|
||||||
|
if (result.data.errmsg == "ok") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DingDing sign */
|
||||||
|
sign(timestamp, secretKey) {
|
||||||
|
return Crypto
|
||||||
|
.createHmac("sha256", Buffer.from(secretKey, "utf8"))
|
||||||
|
.update(Buffer.from(`${timestamp}\n${secretKey}`, "utf8"))
|
||||||
|
.digest("base64");
|
||||||
|
}
|
||||||
|
|
||||||
|
statusToString(status) {
|
||||||
|
switch (status) {
|
||||||
|
case DOWN:
|
||||||
|
return "DOWN";
|
||||||
|
case UP:
|
||||||
|
return "UP";
|
||||||
|
default:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DingDing;
|
83
server/notification-providers/feishu.js
Normal file
83
server/notification-providers/feishu.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Feishu extends NotificationProvider {
|
||||||
|
name = "Feishu";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
let feishuWebHookUrl = notification.feishuWebHookUrl;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let testdata = {
|
||||||
|
msg_type: "text",
|
||||||
|
content: {
|
||||||
|
text: msg,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await axios.post(feishuWebHookUrl, testdata);
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let downdata = {
|
||||||
|
msg_type: "post",
|
||||||
|
content: {
|
||||||
|
post: {
|
||||||
|
zh_cn: {
|
||||||
|
title: "UptimeKuma Alert: [Down] " + monitorJSON["name"],
|
||||||
|
content: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
tag: "text",
|
||||||
|
text:
|
||||||
|
"[Down] " +
|
||||||
|
heartbeatJSON["msg"] +
|
||||||
|
"\nTime (UTC): " +
|
||||||
|
heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await axios.post(feishuWebHookUrl, downdata);
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == UP) {
|
||||||
|
let updata = {
|
||||||
|
msg_type: "post",
|
||||||
|
content: {
|
||||||
|
post: {
|
||||||
|
zh_cn: {
|
||||||
|
title: "UptimeKuma Alert: [Up] " + monitorJSON["name"],
|
||||||
|
content: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
tag: "text",
|
||||||
|
text:
|
||||||
|
"[Up] " +
|
||||||
|
heartbeatJSON["msg"] +
|
||||||
|
"\nTime (UTC): " +
|
||||||
|
heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await axios.post(feishuWebHookUrl, updata);
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Feishu;
|
@@ -39,8 +39,9 @@ class Slack extends NotificationProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const time = heartbeatJSON["time"];
|
const time = heartbeatJSON["time"];
|
||||||
|
const textMsg = "Uptime Kuma Alert";
|
||||||
let data = {
|
let data = {
|
||||||
"text": "Uptime Kuma Alert",
|
"text": monitorJSON ? textMsg + `: ${monitorJSON.name}` : textMsg,
|
||||||
"channel": notification.slackchannel,
|
"channel": notification.slackchannel,
|
||||||
"username": notification.slackusername,
|
"username": notification.slackusername,
|
||||||
"icon_emoji": notification.slackiconemo,
|
"icon_emoji": notification.slackiconemo,
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
const nodemailer = require("nodemailer");
|
const nodemailer = require("nodemailer");
|
||||||
const NotificationProvider = require("./notification-provider");
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
class SMTP extends NotificationProvider {
|
class SMTP extends NotificationProvider {
|
||||||
|
|
||||||
@@ -11,6 +12,9 @@ class SMTP extends NotificationProvider {
|
|||||||
host: notification.smtpHost,
|
host: notification.smtpHost,
|
||||||
port: notification.smtpPort,
|
port: notification.smtpPort,
|
||||||
secure: notification.smtpSecure,
|
secure: notification.smtpSecure,
|
||||||
|
tls: {
|
||||||
|
rejectUnauthorized: notification.smtpIgnoreTLSError || false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
|
// Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
|
||||||
@@ -20,6 +24,56 @@ class SMTP extends NotificationProvider {
|
|||||||
pass: notification.smtpPassword,
|
pass: notification.smtpPassword,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Lets start with default subject and empty string for custom one
|
||||||
|
let subject = msg;
|
||||||
|
|
||||||
|
// Change the subject if:
|
||||||
|
// - The msg ends with "Testing" or
|
||||||
|
// - Actual Up/Down Notification
|
||||||
|
if ((monitorJSON && heartbeatJSON) || msg.endsWith("Testing")) {
|
||||||
|
let customSubject = "";
|
||||||
|
|
||||||
|
// Our subject cannot end with whitespace it's often raise spam score
|
||||||
|
// Once I got "Cannot read property 'trim' of undefined", better be safe than sorry
|
||||||
|
if (notification.customSubject) {
|
||||||
|
customSubject = notification.customSubject.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If custom subject is not empty, change subject for notification
|
||||||
|
if (customSubject !== "") {
|
||||||
|
|
||||||
|
// Replace "MACROS" with corresponding variable
|
||||||
|
let replaceName = new RegExp("{{NAME}}", "g");
|
||||||
|
let replaceHostnameOrURL = new RegExp("{{HOSTNAME_OR_URL}}", "g");
|
||||||
|
let replaceStatus = new RegExp("{{STATUS}}", "g");
|
||||||
|
|
||||||
|
// Lets start with dummy values to simplify code
|
||||||
|
let monitorName = "Test";
|
||||||
|
let monitorHostnameOrURL = "testing.hostname";
|
||||||
|
let serviceStatus = "⚠️ Test";
|
||||||
|
|
||||||
|
if (monitorJSON !== null) {
|
||||||
|
monitorName = monitorJSON["name"];
|
||||||
|
|
||||||
|
if (monitorJSON["type"] === "http" || monitorJSON["type"] === "keyword") {
|
||||||
|
monitorHostnameOrURL = monitorJSON["url"];
|
||||||
|
} else {
|
||||||
|
monitorHostnameOrURL = monitorJSON["hostname"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON !== null) {
|
||||||
|
serviceStatus = (heartbeatJSON["status"] === DOWN) ? "🔴 Down" : "✅ Up";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break replace to one by line for better readability
|
||||||
|
customSubject = customSubject.replace(replaceStatus, serviceStatus);
|
||||||
|
customSubject = customSubject.replace(replaceName, monitorName);
|
||||||
|
customSubject = customSubject.replace(replaceHostnameOrURL, monitorHostnameOrURL);
|
||||||
|
|
||||||
|
subject = customSubject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let transporter = nodemailer.createTransport(config);
|
let transporter = nodemailer.createTransport(config);
|
||||||
|
|
||||||
@@ -34,11 +88,8 @@ class SMTP extends NotificationProvider {
|
|||||||
cc: notification.smtpCC,
|
cc: notification.smtpCC,
|
||||||
bcc: notification.smtpBCC,
|
bcc: notification.smtpBCC,
|
||||||
to: notification.smtpTo,
|
to: notification.smtpTo,
|
||||||
subject: msg,
|
subject: subject,
|
||||||
text: bodyTextContent,
|
text: bodyTextContent,
|
||||||
tls: {
|
|
||||||
rejectUnauthorized: notification.smtpIgnoreTLSError || false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return "Sent Successfully.";
|
return "Sent Successfully.";
|
||||||
|
@@ -8,6 +8,7 @@ const Mattermost = require("./notification-providers/mattermost");
|
|||||||
const Matrix = require("./notification-providers/matrix");
|
const Matrix = require("./notification-providers/matrix");
|
||||||
const Octopush = require("./notification-providers/octopush");
|
const Octopush = require("./notification-providers/octopush");
|
||||||
const PromoSMS = require("./notification-providers/promosms");
|
const PromoSMS = require("./notification-providers/promosms");
|
||||||
|
const ClickSendSMS = require("./notification-providers/clicksendsms");
|
||||||
const Pushbullet = require("./notification-providers/pushbullet");
|
const Pushbullet = require("./notification-providers/pushbullet");
|
||||||
const Pushover = require("./notification-providers/pushover");
|
const Pushover = require("./notification-providers/pushover");
|
||||||
const Pushy = require("./notification-providers/pushy");
|
const Pushy = require("./notification-providers/pushy");
|
||||||
@@ -18,6 +19,10 @@ const SMTP = require("./notification-providers/smtp");
|
|||||||
const Teams = require("./notification-providers/teams");
|
const Teams = require("./notification-providers/teams");
|
||||||
const Telegram = require("./notification-providers/telegram");
|
const Telegram = require("./notification-providers/telegram");
|
||||||
const Webhook = require("./notification-providers/webhook");
|
const Webhook = require("./notification-providers/webhook");
|
||||||
|
const Feishu = require("./notification-providers/feishu");
|
||||||
|
const AliyunSms = require("./notification-providers/aliyun-sms");
|
||||||
|
const DingDing = require("./notification-providers/dingding");
|
||||||
|
const Bark = require("./notification-providers/bark");
|
||||||
|
|
||||||
class Notification {
|
class Notification {
|
||||||
|
|
||||||
@@ -30,15 +35,19 @@ class Notification {
|
|||||||
|
|
||||||
const list = [
|
const list = [
|
||||||
new Apprise(),
|
new Apprise(),
|
||||||
|
new AliyunSms(),
|
||||||
|
new DingDing(),
|
||||||
new Discord(),
|
new Discord(),
|
||||||
new Teams(),
|
new Teams(),
|
||||||
new Gotify(),
|
new Gotify(),
|
||||||
new Line(),
|
new Line(),
|
||||||
new LunaSea(),
|
new LunaSea(),
|
||||||
|
new Feishu(),
|
||||||
new Mattermost(),
|
new Mattermost(),
|
||||||
new Matrix(),
|
new Matrix(),
|
||||||
new Octopush(),
|
new Octopush(),
|
||||||
new PromoSMS(),
|
new PromoSMS(),
|
||||||
|
new ClickSendSMS(),
|
||||||
new Pushbullet(),
|
new Pushbullet(),
|
||||||
new Pushover(),
|
new Pushover(),
|
||||||
new Pushy(),
|
new Pushy(),
|
||||||
@@ -48,6 +57,7 @@ class Notification {
|
|||||||
new SMTP(),
|
new SMTP(),
|
||||||
new Telegram(),
|
new Telegram(),
|
||||||
new Webhook(),
|
new Webhook(),
|
||||||
|
new Bark(),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let item of list) {
|
for (let item of list) {
|
||||||
|
@@ -4,10 +4,7 @@ const net = require("net");
|
|||||||
const spawn = require("child_process").spawn;
|
const spawn = require("child_process").spawn;
|
||||||
const events = require("events");
|
const events = require("events");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const WIN = /^win/.test(process.platform);
|
const util = require("./util-server");
|
||||||
const LIN = /^linux/.test(process.platform);
|
|
||||||
const MAC = /^darwin/.test(process.platform);
|
|
||||||
const FBSD = /^freebsd/.test(process.platform);
|
|
||||||
|
|
||||||
module.exports = Ping;
|
module.exports = Ping;
|
||||||
|
|
||||||
@@ -23,12 +20,12 @@ function Ping(host, options) {
|
|||||||
|
|
||||||
const timeout = 10;
|
const timeout = 10;
|
||||||
|
|
||||||
if (WIN) {
|
if (util.WIN) {
|
||||||
this._bin = "c:/windows/system32/ping.exe";
|
this._bin = "c:/windows/system32/ping.exe";
|
||||||
this._args = (options.args) ? options.args : [ "-n", "1", "-w", timeout * 1000, host ];
|
this._args = (options.args) ? options.args : [ "-n", "1", "-w", timeout * 1000, host ];
|
||||||
this._regmatch = /[><=]([0-9.]+?)ms/;
|
this._regmatch = /[><=]([0-9.]+?)ms/;
|
||||||
|
|
||||||
} else if (LIN) {
|
} else if (util.LIN) {
|
||||||
this._bin = "/bin/ping";
|
this._bin = "/bin/ping";
|
||||||
|
|
||||||
const defaultArgs = [ "-n", "-w", timeout, "-c", "1", host ];
|
const defaultArgs = [ "-n", "-w", timeout, "-c", "1", host ];
|
||||||
@@ -40,7 +37,7 @@ function Ping(host, options) {
|
|||||||
this._args = (options.args) ? options.args : defaultArgs;
|
this._args = (options.args) ? options.args : defaultArgs;
|
||||||
this._regmatch = /=([0-9.]+?) ms/;
|
this._regmatch = /=([0-9.]+?) ms/;
|
||||||
|
|
||||||
} else if (MAC) {
|
} else if (util.MAC) {
|
||||||
|
|
||||||
if (net.isIPv6(host) || options.ipv6) {
|
if (net.isIPv6(host) || options.ipv6) {
|
||||||
this._bin = "/sbin/ping6";
|
this._bin = "/sbin/ping6";
|
||||||
@@ -51,7 +48,7 @@ function Ping(host, options) {
|
|||||||
this._args = (options.args) ? options.args : [ "-n", "-t", timeout, "-c", "1", host ];
|
this._args = (options.args) ? options.args : [ "-n", "-t", timeout, "-c", "1", host ];
|
||||||
this._regmatch = /=([0-9.]+?) ms/;
|
this._regmatch = /=([0-9.]+?) ms/;
|
||||||
|
|
||||||
} else if (FBSD) {
|
} else if (util.FBSD) {
|
||||||
this._bin = "/sbin/ping";
|
this._bin = "/sbin/ping";
|
||||||
|
|
||||||
const defaultArgs = [ "-n", "-t", timeout, "-c", "1", host ];
|
const defaultArgs = [ "-n", "-t", timeout, "-c", "1", host ];
|
||||||
@@ -101,6 +98,9 @@ Ping.prototype.send = function (callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._ping.stdout.on("data", function (data) { // log stdout
|
this._ping.stdout.on("data", function (data) { // log stdout
|
||||||
|
if (util.WIN) {
|
||||||
|
data = convertOutput(data);
|
||||||
|
}
|
||||||
this._stdout = (this._stdout || "") + data;
|
this._stdout = (this._stdout || "") + data;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -112,6 +112,9 @@ Ping.prototype.send = function (callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._ping.stderr.on("data", function (data) { // log stderr
|
this._ping.stderr.on("data", function (data) { // log stderr
|
||||||
|
if (util.WIN) {
|
||||||
|
data = convertOutput(data);
|
||||||
|
}
|
||||||
this._stderr = (this._stderr || "") + data;
|
this._stderr = (this._stderr || "") + data;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -157,3 +160,19 @@ Ping.prototype.start = function (callback) {
|
|||||||
Ping.prototype.stop = function () {
|
Ping.prototype.stop = function () {
|
||||||
clearInterval(this._i);
|
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 data
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function convertOutput(data) {
|
||||||
|
if (util.WIN) {
|
||||||
|
if (data) {
|
||||||
|
return util.convertToUTF8(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
39
server/rate-limiter.js
Normal file
39
server/rate-limiter.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const { RateLimiter } = require("limiter");
|
||||||
|
const { debug } = require("../src/util");
|
||||||
|
|
||||||
|
class KumaRateLimiter {
|
||||||
|
constructor(config) {
|
||||||
|
this.errorMessage = config.errorMessage;
|
||||||
|
this.rateLimiter = new RateLimiter(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
async pass(callback, num = 1) {
|
||||||
|
const remainingRequests = await this.removeTokens(num);
|
||||||
|
debug("Rate Limit (remainingRequests):" + remainingRequests);
|
||||||
|
if (remainingRequests < 0) {
|
||||||
|
if (callback) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: this.errorMessage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeTokens(num = 1) {
|
||||||
|
return await this.rateLimiter.removeTokens(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginRateLimiter = new KumaRateLimiter({
|
||||||
|
tokensPerInterval: 20,
|
||||||
|
interval: "minute",
|
||||||
|
fireImmediately: true,
|
||||||
|
errorMessage: "Too frequently, try again later."
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
loginRateLimiter
|
||||||
|
};
|
@@ -5,7 +5,7 @@ const server = require("../server");
|
|||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
const Monitor = require("../model/monitor");
|
const Monitor = require("../model/monitor");
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { UP } = require("../../src/util");
|
const { UP, flipStatus, debug } = require("../../src/util");
|
||||||
let router = express.Router();
|
let router = express.Router();
|
||||||
|
|
||||||
let cache = apicache.middleware;
|
let cache = apicache.middleware;
|
||||||
@@ -18,9 +18,10 @@ router.get("/api/entry-page", async (_, response) => {
|
|||||||
|
|
||||||
router.get("/api/push/:pushToken", async (request, response) => {
|
router.get("/api/push/:pushToken", async (request, response) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
let pushToken = request.params.pushToken;
|
let pushToken = request.params.pushToken;
|
||||||
let msg = request.query.msg || "OK";
|
let msg = request.query.msg || "OK";
|
||||||
let ping = request.query.ping;
|
let ping = request.query.ping || null;
|
||||||
|
|
||||||
let monitor = await R.findOne("monitor", " push_token = ? AND active = 1 ", [
|
let monitor = await R.findOne("monitor", " push_token = ? AND active = 1 ", [
|
||||||
pushToken
|
pushToken
|
||||||
@@ -30,12 +31,40 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
|||||||
throw new Error("Monitor not found or not active.");
|
throw new Error("Monitor not found or not active.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const previousHeartbeat = await R.getRow(`
|
||||||
|
SELECT status, time FROM heartbeat
|
||||||
|
WHERE id = (select MAX(id) from heartbeat where monitor_id = ?)
|
||||||
|
`, [
|
||||||
|
monitor.id
|
||||||
|
]);
|
||||||
|
|
||||||
|
let status = UP;
|
||||||
|
if (monitor.isUpsideDown()) {
|
||||||
|
status = flipStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
let isFirstBeat = true;
|
||||||
|
let previousStatus = status;
|
||||||
|
let duration = 0;
|
||||||
|
|
||||||
let bean = R.dispense("heartbeat");
|
let bean = R.dispense("heartbeat");
|
||||||
bean.monitor_id = monitor.id;
|
|
||||||
bean.time = R.isoDateTime(dayjs.utc());
|
bean.time = R.isoDateTime(dayjs.utc());
|
||||||
bean.status = UP;
|
|
||||||
|
if (previousHeartbeat) {
|
||||||
|
isFirstBeat = false;
|
||||||
|
previousStatus = previousHeartbeat.status;
|
||||||
|
duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("PreviousStatus: " + previousStatus);
|
||||||
|
debug("Current Status: " + status);
|
||||||
|
|
||||||
|
bean.important = Monitor.isImportantBeat(isFirstBeat, previousStatus, status);
|
||||||
|
bean.monitor_id = monitor.id;
|
||||||
|
bean.status = status;
|
||||||
bean.msg = msg;
|
bean.msg = msg;
|
||||||
bean.ping = ping;
|
bean.ping = ping;
|
||||||
|
bean.duration = duration;
|
||||||
|
|
||||||
await R.store(bean);
|
await R.store(bean);
|
||||||
|
|
||||||
@@ -45,6 +74,11 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
|||||||
response.json({
|
response.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (bean.important) {
|
||||||
|
await Monitor.sendNotification(isFirstBeat, monitor, bean);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
response.json({
|
response.json({
|
||||||
ok: false,
|
ok: false,
|
||||||
@@ -67,6 +101,10 @@ router.get("/api/status-page/config", async (_request, response) => {
|
|||||||
config.statusPagePublished = true;
|
config.statusPagePublished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! config.statusPageTags) {
|
||||||
|
config.statusPageTags = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (! config.title) {
|
if (! config.title) {
|
||||||
config.title = "Uptime Kuma";
|
config.title = "Uptime Kuma";
|
||||||
}
|
}
|
||||||
@@ -106,10 +144,25 @@ router.get("/api/status-page/monitor-list", cache("5 minutes"), async (_request,
|
|||||||
try {
|
try {
|
||||||
await checkPublished();
|
await checkPublished();
|
||||||
const publicGroupList = [];
|
const publicGroupList = [];
|
||||||
let list = await R.find("group", " public = 1 ORDER BY weight ");
|
const tagsVisible = (await getSettings("statusPage")).statusPageTags;
|
||||||
|
const list = await R.find("group", " public = 1 ORDER BY weight ");
|
||||||
for (let groupBean of list) {
|
for (let groupBean of list) {
|
||||||
publicGroupList.push(await groupBean.toPublicJSON());
|
let monitorGroup = await groupBean.toPublicJSON();
|
||||||
|
if (tagsVisible) {
|
||||||
|
monitorGroup.monitorList = await Promise.all(monitorGroup.monitorList.map(async (monitor) => {
|
||||||
|
// Includes tags as an array in response, allows for tags to be displayed on public status page
|
||||||
|
const tags = await R.getAll(
|
||||||
|
`SELECT monitor_tag.monitor_id, monitor_tag.value, tag.name, tag.color
|
||||||
|
FROM monitor_tag
|
||||||
|
JOIN tag
|
||||||
|
ON monitor_tag.tag_id = tag.id
|
||||||
|
WHERE monitor_tag.monitor_id = ?`, [monitor.id]
|
||||||
|
);
|
||||||
|
return {...monitor, tags: tags}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
publicGroupList.push(monitorGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.json(publicGroupList);
|
response.json(publicGroupList);
|
||||||
|
159
server/server.js
159
server/server.js
@@ -1,6 +1,7 @@
|
|||||||
console.log("Welcome to Uptime Kuma");
|
console.log("Welcome to Uptime Kuma");
|
||||||
const args = require("args-parser")(process.argv);
|
const args = require("args-parser")(process.argv);
|
||||||
const { sleep, debug, getRandomInt, genSecret } = require("../src/util");
|
const { sleep, debug, getRandomInt, genSecret } = require("../src/util");
|
||||||
|
const config = require("./config");
|
||||||
|
|
||||||
debug(args);
|
debug(args);
|
||||||
|
|
||||||
@@ -8,10 +9,6 @@ if (! process.env.NODE_ENV) {
|
|||||||
process.env.NODE_ENV = "production";
|
process.env.NODE_ENV = "production";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo Mode?
|
|
||||||
const demoMode = args["demo"] || false;
|
|
||||||
exports.demoMode = demoMode;
|
|
||||||
|
|
||||||
console.log("Node Env: " + process.env.NODE_ENV);
|
console.log("Node Env: " + process.env.NODE_ENV);
|
||||||
|
|
||||||
console.log("Importing Node libraries");
|
console.log("Importing Node libraries");
|
||||||
@@ -34,6 +31,7 @@ debug("Importing prometheus-api-metrics");
|
|||||||
const prometheusAPIMetrics = require("prometheus-api-metrics");
|
const prometheusAPIMetrics = require("prometheus-api-metrics");
|
||||||
debug("Importing compare-versions");
|
debug("Importing compare-versions");
|
||||||
const compareVersions = require("compare-versions");
|
const compareVersions = require("compare-versions");
|
||||||
|
const { passwordStrength } = require("check-password-strength");
|
||||||
|
|
||||||
debug("Importing 2FA Modules");
|
debug("Importing 2FA Modules");
|
||||||
const notp = require("notp");
|
const notp = require("notp");
|
||||||
@@ -43,7 +41,7 @@ console.log("Importing this project modules");
|
|||||||
debug("Importing Monitor");
|
debug("Importing Monitor");
|
||||||
const Monitor = require("./model/monitor");
|
const Monitor = require("./model/monitor");
|
||||||
debug("Importing Settings");
|
debug("Importing Settings");
|
||||||
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest } = require("./util-server");
|
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog } = require("./util-server");
|
||||||
|
|
||||||
debug("Importing Notification");
|
debug("Importing Notification");
|
||||||
const { Notification } = require("./notification");
|
const { Notification } = require("./notification");
|
||||||
@@ -52,6 +50,10 @@ Notification.init();
|
|||||||
debug("Importing Database");
|
debug("Importing Database");
|
||||||
const Database = require("./database");
|
const Database = require("./database");
|
||||||
|
|
||||||
|
debug("Importing Background Jobs");
|
||||||
|
const { initBackgroundJobs } = require("./jobs");
|
||||||
|
const { loginRateLimiter } = require("./rate-limiter");
|
||||||
|
|
||||||
const { basicAuth } = require("./auth");
|
const { basicAuth } = require("./auth");
|
||||||
const { login } = require("./auth");
|
const { login } = require("./auth");
|
||||||
const passwordHash = require("./password-hash");
|
const passwordHash = require("./password-hash");
|
||||||
@@ -61,12 +63,29 @@ console.info("Version: " + checkVersion.version);
|
|||||||
|
|
||||||
// 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.
|
// 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 (::)
|
// Dual-stack support for (::)
|
||||||
const hostname = process.env.HOST || args.host;
|
let hostname = process.env.UPTIME_KUMA_HOST || args.host;
|
||||||
const port = parseInt(process.env.PORT || args.port || 3001);
|
|
||||||
|
// Also read HOST if not FreeBSD, as HOST is a system environment variable in FreeBSD
|
||||||
|
if (!hostname && !FBSD) {
|
||||||
|
hostname = process.env.HOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hostname) {
|
||||||
|
console.log("Custom hostname: " + hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || args.port || 3001);
|
||||||
|
|
||||||
// SSL
|
// SSL
|
||||||
const sslKey = process.env.SSL_KEY || args["ssl-key"] || undefined;
|
const sslKey = process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || args["ssl-key"] || undefined;
|
||||||
const sslCert = process.env.SSL_CERT || args["ssl-cert"] || undefined;
|
const sslCert = process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || args["ssl-cert"] || undefined;
|
||||||
|
const disableFrameSameOrigin = !!process.env.UPTIME_KUMA_DISABLE_FRAME_SAMEORIGIN || args["disable-frame-sameorigin"] || false;
|
||||||
|
|
||||||
|
// 2FA / notp verification defaults
|
||||||
|
const twofa_verification_opts = {
|
||||||
|
"window": 1,
|
||||||
|
"time": 30
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run unit test after the server is ready
|
* Run unit test after the server is ready
|
||||||
@@ -74,7 +93,7 @@ const sslCert = process.env.SSL_CERT || args["ssl-cert"] || undefined;
|
|||||||
*/
|
*/
|
||||||
const testMode = !!args["test"] || false;
|
const testMode = !!args["test"] || false;
|
||||||
|
|
||||||
if (demoMode) {
|
if (config.demoMode) {
|
||||||
console.log("==== Demo Mode ====");
|
console.log("==== Demo Mode ====");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,9 +119,19 @@ module.exports.io = io;
|
|||||||
// Must be after io instantiation
|
// Must be after io instantiation
|
||||||
const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo } = require("./client");
|
const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo } = require("./client");
|
||||||
const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler");
|
const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler");
|
||||||
|
const databaseSocketHandler = require("./socket-handlers/database-socket-handler");
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Global Middleware
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
if (!disableFrameSameOrigin) {
|
||||||
|
res.setHeader("X-Frame-Options", "SAMEORIGIN");
|
||||||
|
}
|
||||||
|
res.removeHeader("X-Powered-By");
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total WebSocket client connected to server currently, no actual use
|
* Total WebSocket client connected to server currently, no actual use
|
||||||
* @type {number}
|
* @type {number}
|
||||||
@@ -131,7 +160,17 @@ let needSetup = false;
|
|||||||
* Cache Index HTML
|
* Cache Index HTML
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
let indexHTML = fs.readFileSync("./dist/index.html").toString();
|
let indexHTML = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
indexHTML = fs.readFileSync("./dist/index.html").toString();
|
||||||
|
} catch (e) {
|
||||||
|
// "dist/index.html" is not necessary for development
|
||||||
|
if (process.env.NODE_ENV !== "development") {
|
||||||
|
console.error("Error: Cannot find 'dist/index.html', did you install correctly?");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exports.entryPage = "dashboard";
|
exports.entryPage = "dashboard";
|
||||||
|
|
||||||
@@ -147,6 +186,15 @@ exports.entryPage = "dashboard";
|
|||||||
// Normal Router here
|
// Normal Router here
|
||||||
// ***************************
|
// ***************************
|
||||||
|
|
||||||
|
// Entry Page
|
||||||
|
app.get("/", async (_request, response) => {
|
||||||
|
if (exports.entryPage === "statusPage") {
|
||||||
|
response.redirect("/status");
|
||||||
|
} else {
|
||||||
|
response.redirect("/dashboard");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Robots.txt
|
// Robots.txt
|
||||||
app.get("/robots.txt", async (_request, response) => {
|
app.get("/robots.txt", async (_request, response) => {
|
||||||
let txt = "User-agent: *\nDisallow:";
|
let txt = "User-agent: *\nDisallow:";
|
||||||
@@ -176,7 +224,7 @@ exports.entryPage = "dashboard";
|
|||||||
const apiRouter = require("./routers/api-router");
|
const apiRouter = require("./routers/api-router");
|
||||||
app.use(apiRouter);
|
app.use(apiRouter);
|
||||||
|
|
||||||
// Universal Route Handler, must be at the end of all express route.
|
// Universal Route Handler, must be at the end of all express routes.
|
||||||
app.get("*", async (_request, response) => {
|
app.get("*", async (_request, response) => {
|
||||||
if (_request.originalUrl.startsWith("/upload/")) {
|
if (_request.originalUrl.startsWith("/upload/")) {
|
||||||
response.status(404).send("File not found.");
|
response.status(404).send("File not found.");
|
||||||
@@ -244,12 +292,16 @@ exports.entryPage = "dashboard";
|
|||||||
socket.on("login", async (data, callback) => {
|
socket.on("login", async (data, callback) => {
|
||||||
console.log("Login");
|
console.log("Login");
|
||||||
|
|
||||||
|
// Login Rate Limit
|
||||||
|
if (! await loginRateLimiter.pass(callback)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let user = await login(data.username, data.password);
|
let user = await login(data.username, data.password);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
afterLogin(socket, user);
|
if (user.twofa_status == 0) {
|
||||||
|
afterLogin(socket, user);
|
||||||
if (user.twofaStatus == 0) {
|
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
token: jwt.sign({
|
token: jwt.sign({
|
||||||
@@ -258,16 +310,23 @@ exports.entryPage = "dashboard";
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.twofaStatus == 1 && !data.token) {
|
if (user.twofa_status == 1 && !data.token) {
|
||||||
callback({
|
callback({
|
||||||
tokenRequired: true,
|
tokenRequired: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.token) {
|
if (data.token) {
|
||||||
let verify = notp.totp.verify(data.token, user.twofa_secret);
|
let verify = notp.totp.verify(data.token, user.twofa_secret, twofa_verification_opts);
|
||||||
|
|
||||||
|
if (user.twofa_last_token !== data.token && verify) {
|
||||||
|
afterLogin(socket, user);
|
||||||
|
|
||||||
|
await R.exec("UPDATE `user` SET twofa_last_token = ? WHERE id = ? ", [
|
||||||
|
data.token,
|
||||||
|
socket.userID,
|
||||||
|
]);
|
||||||
|
|
||||||
if (verify && verify.delta == 0) {
|
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
token: jwt.sign({
|
token: jwt.sign({
|
||||||
@@ -305,7 +364,7 @@ exports.entryPage = "dashboard";
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (user.twofa_status == 0) {
|
if (user.twofa_status == 0) {
|
||||||
let newSecret = await genSecret();
|
let newSecret = genSecret();
|
||||||
let encodedSecret = base32.encode(newSecret);
|
let encodedSecret = base32.encode(newSecret);
|
||||||
|
|
||||||
// Google authenticator doesn't like equal signs
|
// Google authenticator doesn't like equal signs
|
||||||
@@ -383,9 +442,9 @@ exports.entryPage = "dashboard";
|
|||||||
socket.userID,
|
socket.userID,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let verify = notp.totp.verify(token, user.twofa_secret);
|
let verify = notp.totp.verify(token, user.twofa_secret, twofa_verification_opts);
|
||||||
|
|
||||||
if (verify && verify.delta == 0) {
|
if (user.twofa_last_token !== token && verify) {
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
valid: true,
|
valid: true,
|
||||||
@@ -432,8 +491,12 @@ exports.entryPage = "dashboard";
|
|||||||
|
|
||||||
socket.on("setup", async (username, password, callback) => {
|
socket.on("setup", async (username, password, callback) => {
|
||||||
try {
|
try {
|
||||||
|
if (passwordStrength(password).value === "Too weak") {
|
||||||
|
throw new Error("Password is too weak. It should contain alphabetic and numeric characters. It must be at least 6 characters in length.");
|
||||||
|
}
|
||||||
|
|
||||||
if ((await R.count("user")) !== 0) {
|
if ((await R.count("user")) !== 0) {
|
||||||
throw new Error("Uptime Kuma has been setup. If you want to setup again, please delete the database.");
|
throw new Error("Uptime Kuma has been initialized. If you want to run setup again, please delete the database.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = R.dispense("user");
|
let user = R.dispense("user");
|
||||||
@@ -509,6 +572,9 @@ exports.entryPage = "dashboard";
|
|||||||
bean.name = monitor.name;
|
bean.name = monitor.name;
|
||||||
bean.type = monitor.type;
|
bean.type = monitor.type;
|
||||||
bean.url = monitor.url;
|
bean.url = monitor.url;
|
||||||
|
bean.method = monitor.method;
|
||||||
|
bean.body = monitor.body;
|
||||||
|
bean.headers = monitor.headers;
|
||||||
bean.interval = monitor.interval;
|
bean.interval = monitor.interval;
|
||||||
bean.retryInterval = monitor.retryInterval;
|
bean.retryInterval = monitor.retryInterval;
|
||||||
bean.hostname = monitor.hostname;
|
bean.hostname = monitor.hostname;
|
||||||
@@ -588,6 +654,38 @@ exports.entryPage = "dashboard";
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("getMonitorBeats", async (monitorID, period, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
console.log(`Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`);
|
||||||
|
|
||||||
|
if (period == null) {
|
||||||
|
throw new Error("Invalid period.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let list = await R.getAll(`
|
||||||
|
SELECT * FROM heartbeat
|
||||||
|
WHERE monitor_id = ? AND
|
||||||
|
time > DATETIME('now', '-' || ? || ' hours')
|
||||||
|
ORDER BY time ASC
|
||||||
|
`, [
|
||||||
|
monitorID,
|
||||||
|
period,
|
||||||
|
]);
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
data: list,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Start or Resume the monitor
|
// Start or Resume the monitor
|
||||||
socket.on("resumeMonitor", async (monitorID, callback) => {
|
socket.on("resumeMonitor", async (monitorID, callback) => {
|
||||||
try {
|
try {
|
||||||
@@ -818,10 +916,14 @@ exports.entryPage = "dashboard";
|
|||||||
try {
|
try {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
|
|
||||||
if (! password.currentPassword) {
|
if (! password.newPassword) {
|
||||||
throw new Error("Invalid new password");
|
throw new Error("Invalid new password");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (passwordStrength(password.newPassword).value === "Too weak") {
|
||||||
|
throw new Error("Password is too weak. It should contain alphabetic and numeric characters. It must be at least 6 characters in length.");
|
||||||
|
}
|
||||||
|
|
||||||
let user = await R.findOne("user", " id = ? AND active = 1 ", [
|
let user = await R.findOne("user", " id = ? AND active = 1 ", [
|
||||||
socket.userID,
|
socket.userID,
|
||||||
]);
|
]);
|
||||||
@@ -1034,6 +1136,9 @@ exports.entryPage = "dashboard";
|
|||||||
name: monitorListData[i].name,
|
name: monitorListData[i].name,
|
||||||
type: monitorListData[i].type,
|
type: monitorListData[i].type,
|
||||||
url: monitorListData[i].url,
|
url: monitorListData[i].url,
|
||||||
|
method: monitorListData[i].method || "GET",
|
||||||
|
body: monitorListData[i].body,
|
||||||
|
headers: monitorListData[i].headers,
|
||||||
interval: monitorListData[i].interval,
|
interval: monitorListData[i].interval,
|
||||||
retryInterval: retryInterval,
|
retryInterval: retryInterval,
|
||||||
hostname: monitorListData[i].hostname,
|
hostname: monitorListData[i].hostname,
|
||||||
@@ -1200,6 +1305,7 @@ exports.entryPage = "dashboard";
|
|||||||
|
|
||||||
// Status Page Socket Handler for admin only
|
// Status Page Socket Handler for admin only
|
||||||
statusPageSocketHandler(socket);
|
statusPageSocketHandler(socket);
|
||||||
|
databaseSocketHandler(socket);
|
||||||
|
|
||||||
debug("added all socket handlers");
|
debug("added all socket handlers");
|
||||||
|
|
||||||
@@ -1239,6 +1345,8 @@ exports.entryPage = "dashboard";
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
initBackgroundJobs(args);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
async function updateMonitorNotification(monitorID, notificationIDList) {
|
async function updateMonitorNotification(monitorID, notificationIDList) {
|
||||||
@@ -1315,7 +1423,7 @@ async function initDatabase() {
|
|||||||
fs.copyFileSync(Database.templatePath, Database.path);
|
fs.copyFileSync(Database.templatePath, Database.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Connecting to Database");
|
console.log("Connecting to the Database");
|
||||||
await Database.connect();
|
await Database.connect();
|
||||||
console.log("Connected");
|
console.log("Connected");
|
||||||
|
|
||||||
@@ -1415,7 +1523,7 @@ async function shutdownFunction(signal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function finalFunction() {
|
function finalFunction() {
|
||||||
console.log("Graceful shutdown successfully!");
|
console.log("Graceful shutdown successful!");
|
||||||
}
|
}
|
||||||
|
|
||||||
gracefulShutdown(server, {
|
gracefulShutdown(server, {
|
||||||
@@ -1430,5 +1538,6 @@ gracefulShutdown(server, {
|
|||||||
// Catch unexpected errors here
|
// Catch unexpected errors here
|
||||||
process.addListener("unhandledRejection", (error, promise) => {
|
process.addListener("unhandledRejection", (error, promise) => {
|
||||||
console.trace(error);
|
console.trace(error);
|
||||||
|
errorLog(error, false);
|
||||||
console.error("If you keep encountering errors, please report to https://github.com/louislam/uptime-kuma/issues");
|
console.error("If you keep encountering errors, please report to https://github.com/louislam/uptime-kuma/issues");
|
||||||
});
|
});
|
||||||
|
37
server/socket-handlers/database-socket-handler.js
Normal file
37
server/socket-handlers/database-socket-handler.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const { checkLogin } = require("../util-server");
|
||||||
|
const Database = require("../database");
|
||||||
|
|
||||||
|
module.exports = (socket) => {
|
||||||
|
|
||||||
|
// Post or edit incident
|
||||||
|
socket.on("getDatabaseSize", async (callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
size: Database.getSize(),
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("shrinkDatabase", async (callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
Database.shrink();
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
callback({
|
||||||
|
ok: false,
|
||||||
|
msg: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
@@ -6,6 +6,16 @@ const passwordHash = require("./password-hash");
|
|||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { Resolver } = require("dns");
|
const { Resolver } = require("dns");
|
||||||
const child_process = require("child_process");
|
const child_process = require("child_process");
|
||||||
|
const iconv = require("iconv-lite");
|
||||||
|
const chardet = require("chardet");
|
||||||
|
const fs = require("fs");
|
||||||
|
const nodeJsUtil = require("util");
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init or reset JWT secret
|
* Init or reset JWT secret
|
||||||
@@ -116,7 +126,7 @@ exports.setting = async function (key) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.setSetting = async function (key, value) {
|
exports.setSetting = async function (key, value, type = null) {
|
||||||
let bean = await R.findOne("setting", " `key` = ? ", [
|
let bean = await R.findOne("setting", " `key` = ? ", [
|
||||||
key,
|
key,
|
||||||
]);
|
]);
|
||||||
@@ -124,6 +134,7 @@ exports.setSetting = async function (key, value) {
|
|||||||
bean = R.dispense("setting");
|
bean = R.dispense("setting");
|
||||||
bean.key = key;
|
bean.key = key;
|
||||||
}
|
}
|
||||||
|
bean.type = type;
|
||||||
bean.value = JSON.stringify(value);
|
bean.value = JSON.stringify(value);
|
||||||
await R.store(bean);
|
await R.store(bean);
|
||||||
};
|
};
|
||||||
@@ -190,8 +201,13 @@ const getDaysRemaining = (validFrom, validTo) => {
|
|||||||
// param: info - the chain obtained from getPeerCertificate()
|
// param: info - the chain obtained from getPeerCertificate()
|
||||||
const parseCertificateInfo = function (info) {
|
const parseCertificateInfo = function (info) {
|
||||||
let link = info;
|
let link = info;
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
const existingList = {};
|
||||||
|
|
||||||
while (link) {
|
while (link) {
|
||||||
|
debug(`[${i}] ${link.fingerprint}`);
|
||||||
|
|
||||||
if (!link.valid_from || !link.valid_to) {
|
if (!link.valid_from || !link.valid_to) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -199,15 +215,24 @@ const parseCertificateInfo = function (info) {
|
|||||||
link.validFor = link.subjectaltname?.replace(/DNS:|IP Address:/g, "").split(", ");
|
link.validFor = link.subjectaltname?.replace(/DNS:|IP Address:/g, "").split(", ");
|
||||||
link.daysRemaining = getDaysRemaining(new Date(), link.validTo);
|
link.daysRemaining = getDaysRemaining(new Date(), link.validTo);
|
||||||
|
|
||||||
|
existingList[link.fingerprint] = true;
|
||||||
|
|
||||||
// Move up the chain until loop is encountered
|
// Move up the chain until loop is encountered
|
||||||
if (link.issuerCertificate == null) {
|
if (link.issuerCertificate == null) {
|
||||||
break;
|
break;
|
||||||
} else if (link.fingerprint == link.issuerCertificate.fingerprint) {
|
} else if (link.issuerCertificate.fingerprint in existingList) {
|
||||||
|
debug(`[Last] ${link.issuerCertificate.fingerprint}`);
|
||||||
link.issuerCertificate = null;
|
link.issuerCertificate = null;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
link = link.issuerCertificate;
|
link = link.issuerCertificate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be no use, but just in case.
|
||||||
|
if (i > 500) {
|
||||||
|
throw new Error("Dead loop occurred in parseCertificateInfo");
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
@@ -217,6 +242,7 @@ exports.checkCertificate = function (res) {
|
|||||||
const info = res.request.res.socket.getPeerCertificate(true);
|
const info = res.request.res.socket.getPeerCertificate(true);
|
||||||
const valid = res.request.res.socket.authorized || false;
|
const valid = res.request.res.socket.authorized || false;
|
||||||
|
|
||||||
|
debug("Parsing Certificate Info");
|
||||||
const parsedInfo = parseCertificateInfo(info);
|
const parsedInfo = parseCertificateInfo(info);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -312,3 +338,35 @@ exports.startUnitTest = async () => {
|
|||||||
process.exit(code);
|
process.exit(code);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param body : Buffer
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
exports.convertToUTF8 = (body) => {
|
||||||
|
const guessEncoding = chardet.detect(body);
|
||||||
|
//debug("Guess Encoding: " + guessEncoding);
|
||||||
|
const str = iconv.decode(body, guessEncoding);
|
||||||
|
return str.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
let logFile;
|
||||||
|
|
||||||
|
try {
|
||||||
|
logFile = fs.createWriteStream("./data/error.log", {
|
||||||
|
flags: "a"
|
||||||
|
});
|
||||||
|
} catch (_) { }
|
||||||
|
|
||||||
|
exports.errorLog = (error, outputToConsole = true) => {
|
||||||
|
try {
|
||||||
|
if (logFile) {
|
||||||
|
const dateTime = R.isoDateTime();
|
||||||
|
logFile.write(`[${dateTime}] ` + nodeJsUtil.format(error) + "\n");
|
||||||
|
|
||||||
|
if (outputToConsole) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) { }
|
||||||
|
};
|
||||||
|
@@ -14,6 +14,10 @@ h2 {
|
|||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea.form-control {
|
||||||
|
border-radius: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
}
|
}
|
||||||
@@ -185,7 +189,7 @@ h2 {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-hover > tbody > tr:hover {
|
.table-hover > tbody > tr:hover > * {
|
||||||
--bs-table-accent-bg: #070a10;
|
--bs-table-accent-bg: #070a10;
|
||||||
color: $dark-font-color;
|
color: $dark-font-color;
|
||||||
}
|
}
|
||||||
@@ -342,6 +346,10 @@ h2 {
|
|||||||
&.active {
|
&.active {
|
||||||
background-color: #cdf8f4;
|
background-color: #cdf8f4;
|
||||||
}
|
}
|
||||||
|
.tags {
|
||||||
|
// Removes margin to line up tags list with uptime percentage
|
||||||
|
margin-left: -0.25rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.multiselect__tag {
|
.multiselect__tag {
|
||||||
border-radius: 50rem;
|
border-radius: $border-radius;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
padding: 6px 26px 6px 10px;
|
padding: 6px 26px 6px 10px;
|
||||||
background: $primary !important;
|
background: $primary !important;
|
||||||
|
@@ -167,7 +167,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getBeatTitle(beat) {
|
getBeatTitle(beat) {
|
||||||
return `${this.$root.datetime(beat.time)} - ${beat.msg}`;
|
return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : ``);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ export default {
|
|||||||
.beat {
|
.beat {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: $primary;
|
background-color: $primary;
|
||||||
border-radius: 50rem;
|
border-radius: $border-radius;
|
||||||
|
|
||||||
&.empty {
|
&.empty {
|
||||||
background-color: aliceblue;
|
background-color: aliceblue;
|
||||||
|
@@ -1,16 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
<LineChart :chart-data="chartData" :options="chartOptions" />
|
<div>
|
||||||
|
<div class="period-options">
|
||||||
|
<button type="button" class="btn btn-light dropdown-toggle btn-period-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{{ chartPeriodOptions[chartPeriodHrs] }}
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li v-for="(item, key) in chartPeriodOptions" :key="key">
|
||||||
|
<a class="dropdown-item" :class="{ active: chartPeriodHrs == key }" href="#" @click="chartPeriodHrs = key">{{ item }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="chart-wrapper" :class="{ loading : loading}">
|
||||||
|
<LineChart :chart-data="chartData" :options="chartOptions" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { BarController, BarElement, Chart, Filler, LinearScale, LineController, LineElement, PointElement, TimeScale, Tooltip } from "chart.js";
|
import { BarController, BarElement, Chart, Filler, LinearScale, LineController, LineElement, PointElement, TimeScale, Tooltip } from "chart.js";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import utc from "dayjs/plugin/utc";
|
import utc from "dayjs/plugin/utc";
|
||||||
import timezone from "dayjs/plugin/timezone";
|
import timezone from "dayjs/plugin/timezone";
|
||||||
import "chartjs-adapter-dayjs";
|
import "chartjs-adapter-dayjs";
|
||||||
import { LineChart } from "vue-chart-3";
|
import { LineChart } from "vue-chart-3";
|
||||||
|
import { useToast } from "vue-toastification";
|
||||||
|
import { UP, DOWN, PENDING } from "../util.ts";
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler);
|
Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler);
|
||||||
|
|
||||||
@@ -24,8 +42,23 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
|
loading: false,
|
||||||
|
|
||||||
// Configurable filtering on top of the returned data
|
// Configurable filtering on top of the returned data
|
||||||
chartPeriodHrs: 6,
|
chartPeriodHrs: 0,
|
||||||
|
|
||||||
|
chartPeriodOptions: {
|
||||||
|
0: this.$t("recent"),
|
||||||
|
3: "3h",
|
||||||
|
6: "6h",
|
||||||
|
24: "24h",
|
||||||
|
168: "1w",
|
||||||
|
},
|
||||||
|
|
||||||
|
// A heartbeatList for 3h, 6h, 24h, 1w
|
||||||
|
// Uses the $root.heartbeatList when value is null
|
||||||
|
heartbeatList: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -117,7 +150,7 @@ export default {
|
|||||||
},
|
},
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: (context) => {
|
label: (context) => {
|
||||||
return ` ${new Intl.NumberFormat().format(context.parsed.y)} ms`
|
return ` ${new Intl.NumberFormat().format(context.parsed.y)} ms`;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -125,27 +158,36 @@ export default {
|
|||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
chartData() {
|
chartData() {
|
||||||
let pingData = []; // Ping Data for Line Chart, y-axis contains ping time
|
let pingData = []; // Ping Data for Line Chart, y-axis contains ping time
|
||||||
let downData = []; // Down Data for Bar Chart, y-axis is 1 if target is down, 0 if target is up
|
let downData = []; // Down Data for Bar Chart, y-axis is 1 if target is down, 0 if target is up
|
||||||
if (this.monitorId in this.$root.heartbeatList) {
|
|
||||||
this.$root.heartbeatList[this.monitorId]
|
let heartbeatList = this.heartbeatList ||
|
||||||
.filter(
|
(this.monitorId in this.$root.heartbeatList && this.$root.heartbeatList[this.monitorId]) ||
|
||||||
(beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter(dayjs().subtract(this.chartPeriodHrs, "hours")))
|
[];
|
||||||
.map((beat) => {
|
|
||||||
const x = this.$root.datetime(beat.time);
|
heartbeatList
|
||||||
pingData.push({
|
.filter(
|
||||||
x,
|
// Filtering as data gets appended
|
||||||
y: beat.ping,
|
// not the most efficient, but works for now
|
||||||
});
|
(beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter(
|
||||||
downData.push({
|
dayjs().subtract(Math.max(this.chartPeriodHrs, 6), "hours")
|
||||||
x,
|
)
|
||||||
y: beat.status === 0 ? 1 : 0,
|
)
|
||||||
})
|
.map((beat) => {
|
||||||
|
const x = this.$root.datetime(beat.time);
|
||||||
|
pingData.push({
|
||||||
|
x,
|
||||||
|
y: beat.ping,
|
||||||
});
|
});
|
||||||
}
|
downData.push({
|
||||||
|
x,
|
||||||
|
y: beat.status === DOWN ? 1 : 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
@@ -172,5 +214,110 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
// Update chart data when the selected chart period changes
|
||||||
|
chartPeriodHrs: function (newPeriod) {
|
||||||
|
if (newPeriod == "0") {
|
||||||
|
newPeriod = null;
|
||||||
|
this.heartbeatList = null;
|
||||||
|
} else {
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
this.$root.getMonitorBeats(this.monitorId, newPeriod, (res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
toast.error(res.msg);
|
||||||
|
} else {
|
||||||
|
this.heartbeatList = res.data;
|
||||||
|
}
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// Setup Watcher on the root heartbeatList,
|
||||||
|
// And mirror latest change to this.heartbeatList
|
||||||
|
this.$watch(() => this.$root.heartbeatList[this.monitorId],
|
||||||
|
(heartbeatList) => {
|
||||||
|
if (this.chartPeriodHrs != 0) {
|
||||||
|
const newBeat = heartbeatList.at(-1);
|
||||||
|
if (newBeat && dayjs.utc(newBeat.time) > dayjs.utc(this.heartbeatList.at(-1)?.time)) {
|
||||||
|
this.heartbeatList.push(heartbeatList.at(-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../assets/vars.scss";
|
||||||
|
|
||||||
|
.form-select {
|
||||||
|
width: unset;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.period-options {
|
||||||
|
padding: 0.1em 1em;
|
||||||
|
margin-bottom: -1.2em;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
padding: 0;
|
||||||
|
min-width: 50px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
background: $dark-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
padding: 2px 16px 4px 16px;
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
background: $dark-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark &:hover {
|
||||||
|
background: $dark-font-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark & .dropdown-item.active {
|
||||||
|
background: $primary;
|
||||||
|
color: $dark-font-color2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-period-toggle {
|
||||||
|
padding: 2px 15px;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
color: $link-color;
|
||||||
|
opacity: 0.7;
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
vertical-align: 0.155em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
color: $dark-font-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-wrapper {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -41,6 +41,9 @@
|
|||||||
<Uptime :monitor="monitor.element" type="24" :pill="true" />
|
<Uptime :monitor="monitor.element" type="24" :pill="true" />
|
||||||
{{ monitor.element.name }}
|
{{ monitor.element.name }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tags">
|
||||||
|
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :key="$root.userHeartbeatBar" class="col-3 col-md-4">
|
<div :key="$root.userHeartbeatBar" class="col-3 col-md-4">
|
||||||
<HeartbeatBar size="small" :monitor-id="monitor.element.id" />
|
<HeartbeatBar size="small" :monitor-id="monitor.element.id" />
|
||||||
@@ -59,12 +62,14 @@
|
|||||||
import Draggable from "vuedraggable";
|
import Draggable from "vuedraggable";
|
||||||
import HeartbeatBar from "./HeartbeatBar.vue";
|
import HeartbeatBar from "./HeartbeatBar.vue";
|
||||||
import Uptime from "./Uptime.vue";
|
import Uptime from "./Uptime.vue";
|
||||||
|
import Tag from "./Tag.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Draggable,
|
Draggable,
|
||||||
HeartbeatBar,
|
HeartbeatBar,
|
||||||
Uptime,
|
Uptime,
|
||||||
|
Tag,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
editMode: {
|
editMode: {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<span :class="className">{{ uptime }}</span>
|
<span :class="className" :title="24 + $t('-hour')">{{ uptime }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
25
src/components/notifications/AliyunSms.vue
Normal file
25
src/components/notifications/AliyunSms.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="accessKeyId" class="form-label">{{ $t("AccessKeyId") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="accessKeyId" v-model="$parent.notification.accessKeyId" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<label for="secretAccessKey" class="form-label">{{ $t("SecretAccessKey") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="secretAccessKey" v-model="$parent.notification.secretAccessKey" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<label for="phonenumber" class="form-label">{{ $t("Phonenumber") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="phonenumber" v-model="$parent.notification.phonenumber" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<label for="templateCode" class="form-label">{{ $t("TemplateCode") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="templateCode" v-model="$parent.notification.templateCode" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<label for="signName" class="form-label">{{ $t("SignName") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="signName" v-model="$parent.notification.signName" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<div class="form-text">
|
||||||
|
<p>Sms template must contain parameters: <br> <code>${name} ${time} ${status} ${msg}</code></p>
|
||||||
|
<i18n-t tag="p" keypath="Read more:">
|
||||||
|
<a href="https://help.aliyun.com/document_detail/101414.html" target="_blank">https://help.aliyun.com/document_detail/101414.html</a>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
15
src/components/notifications/Bark.vue
Normal file
15
src/components/notifications/Bark.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="Bark Endpoint" class="form-label">{{ $t("Bark Endpoint") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="Bark Endpoint" v-model="$parent.notification.barkEndpoint" type="text" class="form-control" required>
|
||||||
|
<div class="form-text">
|
||||||
|
<p><span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}</p>
|
||||||
|
</div>
|
||||||
|
<i18n-t tag="div" keypath="wayToGetTeamsURL" class="form-text">
|
||||||
|
<a
|
||||||
|
href="https://github.com/Finb/Bark"
|
||||||
|
target="_blank"
|
||||||
|
>{{ $t("here") }}</a>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
</template>
|
38
src/components/notifications/ClickSendSMS.vue
Normal file
38
src/components/notifications/ClickSendSMS.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="clicksendsms-login" class="form-label">API Username</label>
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("apiCredentials") }}
|
||||||
|
<a href="http://dashboard.clicksend.com/account/subaccounts" target="_blank">here</a>
|
||||||
|
</div>
|
||||||
|
<input id="clicksendsms-login" v-model="$parent.notification.clicksendsmsLogin" type="text" class="form-control" required>
|
||||||
|
<label for="clicksendsms-key" class="form-label">API Key</label>
|
||||||
|
<HiddenInput id="clicksendsms-key" v-model="$parent.notification.clicksendsmsPassword" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("checkPrice", [$t("clicksendsms")]) }}
|
||||||
|
<a href="https://www.clicksend.com/us/pricing" target="_blank">https://clicksend.com/us/pricing</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="clicksendsms-to-number" class="form-label">Recipient Number</label>
|
||||||
|
<input id="clicksendsms-to-number" v-model="$parent.notification.clicksendsmsToNumber" type="text" minlength="8" maxlength="14" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="clicksendsms-sender-name" class="form-label">From Name/Number -
|
||||||
|
<a href="https://help.clicksend.com/article/4kgj7krx00-what-is-a-sender-id-or-sender-number" target="_blank">More Info</a>
|
||||||
|
</label>
|
||||||
|
<input id="clicksendsms-sender-name" v-model="$parent.notification.clicksendsmsSenderName" type="text" minlength="3" maxlength="11" class="form-control">
|
||||||
|
<div class="form-text">Leave blank to use a shared sender number.</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import HiddenInput from "../HiddenInput.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HiddenInput,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
16
src/components/notifications/DingDing.vue
Normal file
16
src/components/notifications/DingDing.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="WebHookUrl" class="form-label">{{ $t("WebHookUrl") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="WebHookUrl" v-model="$parent.notification.webHookUrl" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<label for="secretKey" class="form-label">{{ $t("SecretKey") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="secretKey" v-model="$parent.notification.secretKey" type="text" class="form-control" required>
|
||||||
|
|
||||||
|
<div class="form-text">
|
||||||
|
<p>For safety, must use secret key</p>
|
||||||
|
<i18n-t tag="p" keypath="Read more:">
|
||||||
|
<a href="https://developers.dingtalk.com/document/robots/custom-robot-access" target="_blank">https://developers.dingtalk.com/document/robots/custom-robot-access</a>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
15
src/components/notifications/Feishu.vue
Normal file
15
src/components/notifications/Feishu.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="Feishu-WebHookUrl" class="form-label">{{ $t("Feishu WebHookUrl") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="Feishu-WebHookUrl" v-model="$parent.notification.feishuWebHookUrl" type="text" class="form-control" required>
|
||||||
|
<div class="form-text">
|
||||||
|
<p><span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}</p>
|
||||||
|
</div>
|
||||||
|
<i18n-t tag="div" keypath="wayToGetTeamsURL" class="form-text">
|
||||||
|
<a
|
||||||
|
href="https://www.feishu.cn/hc/zh-CN/articles/360024984973"
|
||||||
|
target="_blank"
|
||||||
|
>{{ $t("here") }}</a>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
</template>
|
@@ -1,25 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="homeserver-url" class="form-label">Homeserver URL (with http(s):// and optionally port)</label><span style="color: red;"><sup>*</sup></span>
|
<label for="homeserver-url" class="form-label">{{ $t("matrixHomeserverURL") }}</label><span style="color: red;"><sup>*</sup></span>
|
||||||
<input id="homeserver-url" v-model="$parent.notification.homeserverUrl" type="text" class="form-control" :required="true">
|
<input id="homeserver-url" v-model="$parent.notification.homeserverUrl" type="text" class="form-control" :required="true">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="internal-room-id" class="form-label">Internal Room Id</label><span style="color: red;"><sup>*</sup></span>
|
<label for="internal-room-id" class="form-label">{{ $t("Internal Room Id") }}</label><span style="color: red;"><sup>*</sup></span>
|
||||||
<input id="internal-room-id" v-model="$parent.notification.internalRoomId" type="text" class="form-control" required="true">
|
<input id="internal-room-id" v-model="$parent.notification.internalRoomId" type="text" class="form-control" required="true">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="access-token" class="form-label">Access Token</label><span style="color: red;"><sup>*</sup></span>
|
<label for="access-token" class="form-label">{{ $t("Access Token") }}</label><span style="color: red;"><sup>*</sup></span>
|
||||||
<HiddenInput id="access-token" v-model="$parent.notification.accessToken" :required="true" autocomplete="one-time-code" :maxlength="500"></HiddenInput>
|
<HiddenInput id="access-token" v-model="$parent.notification.accessToken" :required="true" autocomplete="one-time-code" :maxlength="500"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<span style="color: red;"><sup>*</sup></span>Required
|
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
||||||
<p style="margin-top: 8px;">
|
<p style="margin-top: 8px;">
|
||||||
You can find the internal room ID by looking in the advanced section of the room settings in your Matrix client. It should look like !QMdRCpUIfLwsfjxye6:home.server.
|
{{ $t("matrixDesc1") }}
|
||||||
</p>
|
|
||||||
<p style="margin-top: 8px;">
|
|
||||||
It is highly recommended you create a new user and do not use your own Matrix user's access token as it will allow full access to your account and all the rooms you joined. Instead, create a new user and only invite it to the room that you want to receive the notification in. You can get the access token by running <code>curl -XPOST -d '{"type": "m.login.password", "identifier": {"user": "botusername", "type": "m.id.user"}, "password": "passwordforuser"}' "https://home.server/_matrix/client/r0/login"</code>.
|
|
||||||
</p>
|
</p>
|
||||||
|
<i18n-t tag="p" keypath="matrixDesc2" style="margin-top: 8px;">
|
||||||
|
<code>curl -XPOST -d '{"type": "m.login.password", "identifier": {"user": "botusername", "type": "m.id.user"}, "password": "passwordforuser"}' "https://home.server/_matrix/client/r0/login"</code>.
|
||||||
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -30,5 +30,5 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
HiddenInput,
|
HiddenInput,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
<option value="1">Legacy Octopush-DM (endpoint: www.octopush-dm.com)</option>
|
<option value="1">Legacy Octopush-DM (endpoint: www.octopush-dm.com)</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
Do you use the legacy version of Octopush (2011-2020) or the new version?
|
{{ $t("octopushLegacyHint") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@@ -10,12 +10,13 @@
|
|||||||
<select id="promosms-type-sms" v-model="$parent.notification.promosmsSMSType" class="form-select">
|
<select id="promosms-type-sms" v-model="$parent.notification.promosmsSMSType" class="form-select">
|
||||||
<option value="0">{{ $t("promosmsTypeFlash") }}</option>
|
<option value="0">{{ $t("promosmsTypeFlash") }}</option>
|
||||||
<option value="1">{{ $t("promosmsTypeEco") }}</option>
|
<option value="1">{{ $t("promosmsTypeEco") }}</option>
|
||||||
<option value="2">{{ $t("promosmsTypeFull") }}</option>
|
<option value="3">{{ $t("promosmsTypeFull") }}</option>
|
||||||
<option value="3">{{ $t("promosmsTypeSpeed") }}</option>
|
<option value="4">{{ $t("promosmsTypeSpeed") }}</option>
|
||||||
</select>
|
</select>
|
||||||
<i18n-t tag="div" keypath="Check PromoSMS prices" class="form-text">
|
<div class="form-text">
|
||||||
|
{{ $t("checkPrice", [$t("promosms")]) }}
|
||||||
<a href="https://promosms.com/cennik/" target="_blank">https://promosms.com/cennik/</a>
|
<a href="https://promosms.com/cennik/" target="_blank">https://promosms.com/cennik/</a>
|
||||||
</i18n-t>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="promosms-phone-number" class="form-label">{{ $t("promosmsPhoneNumber") }}</label>
|
<label for="promosms-phone-number" class="form-label">{{ $t("promosmsPhoneNumber") }}</label>
|
||||||
@@ -25,7 +26,6 @@
|
|||||||
<label for="promosms-sender-name" class="form-label">{{ $t("promosmsSMSSender") }}</label>
|
<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">
|
<input id="promosms-sender-name" v-model="$parent.notification.promosmsSenderName" type="text" minlength="3" maxlength="11" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
||||||
<i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;">
|
<i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;">
|
||||||
<a href="https://docs.rocket.chat/guides/administration/administration/integrations" target="_blank">https://api.slack.com/messaging/webhooks</a>
|
<a href="https://docs.rocket.chat/guides/administration/administration/integrations" target="_blank">https://docs.rocket.chat/guides/administration/administration/integrations</a>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
<p style="margin-top: 8px;">
|
<p style="margin-top: 8px;">
|
||||||
{{ $t("aboutChannelName", [$t("rocket.chat")]) }}
|
{{ $t("aboutChannelName", [$t("rocket.chat")]) }}
|
||||||
|
@@ -57,6 +57,18 @@
|
|||||||
<label for="to-bcc" class="form-label">{{ $t("smtpBCC") }}</label>
|
<label for="to-bcc" class="form-label">{{ $t("smtpBCC") }}</label>
|
||||||
<input id="to-bcc" v-model="$parent.notification.smtpBCC" type="text" class="form-control" autocomplete="false" :required="!hasRecipient">
|
<input id="to-bcc" v-model="$parent.notification.smtpBCC" type="text" class="form-control" autocomplete="false" :required="!hasRecipient">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="subject-email" class="form-label">{{ $t("emailCustomSubject") }}</label>
|
||||||
|
<input id="subject-email" v-model="$parent.notification.customSubject" type="text" class="form-control" autocomplete="false" placeholder="">
|
||||||
|
<div v-pre class="form-text">
|
||||||
|
(leave blank for default one)<br />
|
||||||
|
{{NAME}}: Service Name<br />
|
||||||
|
{{HOSTNAME_OR_URL}}: Hostname or URL<br />
|
||||||
|
{{URL}}: URL<br />
|
||||||
|
{{STATUS}}: Status<br />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="telegram-bot-token" class="form-label">{{ $t("Bot Token") }}</label>
|
<label for="telegram-bot-token" class="form-label">{{ $t("Bot Token") }}</label>
|
||||||
<HiddenInput id="telegram-bot-token" v-model="$parent.notification.telegramBotToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
<HiddenInput id="telegram-bot-token" v-model="$parent.notification.telegramBotToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
<div class="form-text">
|
<i18n-t tag="div" keypath="wayToGetTelegramToken" class="form-text">
|
||||||
{{ $t("You can get a token from") }} <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>.
|
<a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>
|
||||||
</div>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<p>"application/json" is good for any modern http servers such as express.js</p>
|
<p>{{ $t("webhookJsonDesc", ["\"application/json\""]) }}</p>
|
||||||
<i18n-t tag="p" keypath="webhookFormDataDesc">
|
<i18n-t tag="p" keypath="webhookFormDataDesc">
|
||||||
<template #multipart>"multipart/form-data"</template>
|
<template #multipart>"multipart/form-data"</template>
|
||||||
<template #decodeFunction>
|
<template #decodeFunction>
|
||||||
|
@@ -11,12 +11,17 @@ import Pushover from "./Pushover.vue";
|
|||||||
import Pushy from "./Pushy.vue";
|
import Pushy from "./Pushy.vue";
|
||||||
import Octopush from "./Octopush.vue";
|
import Octopush from "./Octopush.vue";
|
||||||
import PromoSMS from "./PromoSMS.vue";
|
import PromoSMS from "./PromoSMS.vue";
|
||||||
|
import ClickSendSMS from "./ClickSendSMS.vue";
|
||||||
import LunaSea from "./LunaSea.vue";
|
import LunaSea from "./LunaSea.vue";
|
||||||
|
import Feishu from "./Feishu.vue";
|
||||||
import Apprise from "./Apprise.vue";
|
import Apprise from "./Apprise.vue";
|
||||||
import Pushbullet from "./Pushbullet.vue";
|
import Pushbullet from "./Pushbullet.vue";
|
||||||
import Line from "./Line.vue";
|
import Line from "./Line.vue";
|
||||||
import Mattermost from "./Mattermost.vue";
|
import Mattermost from "./Mattermost.vue";
|
||||||
import Matrix from "./Matrix.vue";
|
import Matrix from "./Matrix.vue";
|
||||||
|
import AliyunSMS from "./AliyunSms.vue";
|
||||||
|
import DingDing from "./DingDing.vue";
|
||||||
|
import Bark from "./Bark.vue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage all notification form.
|
* Manage all notification form.
|
||||||
@@ -37,12 +42,17 @@ const NotificationFormList = {
|
|||||||
"pushy": Pushy,
|
"pushy": Pushy,
|
||||||
"octopush": Octopush,
|
"octopush": Octopush,
|
||||||
"promosms": PromoSMS,
|
"promosms": PromoSMS,
|
||||||
|
"clicksendsms": ClickSendSMS,
|
||||||
"lunasea": LunaSea,
|
"lunasea": LunaSea,
|
||||||
|
"Feishu": Feishu,
|
||||||
|
"AliyunSMS": AliyunSMS,
|
||||||
"apprise": Apprise,
|
"apprise": Apprise,
|
||||||
"pushbullet": Pushbullet,
|
"pushbullet": Pushbullet,
|
||||||
"line": Line,
|
"line": Line,
|
||||||
"mattermost": Mattermost,
|
"mattermost": Mattermost,
|
||||||
"matrix": Matrix,
|
"matrix": Matrix,
|
||||||
|
"DingDing": DingDing,
|
||||||
|
"Bark": Bark
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NotificationFormList
|
export default NotificationFormList
|
||||||
|
10
src/i18n.js
10
src/i18n.js
@@ -7,10 +7,13 @@ import etEE from "./languages/et-EE";
|
|||||||
import fa from "./languages/fa";
|
import fa from "./languages/fa";
|
||||||
import frFR from "./languages/fr-FR";
|
import frFR from "./languages/fr-FR";
|
||||||
import hu from "./languages/hu";
|
import hu from "./languages/hu";
|
||||||
|
import hrHR from "./languages/hr-HR";
|
||||||
import itIT from "./languages/it-IT";
|
import itIT from "./languages/it-IT";
|
||||||
|
import idID from "./languages/id-ID";
|
||||||
import ja from "./languages/ja";
|
import ja from "./languages/ja";
|
||||||
import koKR from "./languages/ko-KR";
|
import koKR from "./languages/ko-KR";
|
||||||
import nlNL from "./languages/nl-NL";
|
import nlNL from "./languages/nl-NL";
|
||||||
|
import nbNO from "./languages/nb-NO";
|
||||||
import pl from "./languages/pl";
|
import pl from "./languages/pl";
|
||||||
import ptBR from "./languages/pt-BR";
|
import ptBR from "./languages/pt-BR";
|
||||||
import bgBG from "./languages/bg-BG";
|
import bgBG from "./languages/bg-BG";
|
||||||
@@ -19,8 +22,10 @@ import sr from "./languages/sr";
|
|||||||
import srLatn from "./languages/sr-latn";
|
import srLatn from "./languages/sr-latn";
|
||||||
import svSE from "./languages/sv-SE";
|
import svSE from "./languages/sv-SE";
|
||||||
import trTR from "./languages/tr-TR";
|
import trTR from "./languages/tr-TR";
|
||||||
|
import vi from "./languages/vi";
|
||||||
import zhCN from "./languages/zh-CN";
|
import zhCN from "./languages/zh-CN";
|
||||||
import zhHK from "./languages/zh-HK";
|
import zhHK from "./languages/zh-HK";
|
||||||
|
import zhTW from "./languages/zh-TW";
|
||||||
|
|
||||||
const languageList = {
|
const languageList = {
|
||||||
en,
|
en,
|
||||||
@@ -28,12 +33,15 @@ const languageList = {
|
|||||||
"bg-BG": bgBG,
|
"bg-BG": bgBG,
|
||||||
"de-DE": deDE,
|
"de-DE": deDE,
|
||||||
"nl-NL": nlNL,
|
"nl-NL": nlNL,
|
||||||
|
"nb-NO": nbNO,
|
||||||
"es-ES": esEs,
|
"es-ES": esEs,
|
||||||
"fa": fa,
|
"fa": fa,
|
||||||
"pt-BR": ptBR,
|
"pt-BR": ptBR,
|
||||||
"fr-FR": frFR,
|
"fr-FR": frFR,
|
||||||
"hu": hu,
|
"hu": hu,
|
||||||
|
"hr-HR": hrHR,
|
||||||
"it-IT": itIT,
|
"it-IT": itIT,
|
||||||
|
"id-ID" : idID,
|
||||||
"ja": ja,
|
"ja": ja,
|
||||||
"da-DK": daDK,
|
"da-DK": daDK,
|
||||||
"sr": sr,
|
"sr": sr,
|
||||||
@@ -45,6 +53,8 @@ const languageList = {
|
|||||||
"zh-CN": zhCN,
|
"zh-CN": zhCN,
|
||||||
"pl": pl,
|
"pl": pl,
|
||||||
"et-EE": etEE,
|
"et-EE": etEE,
|
||||||
|
"vi": vi,
|
||||||
|
"zh-TW": zhTW
|
||||||
};
|
};
|
||||||
|
|
||||||
const rtlLangs = ["fa"];
|
const rtlLangs = ["fa"];
|
||||||
|
@@ -2,11 +2,11 @@ export default {
|
|||||||
languageName: "Български",
|
languageName: "Български",
|
||||||
checkEverySecond: "Ще се извършва на всеки {0} секунди",
|
checkEverySecond: "Ще се извършва на всеки {0} секунди",
|
||||||
retryCheckEverySecond: "Ще се извършва на всеки {0} секунди",
|
retryCheckEverySecond: "Ще се извършва на всеки {0} секунди",
|
||||||
retriesDescription: "Максимакен брой опити преди услугата да бъде маркирана като недостъпна и да бъде изпратено известие",
|
retriesDescription: "Максимакен брой опити преди маркиране на услугата като недостъпна и изпращане на известие",
|
||||||
ignoreTLSError: "Игнорирай TLS/SSL грешки за HTTPS уебсайтове",
|
ignoreTLSError: "Игнорирай TLS/SSL грешки за HTTPS уебсайтове",
|
||||||
upsideDownModeDescription: "Обърни статуса от достъпен на недостъпен. Ако услугата е достъпна се вижда НЕДОСТЪПНА.",
|
upsideDownModeDescription: "Обръща статуса от достъпен на недостъпен. Ако услугата е достъпна, ще се вижда като НЕДОСТЪПНА.",
|
||||||
maxRedirectDescription: "Максимален брой пренасочвания, които да бъдат следвани. Въведете 0 за да изключите пренасочване.",
|
maxRedirectDescription: "Максимален брой пренасочвания, които да бъдат следвани. Въведете 0 за да изключите пренасочване.",
|
||||||
acceptedStatusCodesDescription: "Изберете статус кодове, които се считат за успешен отговор.",
|
acceptedStatusCodesDescription: "Изберете статус кодове, които да се считат за успешен отговор.",
|
||||||
passwordNotMatchMsg: "Повторената парола не съвпада.",
|
passwordNotMatchMsg: "Повторената парола не съвпада.",
|
||||||
notificationDescription: "Моля, задайте известието към монитор(и), за да функционира.",
|
notificationDescription: "Моля, задайте известието към монитор(и), за да функционира.",
|
||||||
keywordDescription: "Търси ключова дума в чист html или JSON отговор - чувствителна е към регистъра",
|
keywordDescription: "Търси ключова дума в чист html или JSON отговор - чувствителна е към регистъра",
|
||||||
@@ -48,7 +48,7 @@ export default {
|
|||||||
Status: "Статус",
|
Status: "Статус",
|
||||||
DateTime: "Дата и час",
|
DateTime: "Дата и час",
|
||||||
Message: "Отговор",
|
Message: "Отговор",
|
||||||
"No important events": "Няма важни събития",
|
"No important events": "Все още няма събития",
|
||||||
Resume: "Възобнови",
|
Resume: "Възобнови",
|
||||||
Edit: "Редактирай",
|
Edit: "Редактирай",
|
||||||
Delete: "Изтрий",
|
Delete: "Изтрий",
|
||||||
@@ -77,7 +77,7 @@ export default {
|
|||||||
"Accepted Status Codes": "Допустими статус кодове",
|
"Accepted Status Codes": "Допустими статус кодове",
|
||||||
Save: "Запази",
|
Save: "Запази",
|
||||||
Notifications: "Известявания",
|
Notifications: "Известявания",
|
||||||
"Not available, please setup.": "Не е налично. Моля, настройте.",
|
"Not available, please setup.": "Не са налични. Моля, настройте.",
|
||||||
"Setup Notification": "Настройки за известявания",
|
"Setup Notification": "Настройки за известявания",
|
||||||
Light: "Светла",
|
Light: "Светла",
|
||||||
Dark: "Тъмна",
|
Dark: "Тъмна",
|
||||||
@@ -107,8 +107,8 @@ export default {
|
|||||||
Password: "Парола",
|
Password: "Парола",
|
||||||
"Remember me": "Запомни ме",
|
"Remember me": "Запомни ме",
|
||||||
Login: "Вход",
|
Login: "Вход",
|
||||||
"No Monitors, please": "Моля, без монитори",
|
"No Monitors, please": "Все още няма монитори. Моля, добавете поне ",
|
||||||
"add one": "добави един",
|
"add one": "един.",
|
||||||
"Notification Type": "Тип известяване",
|
"Notification Type": "Тип известяване",
|
||||||
Email: "Имейл",
|
Email: "Имейл",
|
||||||
Test: "Тест",
|
Test: "Тест",
|
||||||
@@ -130,7 +130,7 @@ export default {
|
|||||||
"Clear Data": "Изтрий данни",
|
"Clear Data": "Изтрий данни",
|
||||||
Events: "Събития",
|
Events: "Събития",
|
||||||
Heartbeats: "Проверки",
|
Heartbeats: "Проверки",
|
||||||
"Auto Get": "Автоматияно получаване",
|
"Auto Get": "Авт. попълване",
|
||||||
backupDescription: "Можете да архивирате всички монитори и всички известия в JSON файл.",
|
backupDescription: "Можете да архивирате всички монитори и всички известия в JSON файл.",
|
||||||
backupDescription2: "PS: Данни за история и събития не са включени.",
|
backupDescription2: "PS: Данни за история и събития не са включени.",
|
||||||
backupDescription3: "Чувствителни данни, като токен кодове за известяване, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.",
|
backupDescription3: "Чувствителни данни, като токен кодове за известяване, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.",
|
||||||
@@ -141,7 +141,7 @@ export default {
|
|||||||
Overwrite: "Презапиши",
|
Overwrite: "Презапиши",
|
||||||
Options: "Опции",
|
Options: "Опции",
|
||||||
"Keep both": "Запази двете",
|
"Keep both": "Запази двете",
|
||||||
"Verify Token": "Проверка на токен код",
|
"Verify Token": "Провери токен код",
|
||||||
"Setup 2FA": "Настройка 2FA",
|
"Setup 2FA": "Настройка 2FA",
|
||||||
"Enable 2FA": "Включи 2FA",
|
"Enable 2FA": "Включи 2FA",
|
||||||
"Disable 2FA": "Изключи 2FA",
|
"Disable 2FA": "Изключи 2FA",
|
||||||
@@ -179,8 +179,8 @@ export default {
|
|||||||
"Edit Status Page": "Редактиране Статус страница",
|
"Edit Status Page": "Редактиране Статус страница",
|
||||||
"Go to Dashboard": "Към Таблото",
|
"Go to Dashboard": "Към Таблото",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Уеб кука",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Имейл (SMTP)",
|
||||||
discord: "Discord",
|
discord: "Discord",
|
||||||
teams: "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
signal: "Signal",
|
signal: "Signal",
|
||||||
@@ -197,4 +197,114 @@ export default {
|
|||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
"Status Page": "Статус страница",
|
"Status Page": "Статус страница",
|
||||||
|
"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: "Може да замените канала по подразбиране, към който публикува уеб куката, като въведете името на канала в полето \"Канал име\". Tрябва да бъде активирано в настройките за уеб кука на 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: "Скорошни",
|
||||||
};
|
};
|
||||||
|
@@ -8,7 +8,7 @@ export default {
|
|||||||
Theme: "Thema",
|
Theme: "Thema",
|
||||||
General: "Allgemein",
|
General: "Allgemein",
|
||||||
Version: "Version",
|
Version: "Version",
|
||||||
"Check Update On GitHub": "Überprüfen von Updates auf Github",
|
"Check Update On GitHub": "Auf GitHub nach Updates suchen",
|
||||||
List: "Liste",
|
List: "Liste",
|
||||||
Add: "Hinzufügen",
|
Add: "Hinzufügen",
|
||||||
"Add New Monitor": "Neuer Monitor",
|
"Add New Monitor": "Neuer Monitor",
|
||||||
@@ -38,21 +38,21 @@ export default {
|
|||||||
checkEverySecond: "Überprüfe alle {0} Sekunden",
|
checkEverySecond: "Überprüfe alle {0} Sekunden",
|
||||||
Response: "Antwortzeit",
|
Response: "Antwortzeit",
|
||||||
Ping: "Ping",
|
Ping: "Ping",
|
||||||
"Monitor Type": "Monitor Typ",
|
"Monitor Type": "Monitor-Typ",
|
||||||
Keyword: "Schlüsselwort",
|
Keyword: "Suchwort",
|
||||||
"Friendly Name": "Anzeigename",
|
"Friendly Name": "Anzeigename",
|
||||||
URL: "URL",
|
URL: "URL",
|
||||||
Hostname: "Hostname",
|
Hostname: "Hostname",
|
||||||
Port: "Port",
|
Port: "Port",
|
||||||
"Heartbeat Interval": "Taktintervall",
|
"Heartbeat Interval": "Prüfintervall",
|
||||||
Retries: "Wiederholungen",
|
Retries: "Wiederholungen",
|
||||||
retriesDescription: "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
|
retriesDescription: "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
|
||||||
Advanced: "Erweitert",
|
Advanced: "Erweitert",
|
||||||
ignoreTLSError: "Ignoriere TLS/SSL Fehler von Webseiten",
|
ignoreTLSError: "Ignoriere TLS-/SSL-Fehler von Webseiten",
|
||||||
"Upside Down Mode": "Umgedrehter Modus",
|
"Upside Down Mode": "Invertierter Modus",
|
||||||
upsideDownModeDescription: "Drehe den Modus um, ist der Dienst erreichbar, wird er als inaktiv angezeigt.",
|
upsideDownModeDescription: "Im invertierten Modus wird der Dienst als inaktiv angezeigt, wenn er erreichbar ist.",
|
||||||
"Max. Redirects": "Max. Weiterleitungen",
|
"Max. Redirects": "Max. Weiterleitungen",
|
||||||
maxRedirectDescription: "Maximale Anzahl von Weiterleitungen, denen gefolgt werden soll. Setzte auf 0, um Weiterleitungen zu deaktivieren.",
|
maxRedirectDescription: "Maximale Anzahl von Weiterleitungen, denen gefolgt werden soll. Auf 0 setzen, um Weiterleitungen zu deaktivieren.",
|
||||||
"Accepted Status Codes": "Erlaubte HTTP-Statuscodes",
|
"Accepted Status Codes": "Erlaubte HTTP-Statuscodes",
|
||||||
acceptedStatusCodesDescription: "Wähle die Statuscodes aus, welche trotzdem als erfolgreich gewertet werden sollen.",
|
acceptedStatusCodesDescription: "Wähle die Statuscodes aus, welche trotzdem als erfolgreich gewertet werden sollen.",
|
||||||
Save: "Speichern",
|
Save: "Speichern",
|
||||||
@@ -62,27 +62,27 @@ export default {
|
|||||||
Light: "Hell",
|
Light: "Hell",
|
||||||
Dark: "Dunkel",
|
Dark: "Dunkel",
|
||||||
Auto: "Auto",
|
Auto: "Auto",
|
||||||
"Theme - Heartbeat Bar": "Thema - Taktleiste",
|
"Theme - Heartbeat Bar": "Thema - Zeitleiste",
|
||||||
Normal: "Normal",
|
Normal: "Normal",
|
||||||
Bottom: "Unten",
|
Bottom: "Unten",
|
||||||
None: "Keine",
|
None: "Keine",
|
||||||
Timezone: "Zeitzone",
|
Timezone: "Zeitzone",
|
||||||
"Search Engine Visibility": "Suchmaschinensichtbarkeit",
|
"Search Engine Visibility": "Sichtbarkeit für Suchmaschinen",
|
||||||
"Allow indexing": "Indizierung zulassen",
|
"Allow indexing": "Indizierung zulassen",
|
||||||
"Discourage search engines from indexing site": "Halte Suchmaschinen von der Indexierung der Seite ab",
|
"Discourage search engines from indexing site": "Halte Suchmaschinen von der Indexierung der Seite ab",
|
||||||
"Change Password": "Passwort ändern",
|
"Change Password": "Passwort ändern",
|
||||||
"Current Password": "Derzeitiges Passwort",
|
"Current Password": "Derzeitiges Passwort",
|
||||||
"New Password": "Neues Passwort",
|
"New Password": "Neues Passwort",
|
||||||
"Repeat New Password": "Wiederhole neues Passwort",
|
"Repeat New Password": "Neues Passwort wiederholen",
|
||||||
passwordNotMatchMsg: "Passwörter stimmen nicht überein. ",
|
passwordNotMatchMsg: "Passwörter stimmen nicht überein. ",
|
||||||
"Update Password": "Ändere Passwort",
|
"Update Password": "Passwort aktualisieren",
|
||||||
"Disable Auth": "Authentifizierung deaktivieren",
|
"Disable Auth": "Authentifizierung deaktivieren",
|
||||||
"Enable Auth": "Authentifizierung aktivieren",
|
"Enable Auth": "Authentifizierung aktivieren",
|
||||||
Logout: "Ausloggen",
|
Logout: "Ausloggen",
|
||||||
notificationDescription: "Weise den Monitor(en) eine Benachrichtigung zu, damit diese Funktion greift.",
|
notificationDescription: "Weise den Monitor(en) eine Benachrichtigung zu, damit diese Funktion greift.",
|
||||||
Leave: "Verlassen",
|
Leave: "Verlassen",
|
||||||
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
|
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
|
||||||
Confirm: "Bestätige",
|
Confirm: "Bestätigen",
|
||||||
Yes: "Ja",
|
Yes: "Ja",
|
||||||
No: "Nein",
|
No: "Nein",
|
||||||
Username: "Benutzername",
|
Username: "Benutzername",
|
||||||
@@ -95,7 +95,7 @@ export default {
|
|||||||
Email: "E-Mail",
|
Email: "E-Mail",
|
||||||
Test: "Test",
|
Test: "Test",
|
||||||
"Certificate Info": "Zertifikatsinfo",
|
"Certificate Info": "Zertifikatsinfo",
|
||||||
keywordDescription: "Suche nach einem Schlüsselwort in der HTML oder JSON Ausgabe. Bitte beachte, es wird in der Groß-/Kleinschreibung unterschieden.",
|
keywordDescription: "Ein Suchwort in der HTML- oder JSON-Ausgabe finden. Bitte beachte: es wird zwischen Groß-/Kleinschreibung unterschieden.",
|
||||||
deleteMonitorMsg: "Bist du sicher, dass du den Monitor löschen möchtest?",
|
deleteMonitorMsg: "Bist du sicher, dass du den Monitor löschen möchtest?",
|
||||||
deleteNotificationMsg: "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?",
|
deleteNotificationMsg: "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?",
|
||||||
resoverserverDescription: "Cloudflare ist als der Standardserver festgelegt, dieser kann jederzeit geändern werden.",
|
resoverserverDescription: "Cloudflare ist als der Standardserver festgelegt, dieser kann jederzeit geändern werden.",
|
||||||
@@ -108,13 +108,13 @@ export default {
|
|||||||
"Clear Data": "Lösche Daten",
|
"Clear Data": "Lösche Daten",
|
||||||
Events: "Ereignisse",
|
Events: "Ereignisse",
|
||||||
Heartbeats: "Statistiken",
|
Heartbeats: "Statistiken",
|
||||||
confirmClearStatisticsMsg: "Bist du dir wirklich sicher, dass du ALLE Statistiken löschen möchtest?",
|
confirmClearStatisticsMsg: "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
|
||||||
"Create your admin account": "Erstelle dein Admin Konto",
|
"Create your admin account": "Erstelle dein Admin-Konto",
|
||||||
"Repeat Password": "Wiederhole das Passwort",
|
"Repeat Password": "Wiederhole das Passwort",
|
||||||
"Resource Record Type": "Resource Record Type",
|
"Resource Record Type": "Resource Record Type",
|
||||||
Export: "Export",
|
Export: "Export",
|
||||||
Import: "Import",
|
Import: "Import",
|
||||||
respTime: "Antw. Zeit (ms)",
|
respTime: "Antw.-Zeit (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
"Default enabled": "Standardmäßig aktiviert",
|
"Default enabled": "Standardmäßig aktiviert",
|
||||||
"Apply on all existing monitors": "Auf alle existierenden Monitore anwenden",
|
"Apply on all existing monitors": "Auf alle existierenden Monitore anwenden",
|
||||||
@@ -125,34 +125,34 @@ export default {
|
|||||||
backupDescription2: "PS: Verlaufs- und Ereignisdaten sind nicht enthalten.",
|
backupDescription2: "PS: Verlaufs- und Ereignisdaten sind nicht enthalten.",
|
||||||
backupDescription3: "Sensible Daten wie Benachrichtigungstoken sind in der Exportdatei enthalten, bitte bewahre sie sorgfältig auf.",
|
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.",
|
alertNoFile: "Bitte wähle eine Datei zum Importieren aus.",
|
||||||
alertWrongFileType: "Bitte wähle eine JSON Datei aus.",
|
alertWrongFileType: "Bitte wähle eine JSON-Datei aus.",
|
||||||
"Clear all statistics": "Lösche alle Statistiken",
|
"Clear all statistics": "Lösche alle Statistiken",
|
||||||
importHandleDescription: "Wähle 'Vorhandene überspringen' aus, wenn jeder Monitor oder Benachrichtigung mit demselben Namen übersprungen werden soll. 'Überschreiben' löscht jeden vorhandenen Monitor sowie Benachrichtigungen.",
|
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",
|
"Skip existing": "Vorhandene überspringen",
|
||||||
Overwrite: "Überschreiben",
|
Overwrite: "Überschreiben",
|
||||||
Options: "Optionen",
|
Options: "Optionen",
|
||||||
confirmImportMsg: "Möchtest du das Backup wirklich importieren? Bitte stelle sicher, dass die richtige Import Option ausgewählt ist.",
|
confirmImportMsg: "Möchtest du das Backup wirklich importieren? Bitte stelle sicher, dass die richtige Import-Option ausgewählt ist.",
|
||||||
"Keep both": "Beide behalten",
|
"Keep both": "Beide behalten",
|
||||||
twoFAVerifyLabel: "Bitte trage deinen Token ein, um zu verifizieren das 2FA funktioniert",
|
twoFAVerifyLabel: "Bitte trage deinen Token ein, um zu verifizieren, dass 2FA funktioniert",
|
||||||
"Verify Token": "Token verifizieren",
|
"Verify Token": "Token verifizieren",
|
||||||
"Setup 2FA": "2FA Einrichten",
|
"Setup 2FA": "2FA einrichten",
|
||||||
"Enable 2FA": "2FA Aktivieren",
|
"Enable 2FA": "2FA aktivieren",
|
||||||
"Disable 2FA": "2FA deaktivieren",
|
"Disable 2FA": "2FA deaktivieren",
|
||||||
"2FA Settings": "2FA Einstellungen",
|
"2FA Settings": "2FA-Einstellungen",
|
||||||
confirmEnableTwoFAMsg: "Bist du sicher, dass du 2FA aktivieren möchtest?",
|
confirmEnableTwoFAMsg: "Bist du sicher, dass du 2FA aktivieren möchtest?",
|
||||||
confirmDisableTwoFAMsg: "Bist du sicher, dass du 2FA deaktivieren möchtest?",
|
confirmDisableTwoFAMsg: "Bist du sicher, dass du 2FA deaktivieren möchtest?",
|
||||||
tokenValidSettingsMsg: "Token gültig! Du kannst jetzt die 2FA Einstellungen speichern.",
|
tokenValidSettingsMsg: "Token gültig! Du kannst jetzt die 2FA-Einstellungen speichern.",
|
||||||
"Two Factor Authentication": "Zwei Faktor Authentifizierung",
|
"Two Factor Authentication": "Zwei-Faktor-Authentifizierung",
|
||||||
Active: "Aktiv",
|
Active: "Aktiv",
|
||||||
Inactive: "Inaktiv",
|
Inactive: "Inaktiv",
|
||||||
Token: "Token",
|
Token: "Token",
|
||||||
"Show URI": "URI Anzeigen",
|
"Show URI": "URI anzeigen",
|
||||||
Tags: "Tags",
|
Tags: "Tags",
|
||||||
"Add New below or Select...": "Füge neuen hinzu oder wähle aus...",
|
"Add New below or Select...": "Bestehenden Tag auswählen oder neuen hinzufügen...",
|
||||||
"Tag with this name already exist.": "Ein Tag mit dem Namen existiert bereits.",
|
"Tag with this name already exist.": "Ein Tag mit diesem Namen existiert bereits.",
|
||||||
"Tag with this value already exist.": "Ein Tag mit dem Wert existiert bereits.",
|
"Tag with this value already exist.": "Ein Tag mit diesem Wert existiert bereits.",
|
||||||
color: "Farbe",
|
color: "Farbe",
|
||||||
"value (optional)": "Wert (Optional)",
|
"value (optional)": "Wert (optional)",
|
||||||
Gray: "Grau",
|
Gray: "Grau",
|
||||||
Red: "Rot",
|
Red: "Rot",
|
||||||
Orange: "Orange",
|
Orange: "Orange",
|
||||||
@@ -164,21 +164,21 @@ export default {
|
|||||||
"Search...": "Suchen...",
|
"Search...": "Suchen...",
|
||||||
"Heartbeat Retry Interval": "Heartbeat-Wiederholungsintervall",
|
"Heartbeat Retry Interval": "Heartbeat-Wiederholungsintervall",
|
||||||
retryCheckEverySecond: "Versuche alle {0} Sekunden",
|
retryCheckEverySecond: "Versuche alle {0} Sekunden",
|
||||||
"Import Backup": "Import Backup",
|
"Import Backup": "Backup importieren",
|
||||||
"Export Backup": "Export Backup",
|
"Export Backup": "Backup exportieren",
|
||||||
"Avg. Ping": "Durchsch. Ping",
|
"Avg. Ping": "Durchschn. Ping",
|
||||||
"Avg. Response": "Durchsch. Antwort",
|
"Avg. Response": "Durchschn. Antwort",
|
||||||
"Entry Page": "Einstiegsseite",
|
"Entry Page": "Einstiegsseite",
|
||||||
statusPageNothing: "Nichts ist hier, bitte füge eine Gruppe oder Monitor hinzu.",
|
statusPageNothing: "Noch ist hier nichts. Bitte füge eine Gruppe oder einen Monitor hinzu.",
|
||||||
"No Services": "Keine Dienste",
|
"No Services": "Keine Dienste",
|
||||||
"All Systems Operational": "Alle Systeme Betriebsbereit",
|
"All Systems Operational": "Alle Systeme betriebsbereit",
|
||||||
"Partially Degraded Service": "Teilweise beeinträchtigter Dienst",
|
"Partially Degraded Service": "Teilweise beeinträchtigter Dienst",
|
||||||
"Degraded Service": "Eingeschränkter Dienst",
|
"Degraded Service": "Eingeschränkter Dienst",
|
||||||
"Add Group": "Gruppe hinzufügen",
|
"Add Group": "Gruppe hinzufügen",
|
||||||
"Add a monitor": "Monitor hinzufügen",
|
"Add a monitor": "Monitor hinzufügen",
|
||||||
"Edit Status Page": "Bearbeite Statusseite",
|
"Edit Status Page": "Bearbeite Status-Seite",
|
||||||
"Go to Dashboard": "Gehe zum Dashboard",
|
"Go to Dashboard": "Gehe zum Dashboard",
|
||||||
"Status Page": "Status Seite",
|
"Status Page": "Status-Seite",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "E-Mail (SMTP)",
|
smtp: "E-Mail (SMTP)",
|
||||||
@@ -197,4 +197,111 @@ export default {
|
|||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
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: "Meine {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 sowie Express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} ist gut für PHP. Die JSON muss mit {decodeFunction} geparst werden",
|
||||||
|
secureOptionNone: "Keine / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "TLS-Fehler ignorieren",
|
||||||
|
"From Email": "Von Email",
|
||||||
|
emailCustomSubject: "Benutzerdefinierter Betreff",
|
||||||
|
"To Email": "Zu Email",
|
||||||
|
smtpCC: "CC",
|
||||||
|
smtpBCC: "BCC",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "Du kannst diesen 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: "Hier erfährst du, wie eine Webhook-URL erstellt werden kann {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 auf {0} Feld Kanalname, wenn du den Webhook-Kanal umgehen möchtest. Ex: #other-channel",
|
||||||
|
aboutKumaURL: "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird es standardmäßig die GitHub Projekt Seite verwenden.",
|
||||||
|
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": "Überprüfe 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 postet ü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. Nur auf polnische Empfänger beschränkt.",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - Die Nachricht wird automatisch auf dem Empfängergerät angezeigt. Nur auf polnische Empfänger beschränkt.",
|
||||||
|
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: "Phone number (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 es aussehen wie z.B. !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
|
matrixDesc2: "Es wird dringend empfohlen, dass ein neuen Benutzer erstellt wird und nicht den Zugriffstoken deines eigenen Matrix-Benutzers verwendest. Anderfalls ermöglicht es vollen Zugriff auf dein Konto und alle Räume, denen du beigetreten bist. Erstelle stattdessen einen neuen Benutzer und lade ihn nur in den Raum ein, in dem du die Benachrichtigung erhalten möchtest. Du kannst den Zugriffstoken erhalten, indem du folgendes ausführst {0}",
|
||||||
|
Method: "Method",
|
||||||
|
Body: "Body",
|
||||||
|
Headers: "Headers",
|
||||||
|
PushUrl: "Push URL",
|
||||||
|
HeadersInvalidFormat: "Die 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",
|
||||||
};
|
};
|
||||||
|
@@ -1,28 +1,28 @@
|
|||||||
export default {
|
export default {
|
||||||
languageName: "English",
|
languageName: "English",
|
||||||
checkEverySecond: "Check every {0} seconds.",
|
checkEverySecond: "Check every {0} seconds",
|
||||||
retryCheckEverySecond: "Retry every {0} seconds.",
|
retryCheckEverySecond: "Retry every {0} seconds",
|
||||||
retriesDescription: "Maximum retries before the service is marked as down and a notification is sent",
|
retriesDescription: "Maximum retries before the service is marked as down and a notification is sent",
|
||||||
ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
|
ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
|
||||||
upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
|
upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
|
||||||
maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
|
maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
|
||||||
acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
|
acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
|
||||||
passwordNotMatchMsg: "The repeat password does not match.",
|
passwordNotMatchMsg: "The repeat password does not match.",
|
||||||
notificationDescription: "Please assign a notification to monitor(s) to get it to work.",
|
notificationDescription: "Notifications must be assigned to a monitor to function.",
|
||||||
keywordDescription: "Search keyword in plain html or JSON response and it is case-sensitive",
|
keywordDescription: "Search keyword in plain HTML or JSON response. The search is case-sensitive.",
|
||||||
pauseDashboardHome: "Pause",
|
pauseDashboardHome: "Pause",
|
||||||
deleteMonitorMsg: "Are you sure want to delete this monitor?",
|
deleteMonitorMsg: "Are you sure want to delete this monitor?",
|
||||||
deleteNotificationMsg: "Are you sure want to delete this notification for all monitors?",
|
deleteNotificationMsg: "Are you sure want to delete this notification for all monitors?",
|
||||||
resoverserverDescription: "Cloudflare is the default server, you can change the resolver server anytime.",
|
resoverserverDescription: "Cloudflare is the default server. You can change the resolver server anytime.",
|
||||||
rrtypeDescription: "Select the RR-Type you want to monitor",
|
rrtypeDescription: "Select the RR type you want to monitor",
|
||||||
pauseMonitorMsg: "Are you sure want to pause?",
|
pauseMonitorMsg: "Are you sure want to pause?",
|
||||||
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
enableDefaultNotificationDescription: "This notification will be enabled by default for new monitors. You can still disable the notification separately for each monitor.",
|
||||||
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
||||||
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure you want to delete ALL statistics?",
|
||||||
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
|
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
|
||||||
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
|
confirmImportMsg: "Are you sure you want to import the backup? Please verify you've selected the correct import option.",
|
||||||
twoFAVerifyLabel: "Please type in your token to verify that 2FA is working",
|
twoFAVerifyLabel: "Please enter your token to verify 2FA:",
|
||||||
tokenValidSettingsMsg: "Token is valid! You can now save the 2FA settings.",
|
tokenValidSettingsMsg: "Token is valid! You can now save the 2FA settings.",
|
||||||
confirmEnableTwoFAMsg: "Are you sure you want to enable 2FA?",
|
confirmEnableTwoFAMsg: "Are you sure you want to enable 2FA?",
|
||||||
confirmDisableTwoFAMsg: "Are you sure you want to disable 2FA?",
|
confirmDisableTwoFAMsg: "Are you sure you want to disable 2FA?",
|
||||||
@@ -33,6 +33,7 @@ export default {
|
|||||||
Appearance: "Appearance",
|
Appearance: "Appearance",
|
||||||
Theme: "Theme",
|
Theme: "Theme",
|
||||||
General: "General",
|
General: "General",
|
||||||
|
"Primary Base URL": "Primary Base URL",
|
||||||
Version: "Version",
|
Version: "Version",
|
||||||
"Check Update On GitHub": "Check Update On GitHub",
|
"Check Update On GitHub": "Check Update On GitHub",
|
||||||
List: "List",
|
List: "List",
|
||||||
@@ -75,6 +76,9 @@ export default {
|
|||||||
"Upside Down Mode": "Upside Down Mode",
|
"Upside Down Mode": "Upside Down Mode",
|
||||||
"Max. Redirects": "Max. Redirects",
|
"Max. Redirects": "Max. Redirects",
|
||||||
"Accepted Status Codes": "Accepted Status Codes",
|
"Accepted Status Codes": "Accepted Status Codes",
|
||||||
|
"Push URL": "Push URL",
|
||||||
|
needPushEvery: "You should call this URL every {0} seconds.",
|
||||||
|
pushOptionalParams: "Optional parameters: {0}",
|
||||||
Save: "Save",
|
Save: "Save",
|
||||||
Notifications: "Notifications",
|
Notifications: "Notifications",
|
||||||
"Not available, please setup.": "Not available, please setup.",
|
"Not available, please setup.": "Not available, please setup.",
|
||||||
@@ -131,9 +135,9 @@ export default {
|
|||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats",
|
Heartbeats: "Heartbeats",
|
||||||
"Auto Get": "Auto Get",
|
"Auto Get": "Auto Get",
|
||||||
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
backupDescription: "You can backup all monitors and notifications into a JSON file.",
|
||||||
backupDescription2: "PS: History and event data is not included.",
|
backupDescription2: "Note: history and event data is not included.",
|
||||||
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
backupDescription3: "Sensitive data such as notification tokens are included in the export file; please store export securely.",
|
||||||
alertNoFile: "Please select a file to import.",
|
alertNoFile: "Please select a file to import.",
|
||||||
alertWrongFileType: "Please select a JSON file.",
|
alertWrongFileType: "Please select a JSON file.",
|
||||||
"Clear all statistics": "Clear all Statistics",
|
"Clear all statistics": "Clear all Statistics",
|
||||||
@@ -153,8 +157,8 @@ export default {
|
|||||||
"Show URI": "Show URI",
|
"Show URI": "Show URI",
|
||||||
Tags: "Tags",
|
Tags: "Tags",
|
||||||
"Add New below or Select...": "Add New below or Select...",
|
"Add New below or Select...": "Add New below or Select...",
|
||||||
"Tag with this name already exist.": "Tag with this name already exist.",
|
"Tag with this name already exist.": "Tag with this name already exists.",
|
||||||
"Tag with this value already exist.": "Tag with this value already exist.",
|
"Tag with this value already exist.": "Tag with this value already exists.",
|
||||||
color: "color",
|
color: "color",
|
||||||
"value (optional)": "value (optional)",
|
"value (optional)": "value (optional)",
|
||||||
Gray: "Gray",
|
Gray: "Gray",
|
||||||
@@ -179,70 +183,71 @@ export default {
|
|||||||
"Edit Status Page": "Edit Status Page",
|
"Edit Status Page": "Edit Status Page",
|
||||||
"Go to Dashboard": "Go to Dashboard",
|
"Go to Dashboard": "Go to Dashboard",
|
||||||
"Status Page": "Status Page",
|
"Status Page": "Status Page",
|
||||||
// Start notification form
|
|
||||||
defaultNotificationName: "My {notification} Alert ({number})",
|
defaultNotificationName: "My {notification} Alert ({number})",
|
||||||
here: "here",
|
here: "here",
|
||||||
"Required": "Required",
|
Required: "Required",
|
||||||
"telegram": "Telegram",
|
telegram: "Telegram",
|
||||||
"Bot Token": "Bot Token",
|
"Bot Token": "Bot Token",
|
||||||
"You can get a token from": "You can get a token from",
|
wayToGetTelegramToken: "You can get a token from {0}.",
|
||||||
"Chat ID": "Chat ID",
|
"Chat ID": "Chat ID",
|
||||||
supportTelegramChatID: "Support Direct Chat / Group / Channel's Chat ID",
|
supportTelegramChatID: "Support Direct Chat / Group / Channel's Chat ID",
|
||||||
wayToGetTelegramChatID: "You can get your chat id by sending message to the bot and go to this url to view the chat_id:",
|
wayToGetTelegramChatID: "You can get your chat ID by sending a message to the bot and going to this URL to view the chat_id:",
|
||||||
"YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE",
|
"YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE",
|
||||||
chatIDNotFound: "Chat ID is not found, please send a message to this bot first",
|
chatIDNotFound: "Chat ID is not found; please send a message to this bot first",
|
||||||
"webhook": "Webhook",
|
webhook: "Webhook",
|
||||||
"Post URL": "Post URL",
|
"Post URL": "Post URL",
|
||||||
"Content Type": "Content Type",
|
"Content Type": "Content Type",
|
||||||
webhookJsonDesc: "{0} is good for any modern http servers such as express.js",
|
webhookJsonDesc: "{0} is good for any modern HTTP servers such as Express.js",
|
||||||
webhookFormDataDesc: "{multipart} is good for PHP, you just need to parse the json by {decodeFunction}",
|
webhookFormDataDesc: "{multipart} is good for PHP. The JSON will need to be parsed with {decodeFunction}",
|
||||||
"smtp": "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
secureOptionNone: "None / STARTTLS (25, 587)",
|
secureOptionNone: "None / STARTTLS (25, 587)",
|
||||||
secureOptionTLS: "TLS (465)",
|
secureOptionTLS: "TLS (465)",
|
||||||
"Ignore TLS Error": "Ignore TLS Error",
|
"Ignore TLS Error": "Ignore TLS Error",
|
||||||
"From Email": "From Email",
|
"From Email": "From Email",
|
||||||
|
emailCustomSubject: "Custom Subject",
|
||||||
"To Email": "To Email",
|
"To Email": "To Email",
|
||||||
smtpCC: "CC",
|
smtpCC: "CC",
|
||||||
smtpBCC: "BCC",
|
smtpBCC: "BCC",
|
||||||
"discord": "Discord",
|
discord: "Discord",
|
||||||
"Discord Webhook URL": "Discord Webhook URL",
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
wayToGetDiscordURL: "You can get this by going to Server Settings -> Integrations -> Create Webhook",
|
wayToGetDiscordURL: "You can get this by going to Server Settings -> Integrations -> Create Webhook",
|
||||||
"Bot Display Name": "Bot Display Name",
|
"Bot Display Name": "Bot Display Name",
|
||||||
"Prefix Custom Message": "Prefix Custom Message",
|
"Prefix Custom Message": "Prefix Custom Message",
|
||||||
"Hello @everyone is...": "Hello {'@'}everyone is...",
|
"Hello @everyone is...": "Hello {'@'}everyone is...",
|
||||||
"teams": "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
"Webhook URL": "Webhook URL",
|
"Webhook URL": "Webhook URL",
|
||||||
wayToGetTeamsURL: "You can learn how to create a webhook url {0}.",
|
wayToGetTeamsURL: "You can learn how to create a webhook URL {0}.",
|
||||||
"signal": "Signal",
|
signal: "Signal",
|
||||||
"Number": "Number",
|
Number: "Number",
|
||||||
"Recipients": "Recipients",
|
Recipients: "Recipients",
|
||||||
needSignalAPI: "You need to have a signal client with REST API.",
|
needSignalAPI: "You need to have a signal client with REST API.",
|
||||||
wayToCheckSignalURL: "You can check this url to view how to setup one:",
|
wayToCheckSignalURL: "You can check this URL to view how to set one up:",
|
||||||
signalImportant: "IMPORTANT: You cannot mix groups and numbers in recipients!",
|
signalImportant: "IMPORTANT: You cannot mix groups and numbers in recipients!",
|
||||||
"gotify": "Gotify",
|
gotify: "Gotify",
|
||||||
"Application Token": "Application Token",
|
"Application Token": "Application Token",
|
||||||
"Server URL": "Server URL",
|
"Server URL": "Server URL",
|
||||||
"Priority": "Priority",
|
Priority: "Priority",
|
||||||
"slack": "Slack",
|
slack: "Slack",
|
||||||
"Icon Emoji": "Icon Emoji",
|
"Icon Emoji": "Icon Emoji",
|
||||||
"Channel Name": "Channel Name",
|
"Channel Name": "Channel Name",
|
||||||
"Uptime Kuma URL": "Uptime Kuma URL",
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
aboutWebhooks: "More info about webhooks on: {0}",
|
aboutWebhooks: "More info about Webhooks on: {0}",
|
||||||
aboutChannelName: "Enter the channel name on {0} Channel Name field if you want to bypass the webhook channel. Ex: #other-channel",
|
aboutChannelName: "Enter the channel name on {0} Channel Name field if you want to bypass the Webhook channel. Ex: #other-channel",
|
||||||
aboutKumaURL: "If you leave the Uptime Kuma URL field blank, it will default to the Project Github page.",
|
aboutKumaURL: "If you leave the Uptime Kuma URL field blank, it will default to the Project GitHub page.",
|
||||||
emojiCheatSheet: "Emoji cheat sheet: {0}",
|
emojiCheatSheet: "Emoji cheat sheet: {0}",
|
||||||
"rocket.chat": "Rocket.chat",
|
"rocket.chat": "Rocket.Chat",
|
||||||
pushover: "Pushover",
|
pushover: "Pushover",
|
||||||
pushy: "Pushy",
|
pushy: "Pushy",
|
||||||
octopush: "Octopush",
|
octopush: "Octopush",
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
lunasea: "LunaSea",
|
lunasea: "LunaSea",
|
||||||
apprise: "Apprise (Support 50+ Notification services)",
|
apprise: "Apprise (Support 50+ Notification services)",
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
"User Key": "User Key",
|
"User Key": "User Key",
|
||||||
"Device": "Device",
|
Device: "Device",
|
||||||
"Message Title": "Message Title",
|
"Message Title": "Message Title",
|
||||||
"Notification Sound": "Notification Sound",
|
"Notification Sound": "Notification Sound",
|
||||||
"More info on:": "More info on: {0}",
|
"More info on:": "More info on: {0}",
|
||||||
@@ -250,7 +255,10 @@ export default {
|
|||||||
pushoverDesc2: "If you want to send notifications to different devices, fill out Device field.",
|
pushoverDesc2: "If you want to send notifications to different devices, fill out Device field.",
|
||||||
"SMS Type": "SMS Type",
|
"SMS Type": "SMS Type",
|
||||||
octopushTypePremium: "Premium (Fast - recommended for alerting)",
|
octopushTypePremium: "Premium (Fast - recommended for alerting)",
|
||||||
octopushTypeLowCost: "Low Cost (Slow, sometimes blocked by operator)",
|
octopushTypeLowCost: "Low Cost (Slow - sometimes blocked by operator)",
|
||||||
|
checkPrice: "Check {0} prices:",
|
||||||
|
apiCredentials: "API credentials",
|
||||||
|
octopushLegacyHint: "Do you use the legacy version of Octopush (2011-2020) or the new version?",
|
||||||
"Check octopush prices": "Check octopush prices {0}.",
|
"Check octopush prices": "Check octopush prices {0}.",
|
||||||
octopushPhoneNumber: "Phone number (intl format, eg : +33612345678) ",
|
octopushPhoneNumber: "Phone number (intl format, eg : +33612345678) ",
|
||||||
octopushSMSSender: "SMS Sender Name : 3-11 alphanumeric characters and space (a-zA-Z0-9)",
|
octopushSMSSender: "SMS Sender Name : 3-11 alphanumeric characters and space (a-zA-Z0-9)",
|
||||||
@@ -269,16 +277,34 @@ export default {
|
|||||||
"Basic Settings": "Basic Settings",
|
"Basic Settings": "Basic Settings",
|
||||||
"User ID": "User ID",
|
"User ID": "User ID",
|
||||||
"Messaging API": "Messaging API",
|
"Messaging API": "Messaging API",
|
||||||
wayToGetLineChannelToken: "First access the {0}, create a provider and channel (Messaging API), then you can get the channel access token and user id from the above mentioned menu items.",
|
wayToGetLineChannelToken: "First access the {0}, create a provider and channel (Messaging API), then you can get the channel access token and user ID from the above mentioned menu items.",
|
||||||
"Icon URL": "Icon URL",
|
"Icon URL": "Icon URL",
|
||||||
aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.",
|
aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.",
|
||||||
aboutMattermostChannelName: "You can override the default channel that webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in Mattermost webhook settings. Ex: #other-channel",
|
aboutMattermostChannelName: "You can override the default channel that the Webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in the Mattermost Webhook settings. Ex: #other-channel",
|
||||||
"matrix": "Matrix",
|
matrix: "Matrix",
|
||||||
promosmsTypeEco: "SMS ECO - cheap but slow and often overloaded. Limited only to Polish recipients.",
|
promosmsTypeEco: "SMS ECO - cheap but slow and often overloaded. Limited only to Polish recipients.",
|
||||||
promosmsTypeFlash: "SMS FLASH - Message will automatically show on recipient device. Limited only to Polish recipients.",
|
promosmsTypeFlash: "SMS FLASH - Message will automatically show on recipient device. Limited only to Polish recipients.",
|
||||||
promosmsTypeFull: "SMS FULL - Premium tier of SMS, You can use Your Sender Name (You need to register name first). Reliable for alerts.",
|
promosmsTypeFull: "SMS FULL - Premium tier of SMS, You can use your Sender Name (You need to register name first). Reliable for alerts.",
|
||||||
promosmsTypeSpeed: "SMS SPEED - Highest priority in system. Very quick and reliable but costly (about twice of SMS FULL price).",
|
promosmsTypeSpeed: "SMS SPEED - Highest priority in system. Very quick and reliable but costly (about twice of SMS FULL price).",
|
||||||
promosmsPhoneNumber: "Phone number (for Polish recipient You can skip area codes)",
|
promosmsPhoneNumber: "Phone number (for Polish recipient You can skip area codes)",
|
||||||
promosmsSMSSender: "SMS Sender Name : Pre-registred name or one of defaults: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
promosmsSMSSender: "SMS Sender Name : Pre-registred name or one of defaults: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
// End notification form
|
"Feishu WebHookUrl": "Feishu WebHookURL",
|
||||||
|
matrixHomeserverURL: "Homeserver URL (with http(s):// and optionally port)",
|
||||||
|
"Internal Room Id": "Internal Room ID",
|
||||||
|
matrixDesc1: "You can find the internal room ID by looking in the advanced section of the room settings in your Matrix client. It should look like !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
|
matrixDesc2: "It is highly recommended you create a new user and do not use your own Matrix user's access token as it will allow full access to your account and all the rooms you joined. Instead, create a new user and only invite it to the room that you want to receive the notification in. You can get the access token by running {0}",
|
||||||
|
Method: "Method",
|
||||||
|
Body: "Body",
|
||||||
|
Headers: "Headers",
|
||||||
|
PushUrl: "Push URL",
|
||||||
|
HeadersInvalidFormat: "The request headers are not valid JSON: ",
|
||||||
|
BodyInvalidFormat: "The request body is not valid JSON: ",
|
||||||
|
"Monitor History": "Monitor History",
|
||||||
|
clearDataOlderThan: "Keep monitor history data for {0} days.",
|
||||||
|
PasswordsDoNotMatch: "Passwords do not match.",
|
||||||
|
records: "records",
|
||||||
|
"One record": "One record",
|
||||||
|
steamApiKeyDescription: "For monitoring a Steam Game Server you need a Steam Web-API key. You can register your API key here: ",
|
||||||
|
"Current User": "Current User",
|
||||||
|
recent: "Recent",
|
||||||
};
|
};
|
||||||
|
@@ -9,7 +9,7 @@ export default {
|
|||||||
passwordNotMatchMsg: "La contraseña repetida no coincide.",
|
passwordNotMatchMsg: "La contraseña repetida no coincide.",
|
||||||
notificationDescription: "Por favor asigne una notificación a el/los monitor(es) para hacerlos funcional(es).",
|
notificationDescription: "Por favor asigne una notificación a el/los monitor(es) para hacerlos funcional(es).",
|
||||||
keywordDescription: "Palabra clave en HTML plano o respuesta JSON y es sensible a mayúsculas",
|
keywordDescription: "Palabra clave en HTML plano o respuesta JSON y es sensible a mayúsculas",
|
||||||
pauseDashboardHome: "Pausar",
|
pauseDashboardHome: "Pausado",
|
||||||
deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?",
|
deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?",
|
||||||
deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?",
|
deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?",
|
||||||
resoverserverDescription: "Cloudflare es el servidor por defecto, puedes cambiar el servidor de resolución en cualquier momento.",
|
resoverserverDescription: "Cloudflare es el servidor por defecto, puedes cambiar el servidor de resolución en cualquier momento.",
|
||||||
@@ -32,7 +32,7 @@ export default {
|
|||||||
Down: "Caído",
|
Down: "Caído",
|
||||||
Pending: "Pendiente",
|
Pending: "Pendiente",
|
||||||
Unknown: "Desconocido",
|
Unknown: "Desconocido",
|
||||||
Pause: "Pausa",
|
Pause: "Pausar",
|
||||||
Name: "Nombre",
|
Name: "Nombre",
|
||||||
Status: "Estado",
|
Status: "Estado",
|
||||||
DateTime: "Fecha y Hora",
|
DateTime: "Fecha y Hora",
|
||||||
@@ -198,4 +198,9 @@ export default {
|
|||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
"Monitor History": "Historial de monitor",
|
||||||
|
clearDataOlderThan: "Mantener los datos del historial del monitor durante {0} días.",
|
||||||
|
records: "registros",
|
||||||
|
"One record": "Un registro",
|
||||||
|
steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesita una clave Steam Web-API. Puede registrar su clave API aquí: ",
|
||||||
};
|
};
|
||||||
|
@@ -182,9 +182,6 @@ export default {
|
|||||||
"Uptime Kuma": "آپتایم کوما",
|
"Uptime Kuma": "آپتایم کوما",
|
||||||
records: "مورد",
|
records: "مورد",
|
||||||
"One record": "یک مورد",
|
"One record": "یک مورد",
|
||||||
"Showing {from} to {to} of {count} records": "نمایش از {from} تا {to} از {count} مورد",
|
|
||||||
First: "اولین",
|
|
||||||
Last: "آخرین",
|
|
||||||
Info: "اطلاعات",
|
Info: "اطلاعات",
|
||||||
"Powered by": "نیرو گرفته از",
|
"Powered by": "نیرو گرفته از",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
|
@@ -1,5 +1,31 @@
|
|||||||
export default {
|
export default {
|
||||||
languageName: "Français (France)",
|
languageName: "Français (France)",
|
||||||
|
checkEverySecond: "Vérifier toutes les {0} secondes",
|
||||||
|
retryCheckEverySecond: "Réessayer toutes les {0} secondes.",
|
||||||
|
retriesDescription: "Nombre d'essais avant que le service soit déclaré hors-ligne.",
|
||||||
|
ignoreTLSError: "Ignorer les erreurs liées au certificat SSL/TLS",
|
||||||
|
upsideDownModeDescription: "Si le service est en ligne, il sera alors noté hors-ligne et vice-versa.",
|
||||||
|
maxRedirectDescription: "Nombre maximal de redirections avant que le service soit noté hors-ligne.",
|
||||||
|
acceptedStatusCodesDescription: "Codes HTTP considérés comme en ligne",
|
||||||
|
passwordNotMatchMsg: "Les mots de passe ne correspondent pas",
|
||||||
|
notificationDescription: "Une fois ajoutée, vous devez l'activer manuellement dans les paramètres de vos hôtes.",
|
||||||
|
keywordDescription: "Le mot clé sera recherché dans la réponse HTML/JSON reçue du site internet.",
|
||||||
|
pauseDashboardHome: "En pause",
|
||||||
|
deleteMonitorMsg: "Êtes-vous sûr de vouloir supprimer cette sonde ?",
|
||||||
|
deleteNotificationMsg: "Êtes-vous sûr de vouloir supprimer ce type de notifications ? Une fois désactivée, les services qui l'utilisent ne pourront plus envoyer de notifications.",
|
||||||
|
resoverserverDescription: "Le DNS de cloudflare est utilisé par défaut, mais vous pouvez le changer si vous le souhaitez.",
|
||||||
|
rrtypeDescription: "Veuillez séléctionner un type d'enregistrement DNS",
|
||||||
|
pauseMonitorMsg: "Êtes-vous sûr de vouloir mettre en pause cette sonde ?",
|
||||||
|
enableDefaultNotificationDescription: "Pour chaque nouvelle sonde, cette notification sera activée par défaut. Vous pouvez toujours désactiver la notification séparément pour chaque sonde.",
|
||||||
|
clearEventsMsg: "Êtes-vous sûr de vouloir supprimer tous les événements pour cette sonde ?",
|
||||||
|
clearHeartbeatsMsg: "Êtes-vous sûr de vouloir supprimer tous les vérifications pour cette sonde ?",
|
||||||
|
confirmClearStatisticsMsg: "Êtes-vous sûr de vouloir supprimer tous les statistiques ?",
|
||||||
|
importHandleDescription: "Choisissez 'Ignorer l'existant' si vous voulez ignorer chaque sonde ou notification portant le même nom. L'option 'Écraser' supprime toutes les sondes et notifications existantes.",
|
||||||
|
confirmImportMsg: "Êtes-vous sûr de vouloir importer la sauvegarde ? Veuillez vous assurer que vous avez sélectionné la bonne option d'importation.",
|
||||||
|
twoFAVerifyLabel: "Veuillez saisir votre jeton pour vérifier que le système 2FA fonctionne.",
|
||||||
|
tokenValidSettingsMsg: "Le jeton est valide ; Vous pouvez maintenant sauvegarder les paramètres 2FA.",
|
||||||
|
confirmEnableTwoFAMsg: "Êtes-vous sûr de vouloir activer le 2FA ?",
|
||||||
|
confirmDisableTwoFAMsg: "Êtes-vous sûr de vouloir désactiver le 2FA ?",
|
||||||
Settings: "Paramètres",
|
Settings: "Paramètres",
|
||||||
Dashboard: "Tableau de bord",
|
Dashboard: "Tableau de bord",
|
||||||
"New Update": "Mise à jour disponible",
|
"New Update": "Mise à jour disponible",
|
||||||
@@ -18,7 +44,6 @@ export default {
|
|||||||
Pending: "En attente",
|
Pending: "En attente",
|
||||||
Unknown: "Inconnu",
|
Unknown: "Inconnu",
|
||||||
Pause: "En Pause",
|
Pause: "En Pause",
|
||||||
pauseDashboardHome: "Éléments mis en pause",
|
|
||||||
Name: "Nom",
|
Name: "Nom",
|
||||||
Status: "État",
|
Status: "État",
|
||||||
DateTime: "Heure",
|
DateTime: "Heure",
|
||||||
@@ -29,32 +54,27 @@ export default {
|
|||||||
Delete: "Supprimer",
|
Delete: "Supprimer",
|
||||||
Current: "Actuellement",
|
Current: "Actuellement",
|
||||||
Uptime: "Uptime",
|
Uptime: "Uptime",
|
||||||
"Cert Exp.": "Certificat expiré",
|
"Cert Exp.": "Expiration SSL",
|
||||||
days: "Jours",
|
days: "jours",
|
||||||
day: "Jour",
|
day: "jour",
|
||||||
"-day": "Journée",
|
"-day": "-jours",
|
||||||
hour: "Heure",
|
hour: "-heure",
|
||||||
"-hour": "Heures",
|
"-hour": "-heures",
|
||||||
checkEverySecond: "Vérifier toutes les {0} secondes",
|
|
||||||
Response: "Temps de réponse",
|
Response: "Temps de réponse",
|
||||||
Ping: "Ping",
|
Ping: "Ping",
|
||||||
"Monitor Type": "Type de Sonde",
|
"Monitor Type": "Type de Sonde",
|
||||||
Keyword: "Mot-clé",
|
Keyword: "Mot-clé",
|
||||||
"Friendly Name": "Nom d'affichage",
|
"Friendly Name": "Nom d'affichage",
|
||||||
URL: "URL",
|
URL: "URL",
|
||||||
Hostname: "Nom d'hôte",
|
Hostname: "Nom d'hôte / adresse IP",
|
||||||
Port: "Port",
|
Port: "Port",
|
||||||
"Heartbeat Interval": "Intervale de vérification",
|
"Heartbeat Interval": "Intervale de vérification",
|
||||||
Retries: "Essais",
|
Retries: "Essais",
|
||||||
retriesDescription: "Nombre d'essais avant que le service soit déclaré hors-ligne.",
|
"Heartbeat Retry Interval": "Réessayer l'intervale de vérification",
|
||||||
Advanced: "Avancé",
|
Advanced: "Avancé",
|
||||||
ignoreTLSError: "Ignorer les erreurs liées au certificat SSL/TLS",
|
|
||||||
"Upside Down Mode": "Mode inversé",
|
"Upside Down Mode": "Mode inversé",
|
||||||
upsideDownModeDescription: "Si le service est en ligne, il sera alors noté hors-ligne et vice-versa.",
|
|
||||||
"Max. Redirects": "Nombre maximum de redirections",
|
"Max. Redirects": "Nombre maximum de redirections",
|
||||||
maxRedirectDescription: "Nombre maximal de redirections avant que le service soit noté hors-ligne.",
|
"Accepted Status Codes": "Codes HTTP acceptés",
|
||||||
"Accepted Status Codes": "Codes HTTP",
|
|
||||||
acceptedStatusCodesDescription: "Codes HTTP considérés comme en ligne",
|
|
||||||
Save: "Sauvegarder",
|
Save: "Sauvegarder",
|
||||||
Notifications: "Notifications",
|
Notifications: "Notifications",
|
||||||
"Not available, please setup.": "Pas de système de notification disponible, merci de le configurer",
|
"Not available, please setup.": "Pas de système de notification disponible, merci de le configurer",
|
||||||
@@ -63,9 +83,9 @@ export default {
|
|||||||
Dark: "Sombre",
|
Dark: "Sombre",
|
||||||
Auto: "Automatique",
|
Auto: "Automatique",
|
||||||
"Theme - Heartbeat Bar": "Voir les services surveillés",
|
"Theme - Heartbeat Bar": "Voir les services surveillés",
|
||||||
Normal: "Général",
|
Normal: "Normal",
|
||||||
Bottom: "En dessous",
|
Bottom: "En dessous",
|
||||||
None: "Rien",
|
None: "Aucun",
|
||||||
Timezone: "Fuseau Horaire",
|
Timezone: "Fuseau Horaire",
|
||||||
"Search Engine Visibility": "Visibilité par les moteurs de recherche",
|
"Search Engine Visibility": "Visibilité par les moteurs de recherche",
|
||||||
"Allow indexing": "Autoriser l'indexation par des moteurs de recherche",
|
"Allow indexing": "Autoriser l'indexation par des moteurs de recherche",
|
||||||
@@ -74,14 +94,12 @@ export default {
|
|||||||
"Current Password": "Mot de passe actuel",
|
"Current Password": "Mot de passe actuel",
|
||||||
"New Password": "Nouveau mot de passe",
|
"New Password": "Nouveau mot de passe",
|
||||||
"Repeat New Password": "Répéter votre nouveau mot de passe",
|
"Repeat New Password": "Répéter votre nouveau mot de passe",
|
||||||
passwordNotMatchMsg: "Les mots de passe ne correspondent pas",
|
|
||||||
"Update Password": "Mettre à jour le mot de passe",
|
"Update Password": "Mettre à jour le mot de passe",
|
||||||
"Disable Auth": "Désactiver l'authentification",
|
"Disable Auth": "Désactiver l'authentification",
|
||||||
"Enable Auth": "Activer l'authentification",
|
"Enable Auth": "Activer l'authentification",
|
||||||
Logout: "Se déconnecter",
|
Logout: "Se déconnecter",
|
||||||
notificationDescription: "Une fois ajoutée, vous devez l'activer manuellement dans les paramètres de vos hôtes.",
|
|
||||||
Leave: "Quitter",
|
Leave: "Quitter",
|
||||||
"I understand, please disable": "J'ai compris, désactivez-le",
|
"I understand, please disable": "Je comprends, désactivez-le",
|
||||||
Confirm: "Confirmer",
|
Confirm: "Confirmer",
|
||||||
Yes: "Oui",
|
Yes: "Oui",
|
||||||
No: "Non",
|
No: "Non",
|
||||||
@@ -94,43 +112,35 @@ export default {
|
|||||||
"Notification Type": "Type de notification",
|
"Notification Type": "Type de notification",
|
||||||
Email: "Email",
|
Email: "Email",
|
||||||
Test: "Tester",
|
Test: "Tester",
|
||||||
keywordDescription: "Le mot clé sera recherché dans la réponse HTML/JSON reçue du site internet.",
|
|
||||||
"Certificate Info": "Informations sur le certificat SSL",
|
"Certificate Info": "Informations sur le certificat SSL",
|
||||||
deleteMonitorMsg: "Êtes-vous sûr de vouloir supprimer cette sonde ?",
|
|
||||||
deleteNotificationMsg: "Êtes-vous sûr de vouloir supprimer ce type de notifications ? Une fois désactivée, les services qui l'utilisent ne pourront plus envoyer de notifications.",
|
|
||||||
"Resolver Server": "Serveur DNS utilisé",
|
"Resolver Server": "Serveur DNS utilisé",
|
||||||
"Resource Record Type": "Type d'enregistrement DNS recherché",
|
"Resource Record Type": "Type d'enregistrement DNS recherché",
|
||||||
resoverserverDescription: "Le DNS de cloudflare est utilisé par défaut, mais vous pouvez le changer si vous le souhaitez.",
|
|
||||||
rrtypeDescription: "Veuillez séléctionner un type d'enregistrement DNS",
|
|
||||||
pauseMonitorMsg: "Etes vous sur de vouloir mettre en pause cette sonde ?",
|
|
||||||
"Last Result": "Dernier résultat",
|
"Last Result": "Dernier résultat",
|
||||||
"Create your admin account": "Créez votre compte administrateur",
|
"Create your admin account": "Créez votre compte administrateur",
|
||||||
"Repeat Password": "Répéter le mot de passe",
|
"Repeat Password": "Répéter le mot de passe",
|
||||||
|
"Import Backup": "Importation de la sauvegarde",
|
||||||
|
"Export Backup": "Exportation de la sauvegarde",
|
||||||
|
Export: "Exporter",
|
||||||
|
Import: "Importer",
|
||||||
respTime: "Temps de réponse (ms)",
|
respTime: "Temps de réponse (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "Activé par défaut",
|
||||||
|
"Apply on all existing monitors": "Appliquer sur toutes les sondes existantes",
|
||||||
Create: "Créer",
|
Create: "Créer",
|
||||||
clearEventsMsg: "Êtes-vous sûr de vouloir supprimer tous les événements pour cette sonde ?",
|
|
||||||
clearHeartbeatsMsg: "Êtes-vous sûr de vouloir supprimer tous les vérifications pour cette sonde ? Are you sure want to delete all heartbeats for this monitor?",
|
|
||||||
confirmClearStatisticsMsg: "tes-vous sûr de vouloir supprimer tous les statistiques ?",
|
|
||||||
"Clear Data": "Effacer les données",
|
"Clear Data": "Effacer les données",
|
||||||
Events: "Evénements",
|
Events: "Evénements",
|
||||||
Heartbeats: "Vérfications",
|
Heartbeats: "Vérfications",
|
||||||
"Auto Get": "Auto Get",
|
"Auto Get": "Récuperer automatiquement",
|
||||||
enableDefaultNotificationDescription: "Pour chaque nouvelle sonde, cette notification sera activée par défaut. Vous pouvez toujours désactiver la notification séparément pour chaque sonde.",
|
|
||||||
"Default enabled": "Activé par défaut",
|
|
||||||
"Also apply to existing monitors": "S'applique également aux sondes existantes",
|
|
||||||
Export: "Exporter",
|
|
||||||
Import: "Importer",
|
|
||||||
backupDescription: "Vous pouvez sauvegarder toutes les sondes et toutes les notifications dans un fichier JSON.",
|
backupDescription: "Vous pouvez sauvegarder toutes les sondes et toutes les notifications dans un fichier JSON.",
|
||||||
backupDescription2: "PS: Les données relatives à l'historique et aux événements ne sont pas incluses.",
|
backupDescription2: "PS: Les données relatives à l'historique et aux événements ne sont pas incluses.",
|
||||||
backupDescription3: "Les données sensibles telles que les jetons de notification sont incluses dans le fichier d'exportation, veuillez les conserver soigneusement.",
|
backupDescription3: "Les données sensibles telles que les jetons de notification sont incluses dans le fichier d'exportation, veuillez les conserver soigneusement.",
|
||||||
alertNoFile: "Veuillez sélectionner un fichier à importer.",
|
alertNoFile: "Veuillez sélectionner un fichier à importer.",
|
||||||
alertWrongFileType: "Veuillez sélectionner un fichier JSON à importer.",
|
alertWrongFileType: "Veuillez sélectionner un fichier JSON à importer.",
|
||||||
twoFAVerifyLabel: "Veuillez saisir votre jeton pour vérifier que le système 2FA fonctionne.",
|
"Clear all statistics": "Effacer toutes les statistiques",
|
||||||
tokenValidSettingsMsg: "Le jeton est valide ! Vous pouvez maintenant sauvegarder les paramètres 2FA.",
|
"Skip existing": "Sauter l'existant",
|
||||||
confirmEnableTwoFAMsg: "Êtes-vous sûr de vouloir activer le 2FA ?",
|
Overwrite: "Ecraser",
|
||||||
confirmDisableTwoFAMsg: "Êtes-vous sûr de vouloir désactiver le 2FA ?",
|
Options: "Options",
|
||||||
"Apply on all existing monitors": "Appliquer sur toutes les sondes existantes",
|
"Keep both": "Garder les deux",
|
||||||
"Verify Token": "Vérifier le jeton",
|
"Verify Token": "Vérifier le jeton",
|
||||||
"Setup 2FA": "Configurer 2FA",
|
"Setup 2FA": "Configurer 2FA",
|
||||||
"Enable 2FA": "Activer 2FA",
|
"Enable 2FA": "Activer 2FA",
|
||||||
@@ -141,23 +151,12 @@ export default {
|
|||||||
Inactive: "Inactif",
|
Inactive: "Inactif",
|
||||||
Token: "Jeton",
|
Token: "Jeton",
|
||||||
"Show URI": "Afficher l'URI",
|
"Show URI": "Afficher l'URI",
|
||||||
"Clear all statistics": "Effacer touutes les statistiques",
|
|
||||||
retryCheckEverySecond: "Réessayer toutes les {0} secondes.",
|
|
||||||
importHandleDescription: "Choisissez 'Ignorer l'existant' si vous voulez ignorer chaque sonde ou notification portant le même nom. L'option 'Écraser' supprime tous les sondes et notifications existantes.",
|
|
||||||
confirmImportMsg: "Êtes-vous sûr d'importer la sauvegarde ? Veuillez vous assurer que vous avez sélectionné la bonne option d'importation.",
|
|
||||||
"Heartbeat Retry Interval": "Réessayer l'intervale de vérification",
|
|
||||||
"Import Backup": "Importation de la sauvegarde",
|
|
||||||
"Export Backup": "Exportation de la sauvegarde",
|
|
||||||
"Skip existing": "Sauter l'existant",
|
|
||||||
Overwrite: "Ecraser",
|
|
||||||
Options: "Options",
|
|
||||||
"Keep both": "Garder les deux",
|
|
||||||
Tags: "Étiquettes",
|
Tags: "Étiquettes",
|
||||||
"Add New below or Select...": "Ajouter nouveau ci-dessous ou sélectionner...",
|
"Add New below or Select...": "Ajoutez-en un en dessous ou sélectionnez-le ici...",
|
||||||
"Tag with this name already exist.": "Une étiquette portant ce nom existe déjà.",
|
"Tag with this name already exist.": "Une étiquette portant ce nom existe déjà.",
|
||||||
"Tag with this value already exist.": "Une étiquette avec cette valeur existe déjà.",
|
"Tag with this value already exist.": "Une étiquette avec cette valeur existe déjà.",
|
||||||
color: "couleur",
|
color: "Couleur",
|
||||||
"value (optional)": "valeur (facultatif)",
|
"value (optional)": "Valeur (facultatif)",
|
||||||
Gray: "Gris",
|
Gray: "Gris",
|
||||||
Red: "Rouge",
|
Red: "Rouge",
|
||||||
Orange: "Orange",
|
Orange: "Orange",
|
||||||
@@ -180,14 +179,57 @@ export default {
|
|||||||
"Edit Status Page": "Modifier la page de statut",
|
"Edit Status Page": "Modifier la page de statut",
|
||||||
"Go to Dashboard": "Accéder au tableau de bord",
|
"Go to Dashboard": "Accéder au tableau de bord",
|
||||||
"Status Page": "Status Page",
|
"Status Page": "Status Page",
|
||||||
|
defaultNotificationName: "Ma notification {notification} numéro ({number})",
|
||||||
|
here: "ici",
|
||||||
|
Required: "Requis",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "Bot Token",
|
||||||
|
wayToGetTelegramToken: "Vous pouvez obtenir un token depuis {0}.",
|
||||||
|
"Chat ID": "Chat ID",
|
||||||
|
supportTelegramChatID: "Supporte les messages privés / en groupe / l'ID du salon",
|
||||||
|
wayToGetTelegramChatID: "Vous pouvez obtenir l'ID du chat en envoyant un message avec le bot puis en récupérant l'URL pour voir l'ID du salon :",
|
||||||
|
"YOUR BOT TOKEN HERE": "VOTRE TOKEN BOT ICI",
|
||||||
|
chatIDNotFound: "ID du salon introuvable, envoyez un message via le bot avant",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
|
"Post URL": "Post URL",
|
||||||
|
"Content Type": "Content Type",
|
||||||
|
webhookJsonDesc: "{0} est bien/bon pour tous les serveurs HTTP modernes comme express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} est bien/bon pour du PHP, vous avez juste besoin de mettre le json via/depuis {decodeFunction}",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
secureOptionNone: "Aucun / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "Ignorer les erreurs TLS",
|
||||||
|
"From Email": "Depuis l'Email",
|
||||||
|
"To Email": "Vers l'Email",
|
||||||
|
smtpCC: "CC",
|
||||||
|
smtpBCC: "BCC",
|
||||||
discord: "Discord",
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "Vous pouvez l'obtenir en allant dans 'Paramètres du Serveur' -> 'Intégrations' -> 'Créer un Webhook'",
|
||||||
|
"Bot Display Name": "Nom du bot (affiché)",
|
||||||
|
"Prefix Custom Message": "Prefix Custom Message",
|
||||||
|
"Hello @everyone is...": "Bonjour {'@'}everyone il...",
|
||||||
teams: "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "Webhook URL",
|
||||||
|
wayToGetTeamsURL: "Vous pouvez apprendre comment créer un Webhook {0}.",
|
||||||
signal: "Signal",
|
signal: "Signal",
|
||||||
|
Number: "Numéro",
|
||||||
|
Recipients: "Destinataires",
|
||||||
|
needSignalAPI: "Vous avez besoin d'un client Signal avec l'API REST.",
|
||||||
|
wayToCheckSignalURL: "Vous pouvez regarder l'URL sur comment le mettre en place :",
|
||||||
|
signalImportant: "IMPORTANT: Vous ne pouvez pas mixer les groupes et les numéros en destinataires !",
|
||||||
gotify: "Gotify",
|
gotify: "Gotify",
|
||||||
|
"Application Token": "Application Token",
|
||||||
|
"Server URL": "Server URL",
|
||||||
|
Priority: "Priorité",
|
||||||
slack: "Slack",
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "Icon Emoji",
|
||||||
|
"Channel Name": "Nom du salon",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Plus d'informations sur les Webhooks ici: {0}",
|
||||||
|
aboutChannelName: "Mettez le nom du salon dans {0} dans 'Channel Name' si vous voulez bypass le salon Webhook. Ex : #autre-salon",
|
||||||
|
aboutKumaURL: "Si vous laissez l'URL d'Uptime Kuma vierge, elle redirigera vers la page du projet GitHub.",
|
||||||
|
emojiCheatSheet: "Emoji cheat sheet : {0}",
|
||||||
"rocket.chat": "Rocket.chat",
|
"rocket.chat": "Rocket.chat",
|
||||||
pushover: "Pushover",
|
pushover: "Pushover",
|
||||||
pushy: "Pushy",
|
pushy: "Pushy",
|
||||||
@@ -198,4 +240,68 @@ export default {
|
|||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
"User Key": "Clé d'utilisateur",
|
||||||
|
Device: "Appareil",
|
||||||
|
"Message Title": "Titre du message",
|
||||||
|
"Notification Sound": "Son de notification",
|
||||||
|
"More info on:": "Plus d'informations sur: {0}",
|
||||||
|
pushoverDesc1: "Priorité d'urgence (2) a par défaut 30 secondes de délai dépassé entre les tentatives et expierera après 1 heure.",
|
||||||
|
pushoverDesc2: "Si vous voulez envoyer des notifications sur différents Appareils, remplissez le champ 'Device'.",
|
||||||
|
"SMS Type": "SMS Type",
|
||||||
|
octopushTypePremium: "Premium (Rapide - recommandé pour les alertes)",
|
||||||
|
octopushTypeLowCost: "A bas prix (Lent, bloqué de temps en temps par l'opérateur)",
|
||||||
|
"Check octopush prices": "Vérifier les prix d'octopush {0}.",
|
||||||
|
octopushPhoneNumber: "Numéro de téléphone (format intérn., ex : +33612345678) ",
|
||||||
|
octopushSMSSender: "Nom de l'envoyer : 3-11 caractères alphanumériques avec espace (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "LunaSea Device ID",
|
||||||
|
"Apprise URL": "Apprise URL",
|
||||||
|
"Example:": "Exemple : {0}",
|
||||||
|
"Read more:": "En savoir plus : {0}",
|
||||||
|
"Status:": "Status : {0}",
|
||||||
|
"Read more": "En savoir plus",
|
||||||
|
appriseInstalled: "Apprise est intallé.",
|
||||||
|
appriseNotInstalled: "Apprise n'est pas intallé. {0}",
|
||||||
|
"Access Token": "Access Token",
|
||||||
|
"Channel access token": "Channel access token",
|
||||||
|
"Line Developers Console": "Line Developers Console",
|
||||||
|
lineDevConsoleTo: "Line Developers Console - {0}",
|
||||||
|
"Basic Settings": "Paramètres de base",
|
||||||
|
"User ID": "Identifiant utilisateur",
|
||||||
|
"Messaging API": "Messaging API",
|
||||||
|
wayToGetLineChannelToken: "Premièrement accéder à {0}, créez un Provider et un Salon (Messaging API), puis vous pourrez avoir le Token d'accès du salon ainsi que l'Identifiant utilisateur depuis le même menu.",
|
||||||
|
"Icon URL": "Icon URL",
|
||||||
|
aboutIconURL: "Vous pouvez mettre un lien vers l'image dans \"Icon URL\" pour remplacer l'image de profil par défaut. Ne sera pas utilisé si Icon Emoji est défini.",
|
||||||
|
aboutMattermostChannelName: "Vous pouvez remplacer le salon par défaut que le Webhook utilise en mettant le nom du salon dans le champ \"Channel Name\". Vous aurez besoin de l'activer depuis les paramètres de Mattermost. Ex : #autre-salon",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO - Pas cher mais lent et souvent surchargé. Limité uniquement aux déstinataires Polonais.",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - Le message sera automatiquement affiché sur l'appareil du destinataire. Limité uniquement aux déstinataires Polonais.",
|
||||||
|
promosmsTypeFull: "SMS FULL - Version Premium des SMS, Vous pouvez mettre le nom de l'expéditeur (Vous devez vous enregistrer avant). Fiable pour les alertes.",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - La plus haute des priorités dans le système. Très rapide et fiable mais cher (environ le double du prix d'un SMS FULL).",
|
||||||
|
promosmsPhoneNumber: "Numéro de téléphone (Poiur les déstinataires Polonais, vous pouvez enlever les codes interna.)",
|
||||||
|
promosmsSMSSender: "SMS Expéditeur : Nom pré-enregistré ou l'un de base: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
|
"Primary Base URL": "Primary Base URL",
|
||||||
|
emailCustomSubject: "Sujet personalisé",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
|
checkPrice: "Vérification {0} tarifs:",
|
||||||
|
apiCredentials: "Crédentials de l'API",
|
||||||
|
octopushLegacyHint: "Vous utilisez l'ancienne version d'Octopush (2011-2020) ou la nouvelle version ?",
|
||||||
|
"Feishu WebHookUrl": "Feishu WebHookURL",
|
||||||
|
matrixHomeserverURL: "L'URL du serveur (avec http(s):// et le port de manière facultatif)",
|
||||||
|
"Internal Room Id": "ID de la salle interne",
|
||||||
|
matrixDesc1: "Vous pouvez trouvez l'ID de salle interne en regardant dans la section avancée des paramètres dans le client Matrix. C'est sensé ressembler à: !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
|
matrixDesc2: "Il est fortement recommandé de créer un nouvel utilisateur et de ne pas utiliser le jeton d'accès de votre propre utilisateur Matrix, car il vous donnera un accès complet à votre compte et à toutes les salles que vous avez rejointes. Au lieu de cela, créez un nouvel utilisateur et invitez-le uniquement dans la salle dans laquelle vous souhaitez recevoir la notification. Vous pouvez obtenir le jeton d'accès en exécutant {0}",
|
||||||
|
Method: "Méthode",
|
||||||
|
Body: "Le corps",
|
||||||
|
Headers: "En-têtes",
|
||||||
|
PushUrl: "Push URL",
|
||||||
|
HeadersInvalidFormat: "L'en-têtes de la requête n'est pas dans un format JSON valide: ",
|
||||||
|
BodyInvalidFormat: "Le corps de la requête n'est pas dans un format JSON valide: ",
|
||||||
|
"Monitor History": "Historique de la sonde",
|
||||||
|
clearDataOlderThan: "Garder l'historique des données de la sonde durant {0} jours.",
|
||||||
|
PasswordsDoNotMatch: "Les mots de passe ne correspondent pas.",
|
||||||
|
records: "Enregistrements",
|
||||||
|
"One record": "Un enregistrement",
|
||||||
|
steamApiKeyDescription: "Pour surveiller un serveur Steam, vous avez besoin d'une clé Steam Web-API. Vous pouvez enregistrer votre clé ici: ",
|
||||||
|
"Current User": "Utilisateur actuel",
|
||||||
|
recent: "Récent",
|
||||||
};
|
};
|
||||||
|
311
src/languages/hr-HR.js
Normal file
311
src/languages/hr-HR.js
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Hrvatski",
|
||||||
|
checkEverySecond: "Provjera svake {0} sekunde",
|
||||||
|
retryCheckEverySecond: "Ponovni pokušaj svake {0} sekunde",
|
||||||
|
retriesDescription: "Broj ponovnih pokušaja prije nego će se servis označiti kao nedostupan te poslati obavijest",
|
||||||
|
ignoreTLSError: "Ignoriraj TLS/SSL pogreške za HTTPS web stranice",
|
||||||
|
upsideDownModeDescription: "Preokreni logiku statusa. Ako se primi pozitivan odgovor, smatra se da je usluga nedostupna.",
|
||||||
|
maxRedirectDescription: "Maksimalan broj preusmjeravanja. Postaviti na 0 kako bi se preusmjeravanja onemogućila.",
|
||||||
|
acceptedStatusCodesDescription: "Odaberite statusne kodove koji se smatraju uspješnim odgovorom.",
|
||||||
|
passwordNotMatchMsg: "Lozinke se ne poklapaju.",
|
||||||
|
notificationDescription: "Obavijesti će funkcionirati samo ako su dodijeljene monitoru.",
|
||||||
|
keywordDescription: "Ključna riječ za pretragu, u obliku običnog HTML-a ili u JSON formatu. Pretraga je osjetljiva na velika i mala slova.",
|
||||||
|
deleteMonitorMsg: "Jeste li sigurni da želite izbrisati monitor?",
|
||||||
|
deleteNotificationMsg: "Jeste li sigurni da želite izbrisati ovu obavijest za sve monitore?",
|
||||||
|
resoverserverDescription: "Cloudflare je zadani DNS poslužitelj. Možete to promijeniti u bilo kojem trenutku.",
|
||||||
|
rrtypeDescription: "Odaberite vrstu DNS zapisa o resursu kojeg želite pratiti",
|
||||||
|
pauseMonitorMsg: "Jeste li sigurni da želite pauzirati?",
|
||||||
|
enableDefaultNotificationDescription: "Ova će obavijesti biti omogućena za sve nove monitore. Možete ju ručno onemogućiti za pojedini monitor.",
|
||||||
|
clearEventsMsg: "Jeste li sigurni da želite izbrisati sve zapise o događajima za ovaj monitor?",
|
||||||
|
clearHeartbeatsMsg: "Jeste li sigurni da želite izbrisati sve zapise o provjerama za ovaj monitor?",
|
||||||
|
confirmClearStatisticsMsg: "Jeste li sigurni da želite izbrisati SVE statistike?",
|
||||||
|
importHandleDescription: "Odaberite opciju \"Preskoči postojeće\" ako želite preskočiti uvoz postojećih monitora i obavijesti ako dođe do poklapanja u imenu. Opcija \"Prepiši\" će izbrisati postojeće monitore i obavijesti.",
|
||||||
|
confirmImportMsg: "Jeste li sigurni da želite pokrenuti uvoz? Provjerite jeste li odabrali ispravnu opciju uvoza.",
|
||||||
|
twoFAVerifyLabel: "Unesite svoj 2FA token:",
|
||||||
|
tokenValidSettingsMsg: "Token je važeći! Sada možete spremiti postavke dvofaktorske autentikacije.",
|
||||||
|
confirmEnableTwoFAMsg: "Želite li omogućiti dvofaktorsku autentikaciju?",
|
||||||
|
confirmDisableTwoFAMsg: "Jeste li sigurni da želite onemogućiti dvofaktorsku autentikaciju?",
|
||||||
|
Settings: "Postavke",
|
||||||
|
Dashboard: "Kontrolna ploča",
|
||||||
|
"New Update": "Novo ažuriranje",
|
||||||
|
Language: "Jezik",
|
||||||
|
Appearance: "Izgled",
|
||||||
|
Theme: "Tema",
|
||||||
|
General: "Općenito",
|
||||||
|
"Primary Base URL": "Osnovni URL",
|
||||||
|
Version: "Inačica",
|
||||||
|
"Check Update On GitHub": "Provjeri dostupnost nove inačice na GitHubu",
|
||||||
|
List: "Popis",
|
||||||
|
Add: "Dodaj",
|
||||||
|
"Add New Monitor": "Dodaj novi Monitor",
|
||||||
|
"Quick Stats": "Statistika",
|
||||||
|
Up: "Dostupno",
|
||||||
|
Down: "Nedostupno",
|
||||||
|
Pending: "U tijeku",
|
||||||
|
Unknown: "Nepoznato",
|
||||||
|
pauseDashboardHome: "Pauzirano",
|
||||||
|
Name: "Naziv",
|
||||||
|
Status: "Status",
|
||||||
|
DateTime: "Vremenska oznaka",
|
||||||
|
Message: "Izvještaj",
|
||||||
|
"No important events": "Nema važnih događaja",
|
||||||
|
Pause: "Pauziraj",
|
||||||
|
Resume: "Nastavi",
|
||||||
|
Edit: "Uredi",
|
||||||
|
Delete: "Obriši",
|
||||||
|
Current: "Trenutno",
|
||||||
|
Uptime: "Dostupnost",
|
||||||
|
"Cert Exp.": "Istek cert.",
|
||||||
|
days: "dana",
|
||||||
|
day: "dan",
|
||||||
|
"-day": "-dnevno",
|
||||||
|
hour: "sat",
|
||||||
|
"-hour": "-satno",
|
||||||
|
Response: "Odgovor",
|
||||||
|
Ping: "Odziv",
|
||||||
|
"Monitor Type": "Vrsta Monitora",
|
||||||
|
Keyword: "Ključna riječ",
|
||||||
|
"Friendly Name": "Prilagođen naziv",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Domaćin",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Interval provjere",
|
||||||
|
Retries: "Broj ponovnih pokušaja",
|
||||||
|
"Heartbeat Retry Interval": "Interval ponovnih pokušaja",
|
||||||
|
Advanced: "Napredne postavke",
|
||||||
|
"Upside Down Mode": "Obrnuti način",
|
||||||
|
"Max. Redirects": "Maksimalan broj preusmjeravanja",
|
||||||
|
"Accepted Status Codes": "Prihvaćeni statusni kodovi",
|
||||||
|
"Push URL": "Push URL",
|
||||||
|
needPushEvery: "Potrebno je slati zahtjeve na URL svakih {0} sekundi.",
|
||||||
|
pushOptionalParams: "Neobavezni parametri: {0}",
|
||||||
|
Save: "Spremi",
|
||||||
|
Notifications: "Obavijesti",
|
||||||
|
"Not available, please setup.": "Obavijesti nisu dostupne, potrebno dodati novu obavijest.",
|
||||||
|
"Setup Notification": "Dodaj obavijest",
|
||||||
|
Light: "Svijetli način",
|
||||||
|
Dark: "Tamni način",
|
||||||
|
Auto: "Automatski",
|
||||||
|
"Theme - Heartbeat Bar": "Tema za traku dostupnosti",
|
||||||
|
Normal: "Normalno",
|
||||||
|
Bottom: "Ispod",
|
||||||
|
None: "Isključeno",
|
||||||
|
Timezone: "Vremenska zona",
|
||||||
|
"Search Engine Visibility": "Vidljivost tražilicama",
|
||||||
|
"Allow indexing": "Dopusti indeksiranje",
|
||||||
|
"Discourage search engines from indexing site": "Sprječavanje indeksiranja",
|
||||||
|
"Change Password": "Promjena lozinke",
|
||||||
|
"Current Password": "Trenutna lozinka",
|
||||||
|
"New Password": "Nova lozinka",
|
||||||
|
"Repeat New Password": "Potvrdite novu lozinku",
|
||||||
|
"Update Password": "Spremi novu lozinku",
|
||||||
|
"Disable Auth": "Onemogući autentikaciju",
|
||||||
|
"Enable Auth": "Omogući autentikaciju",
|
||||||
|
Logout: "Odjava",
|
||||||
|
Leave: "Poništi",
|
||||||
|
"I understand, please disable": "Razumijem, svejedno onemogući",
|
||||||
|
Confirm: "Potvrda",
|
||||||
|
Yes: "Da",
|
||||||
|
No: "Ne",
|
||||||
|
Username: "Korisničko ime",
|
||||||
|
Password: "Lozinka",
|
||||||
|
"Remember me": "Zapamti me",
|
||||||
|
Login: "Prijava",
|
||||||
|
"No Monitors, please": "Nema monitora, ",
|
||||||
|
"add one": "dodaj jedan",
|
||||||
|
"Notification Type": "Tip obavijesti",
|
||||||
|
Email: "E-pošta",
|
||||||
|
Test: "Testiraj",
|
||||||
|
"Certificate Info": "Informacije o certifikatu",
|
||||||
|
"Resolver Server": "DNS poslužitelj",
|
||||||
|
"Resource Record Type": "Vrsta DNS zapisa",
|
||||||
|
"Last Result": "Posljednji rezultat",
|
||||||
|
"Create your admin account": "Stvori administratorski račun",
|
||||||
|
"Repeat Password": "Potvrda lozinke",
|
||||||
|
"Import Backup": "Uvoz sigurnosne kopije",
|
||||||
|
"Export Backup": "Izvoz sigurnosne kopije",
|
||||||
|
Export: "Izvoz",
|
||||||
|
Import: "Uvoz",
|
||||||
|
respTime: "Vrijeme odgovora (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "Omogući za nove monitore",
|
||||||
|
"Apply on all existing monitors": "Primijeni na postojeće monitore",
|
||||||
|
Create: "Kreiraj",
|
||||||
|
"Clear Data": "Obriši podatke",
|
||||||
|
Events: "Događaji",
|
||||||
|
Heartbeats: "Provjere",
|
||||||
|
"Auto Get": "Automatski dohvat",
|
||||||
|
backupDescription: "Moguće je napraviti sigurnosnu kopiju svih monitora i obavijesti koja će biti spremljena kao JSON datoteka.",
|
||||||
|
backupDescription2: "Napomena: povijest i podaci o događajima nisu uključeni u sigurnosnu kopiju.",
|
||||||
|
backupDescription3: "Osjetljivi podaci poput tokena za obavijesti uključeni su u sigurnosnu kopiju. Zato je potrebno čuvati izvoz na sigurnom mjestu.",
|
||||||
|
alertNoFile: "Datoteka za uvoz nije odabrana.",
|
||||||
|
alertWrongFileType: "Datoteka za uvoz nije u JSON formatu.",
|
||||||
|
"Clear all statistics": "Obriši sve statistike",
|
||||||
|
"Skip existing": "Preskoči postojeće",
|
||||||
|
Overwrite: "Prepiši",
|
||||||
|
Options: "Opcije",
|
||||||
|
"Keep both": "Zadrži sve",
|
||||||
|
"Verify Token": "Provjeri Token",
|
||||||
|
"Setup 2FA": "Postavi dvofaktorsku autentikaciju",
|
||||||
|
"Enable 2FA": "Omogući dvofaktorsku autentikaciju",
|
||||||
|
"Disable 2FA": "Onemogući dvofaktorsku autentikaciju",
|
||||||
|
"2FA Settings": "Postavke 2FA",
|
||||||
|
"Two Factor Authentication": "Dvofaktorska autentikacija",
|
||||||
|
Active: "Aktivna",
|
||||||
|
Inactive: "Neaktivno",
|
||||||
|
Token: "Token",
|
||||||
|
"Show URI": "Pokaži URI",
|
||||||
|
Tags: "Oznake",
|
||||||
|
"Add New below or Select...": "Dodajte novu oznaku ispod ili odaberite...",
|
||||||
|
"Tag with this name already exist.": "Oznaka s tim nazivom već postoji",
|
||||||
|
"Tag with this value already exist.": "Oznaka s tom vrijednošću već postoji.",
|
||||||
|
color: "Boja",
|
||||||
|
"value (optional)": "Vrijednost (neobavezno)",
|
||||||
|
Gray: "Siva",
|
||||||
|
Red: "Crvena",
|
||||||
|
Orange: "Narančasta",
|
||||||
|
Green: "Zelena",
|
||||||
|
Blue: "Plava",
|
||||||
|
Indigo: "Indigo",
|
||||||
|
Purple: "Ljubičasta",
|
||||||
|
Pink: "Ružičasta",
|
||||||
|
"Search...": "Pretraga...",
|
||||||
|
"Avg. Ping": "Prosječni odziv",
|
||||||
|
"Avg. Response": "Prosječni odgovor",
|
||||||
|
"Entry Page": "Početna stranica",
|
||||||
|
statusPageNothing: "Ovdje nema ničega, dodajte grupu ili monitor.",
|
||||||
|
"No Services": "Nema usluga",
|
||||||
|
"All Systems Operational": "Svi sustavi su operativni",
|
||||||
|
"Partially Degraded Service": "Usluga djelomično nedostupna",
|
||||||
|
"Degraded Service": "Usluga nedostupna",
|
||||||
|
"Add Group": "Dodaj grupu",
|
||||||
|
"Add a monitor": "Dodaj monitor",
|
||||||
|
"Edit Status Page": "Uredi Statusnu stranicu",
|
||||||
|
"Go to Dashboard": "Na Kontrolnu ploču",
|
||||||
|
"Status Page": "Statusna stranica",
|
||||||
|
defaultNotificationName: "Moja {number}. {notification} obavijest",
|
||||||
|
here: "ovdje",
|
||||||
|
Required: "Potrebno",
|
||||||
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "Token bota",
|
||||||
|
wayToGetTelegramToken: "Token možete nabaviti preko {0}.",
|
||||||
|
"Chat ID": "ID razgovora",
|
||||||
|
supportTelegramChatID: "Podržani su ID-jevi izravnih razgovora, grupa i kanala",
|
||||||
|
wayToGetTelegramChatID: "ID razgovora možete saznati tako da botu pošaljete poruku te odete na ovaj URL:",
|
||||||
|
"YOUR BOT TOKEN HERE": "OVDJE IDE TOKEN BOTA",
|
||||||
|
chatIDNotFound: "ID razgovora nije pronađen; prvo morate poslati poruku botu",
|
||||||
|
webhook: "Webhook",
|
||||||
|
"Post URL": "URL Post zahtjeva",
|
||||||
|
"Content Type": "Tip sadržaja (Content Type)",
|
||||||
|
webhookJsonDesc: "{0} je dobra opcija za moderne HTTP poslužitelje poput Express.js-a",
|
||||||
|
webhookFormDataDesc: "{multipart} je moguća alternativa za PHP, samo je potrebno parsirati JSON koristeći {decodeFunction}",
|
||||||
|
smtp: "E-mail (SMTP)",
|
||||||
|
secureOptionNone: "Bez sigurnosti / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "Ignoriraj greške TLS-a",
|
||||||
|
"From Email": "Adresa za \"From\" polje",
|
||||||
|
emailCustomSubject: "Prilagođeno \"Subject\" polje",
|
||||||
|
"To Email": "Odredišne adrese e-pošte",
|
||||||
|
smtpCC: "Cc",
|
||||||
|
smtpBCC: "Bcc",
|
||||||
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "URL Discord webhooka",
|
||||||
|
wayToGetDiscordURL: "Ovo možete dobiti tako da odete na Postavke servera -> Integracije -> Napravi webhook",
|
||||||
|
"Bot Display Name": "Nadimak Bota unutar servera",
|
||||||
|
"Prefix Custom Message": "Prefiks prilagođene poruke",
|
||||||
|
"Hello @everyone is...": "Pozdrav {'@'}everyone...",
|
||||||
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "URL webhooka",
|
||||||
|
wayToGetTeamsURL: "Više informacija o Teams webhookovima možete pročitati {0}.",
|
||||||
|
signal: "Signal",
|
||||||
|
Number: "Broj",
|
||||||
|
Recipients: "Primatelji",
|
||||||
|
needSignalAPI: "Potreban je klijent s REST sučeljem.",
|
||||||
|
wayToCheckSignalURL: "Više informacija o postavljanju Signal klijenta:",
|
||||||
|
signalImportant: "VAŽNO: Grupe i brojevi se ne mogu istovremeno koristiti kao primatelji!",
|
||||||
|
gotify: "Gotify",
|
||||||
|
"Application Token": "Token Aplikacije",
|
||||||
|
"Server URL": "URL poslužitelja",
|
||||||
|
Priority: "Prioritet",
|
||||||
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "Emotikon",
|
||||||
|
"Channel Name": "Naziv kanala",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Dodatne informacije o webhookovima su dostupne na: {0}",
|
||||||
|
aboutChannelName: "Unesite ime {0} kanala u polju Naziv kanala ako želite zaobići webhook kanal. Primjerice: #neki-kanal",
|
||||||
|
aboutKumaURL: "Ako je polje \"Uptime Kuma URL\" prazno, koristi se zadana vrijednost koja vodi na GitHub stranicu projekta.",
|
||||||
|
emojiCheatSheet: "Popis emotikona: {0}",
|
||||||
|
"rocket.chat": "Rocket.Chat",
|
||||||
|
pushover: "Pushover",
|
||||||
|
pushy: "Pushy",
|
||||||
|
octopush: "Octopush",
|
||||||
|
promosms: "PromoSMS",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
|
lunasea: "LunaSea",
|
||||||
|
apprise: "Apprise (Podržava preko 50 usluga za obavijesti)",
|
||||||
|
pushbullet: "Pushbullet",
|
||||||
|
line: "LINE",
|
||||||
|
mattermost: "Mattermost",
|
||||||
|
"User Key": "Korisnički ključ",
|
||||||
|
Device: "Uređaji",
|
||||||
|
"Message Title": "Naslov poruke",
|
||||||
|
"Notification Sound": "Zvuk obavijesti",
|
||||||
|
"More info on:": "Više informacija na: {0}",
|
||||||
|
pushoverDesc1: "Hitni prioritet (2) ima zadani istek vremena od 30 sekundi između ponovnih pokušaja te će isteći nakon 1 sata.",
|
||||||
|
pushoverDesc2: "Ako želite slati obavijesti na više uređaja, ispunite polje \"Uređaji\".",
|
||||||
|
"SMS Type": "Tip SMS-a",
|
||||||
|
octopushTypePremium: "Premium (Brzo - preporučeno za obavijesti)",
|
||||||
|
octopushTypeLowCost: "Low Cost (Sporo - mobilni operateri ponekad blokiraju ove poruke)",
|
||||||
|
checkPrice: "Provjerite {0} cijene:",
|
||||||
|
apiCredentials: "Vjerodajnice za API",
|
||||||
|
octopushLegacyHint: "Koristite li staru inačicu usluge Octopush (2011-2020) ili noviju inačicu?",
|
||||||
|
"Check octopush prices": "Provjerite cijene usluge Octopush {0}.",
|
||||||
|
octopushPhoneNumber: "Telefonski broj (međunarodni format, primjerice: +38512345678) ",
|
||||||
|
octopushSMSSender: "Naziv SMS pošiljatelja : 3-11 alfanumeričkih znakova i razmak (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "LunaSea ID Uređaja",
|
||||||
|
"Apprise URL": "URL usluge Apprise",
|
||||||
|
"Example:": "Primjerice: {0}",
|
||||||
|
"Read more:": "Pročitajte više: {0}",
|
||||||
|
"Status:": "Status: {0}",
|
||||||
|
"Read more": "Pročitaj više",
|
||||||
|
appriseInstalled: "Apprise je instaliran.",
|
||||||
|
appriseNotInstalled: "Apprise nije instaliran. {0}",
|
||||||
|
"Access Token": "Pristupni token",
|
||||||
|
"Channel access token": "Token za pristup kanalu",
|
||||||
|
"Line Developers Console": "LINE razvojnoj konzoli",
|
||||||
|
lineDevConsoleTo: "LINE razvojna konzola - {0}",
|
||||||
|
"Basic Settings": "Osnovne Postavke",
|
||||||
|
"User ID": "Korisnički ID",
|
||||||
|
"Messaging API": "API za razmjenu poruka",
|
||||||
|
wayToGetLineChannelToken: "Prvo, pristupite {0}, kreirajte pružatelja usluga te kanal (API za razmjenu poruka), zatim možete dobiti token za pristup kanalu te korisnički ID za polja iznad.",
|
||||||
|
"Icon URL": "URL slike",
|
||||||
|
aboutIconURL: "Možete postaviti poveznicu na sliku u polju \"URL slike\" kako biste spriječili korištenje zadane slike. Ovo se polje neće koristiti ako je postavljeno polje \"Emotikon\".",
|
||||||
|
aboutMattermostChannelName: "Možete promijeniti kanal u kojeg webhook šalje tako da ispunite polje \"Naziv kanala\". Ta opcija mora biti omogućena unutar Mattermost postavki za webhook. Primjerice: #neki-kanal",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO - jeftina, ali spora opcija koja je često preopterećena. Ograničeno samo na primatelje unutar Poljske.",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - Poruka se automatski pojavljuje na uređaju primatelja. Ograničeno samo na primatelje unutar Poljske.",
|
||||||
|
promosmsTypeFull: "SMS FULL - Premium razina usluge, dozvoljava postavljanje naziva SMS pošiljatelja (Naziv mora biti registriran). Usluga pouzdana za obavijesti.",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - Usluga najvećeg prioriteta. Brza i pouzdana, ali skupa (otprilike dvostruko skuplja od cijene usluge SMS FULL).",
|
||||||
|
promosmsPhoneNumber: "Telefonski broj (za primatelje unutar Poljske nije potrebno navoditi pozivni broj države)",
|
||||||
|
promosmsSMSSender: "Naziv SMS pošiljatelja: Registriran naziv ili jedan od zadanih: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
|
"Feishu WebHookUrl": "Feishu URL webhooka",
|
||||||
|
matrixHomeserverURL: "URL Matrix homeservera (uključujući http(s):// te port, ako je potrebno)",
|
||||||
|
"Internal Room Id": "Interni ID sobe",
|
||||||
|
matrixDesc1: "Interni ID sobe se može pronaći u naprednim postavkama sobe unutar Matrix klijenta. ID sobe nalikuje idućem zapisu: !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
|
matrixDesc2: "Preporučuje se stvaranje novog korisnika te suzdržavanje od korištenja pristupnog tokena vlastitog Matrix korisnika. Novog korisnika potrebno je dodati u sobe u kojima želite primati obavijesti. Pristupni token možete dobiti pokretanjem naredbe {0}",
|
||||||
|
Method: "Metoda",
|
||||||
|
Body: "Tijelo",
|
||||||
|
Headers: "Zaglavlja",
|
||||||
|
PushUrl: "Push URL",
|
||||||
|
HeadersInvalidFormat: "Zaglavlja nisu nije valjani JSON: ",
|
||||||
|
BodyInvalidFormat: "Tijelo zahtjeva nije valjani JSON: ",
|
||||||
|
"Monitor History": "Povijest monitora",
|
||||||
|
clearDataOlderThan: "Podaci o povijesti monitora čuvaju se {0} dana.",
|
||||||
|
PasswordsDoNotMatch: "Lozinke se ne poklapaju.",
|
||||||
|
records: "zapisa",
|
||||||
|
"One record": "Jedan zapis",
|
||||||
|
"Showing {from} to {to} of {count} records": "Prikaz zapisa {from}-{to} od sveukupno {count}",
|
||||||
|
steamApiKeyDescription: "Za praćenje Steam poslužitelja za igru, potrebno je imati Steam Web-API ključ. Možete registrirati vlastiti ključ ovdje: ",
|
||||||
|
"Current User": "Trenutni korisnik",
|
||||||
|
recent: "Nedavno",
|
||||||
|
};
|
283
src/languages/id-ID.js
Normal file
283
src/languages/id-ID.js
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Bahasa Indonesia (Indonesian)",
|
||||||
|
checkEverySecond: "Cek Setiap {0} detik.",
|
||||||
|
retryCheckEverySecond: "Coba lagi setiap {0} detik.",
|
||||||
|
retriesDescription: "Percobaan ulang maksimum sebelum layanan dinyatakan tidak aktif dan notifikasi dikirim",
|
||||||
|
ignoreTLSError: "Abaikan kesalahan TLS/SSL untuk situs web HTTPS",
|
||||||
|
upsideDownModeDescription: "Balikkan statusnya. Jika layanan dapat dijangkau, TIDAK AKTIF.",
|
||||||
|
maxRedirectDescription: "Jumlah maksimum pengalihan untuk diikuti. Setel ke 0 untuk menonaktifkan pengalihan.",
|
||||||
|
acceptedStatusCodesDescription: "Pilih kode status yang dianggap sebagai tanggapan yang berhasil.",
|
||||||
|
passwordNotMatchMsg: "Sandi kedua tidak cocok.",
|
||||||
|
notificationDescription: "Harap atur notifikasi ke monitor agar berfungsi.",
|
||||||
|
keywordDescription: "Cari kata kunci dalam code html atau JSON huruf besar-kecil berpengaruh",
|
||||||
|
pauseDashboardHome: "Jeda",
|
||||||
|
deleteMonitorMsg: "Apakah Anda mau menghapus monitor ini?",
|
||||||
|
deleteNotificationMsg: "Apakah Anda mau menghapus notifikasi ini untuk semua monitor?",
|
||||||
|
resoverserverDescription: "Cloudflare adalah server bawaan, Anda dapat mengubah server resolver kapan saja.",
|
||||||
|
rrtypeDescription: "Pilih RR-Type yang mau Anda monitor",
|
||||||
|
pauseMonitorMsg: "Apakah Anda yakin mau menjeda?",
|
||||||
|
enableDefaultNotificationDescription: "Untuk setiap monitor baru, notifikasi ini akan diaktifkan secara bawaan. Anda masih dapat menonaktifkan notifikasi secara terpisah untuk setiap monitor.",
|
||||||
|
clearEventsMsg: "Apakah Anda yakin mau menghapus semua event di monitor ini?",
|
||||||
|
clearHeartbeatsMsg: "Apakah Anda yakin mau menghapus semua heartbeats di monitor ini?",
|
||||||
|
confirmClearStatisticsMsg: "Apakah Anda yakin mau menghapus semua statistik?",
|
||||||
|
importHandleDescription: "Pilih 'Lewati yang ada' jika Anda ingin melewati setiap monitor atau notifikasi dengan nama yang sama. 'Timpa' akan menghapus setiap monitor dan notifikasi yang ada.",
|
||||||
|
confirmImportMsg: "Apakah Anda yakin untuk mengimpor cadangan? Pastikan Anda telah memilih opsi impor yang tepat.",
|
||||||
|
twoFAVerifyLabel: "Silakan ketik token Anda untuk memverifikasi bahwa 2FA berfungsi",
|
||||||
|
tokenValidSettingsMsg: "Tokennya benar! Anda sekarang dapat menyimpan pengaturan 2FA.",
|
||||||
|
confirmEnableTwoFAMsg: "Apakah Anda yakin ingin mengaktifkan 2FA?",
|
||||||
|
confirmDisableTwoFAMsg: "Apakah Anda yakin ingin menonaktifkan 2FA?",
|
||||||
|
Settings: "Pengaturan",
|
||||||
|
Dashboard: "Dasbor",
|
||||||
|
"New Update": "Pembaruan Baru",
|
||||||
|
Language: "Bahasa",
|
||||||
|
Appearance: "Tampilan",
|
||||||
|
Theme: "Tema",
|
||||||
|
General: "Umum",
|
||||||
|
Version: "Versi",
|
||||||
|
"Check Update On GitHub": "Cek Pembaruan di GitHub",
|
||||||
|
List: "Daftar",
|
||||||
|
Add: "Tambah",
|
||||||
|
"Add New Monitor": "Tambah Monitor Baru",
|
||||||
|
"Quick Stats": "Statistik",
|
||||||
|
Up: "Aktif",
|
||||||
|
Down: "Tidak Aktif",
|
||||||
|
Pending: "Tertunda",
|
||||||
|
Unknown: "Tidak diketahui",
|
||||||
|
Pause: "Jeda",
|
||||||
|
Name: "Nama",
|
||||||
|
Status: "Status",
|
||||||
|
DateTime: "Tanggal Waktu",
|
||||||
|
Message: "Pesan",
|
||||||
|
"No important events": "Tidak ada peristiwa penting",
|
||||||
|
Resume: "Lanjut",
|
||||||
|
Edit: "Ubah",
|
||||||
|
Delete: "Hapus",
|
||||||
|
Current: "Saat ini",
|
||||||
|
Uptime: "Waktu aktif",
|
||||||
|
"Cert Exp.": "Cert Exp.",
|
||||||
|
days: "hari-hari",
|
||||||
|
day: "hari",
|
||||||
|
"-day": "-hari",
|
||||||
|
hour: "Jam",
|
||||||
|
"-hour": "-Jam",
|
||||||
|
Response: "Tanggapan",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Tipe Monitor",
|
||||||
|
Keyword: "Keyword",
|
||||||
|
"Friendly Name": "Nama yang Ramah",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Hostname",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Jarak Waktu Heartbeat ",
|
||||||
|
Retries: "Coba lagi",
|
||||||
|
"Heartbeat Retry Interval": "Jarak Waktu Heartbeat Mencoba kembali ",
|
||||||
|
Advanced: "Tingkat Lanjut",
|
||||||
|
"Upside Down Mode": "Mode Terbalik",
|
||||||
|
"Max. Redirects": "Maksimal Pengalihan",
|
||||||
|
"Accepted Status Codes": "Kode Status yang Diterima",
|
||||||
|
Save: "Simpan",
|
||||||
|
Notifications: "Notifikasi",
|
||||||
|
"Not available, please setup.": "Tidak tersedia, silakan atur.",
|
||||||
|
"Setup Notification": "Setel Notifikasi",
|
||||||
|
Light: "Terang",
|
||||||
|
Dark: "Gelap",
|
||||||
|
Auto: "Otomatis",
|
||||||
|
"Theme - Heartbeat Bar": "Tema - Heartbeat Bar",
|
||||||
|
Normal: "Normal",
|
||||||
|
Bottom: "Bawah",
|
||||||
|
None: "Tidak ada",
|
||||||
|
Timezone: "Zona Waktu",
|
||||||
|
"Search Engine Visibility": "Visibilitas Mesin Pencari",
|
||||||
|
"Allow indexing": "Mengizinkan untuk diindex",
|
||||||
|
"Discourage search engines from indexing site": "Mencegah mesin pencari untuk mengindex situs",
|
||||||
|
"Change Password": "Ganti Sandi",
|
||||||
|
"Current Password": "Sandi Lama",
|
||||||
|
"New Password": "Sandi Baru",
|
||||||
|
"Repeat New Password": "Ulangi Sandi Baru",
|
||||||
|
"Update Password": "Perbarui Kata Sandi",
|
||||||
|
"Disable Auth": "Nonaktifkan Autentikasi",
|
||||||
|
"Enable Auth": "Aktifkan Autentikasi",
|
||||||
|
Logout: "Keluar",
|
||||||
|
Leave: "Pergi",
|
||||||
|
"I understand, please disable": "Saya mengerti, silakan dinonaktifkan",
|
||||||
|
Confirm: "Konfirmasi",
|
||||||
|
Yes: "Ya",
|
||||||
|
No: "Tidak",
|
||||||
|
Username: "Nama Pengguna",
|
||||||
|
Password: "Sandi",
|
||||||
|
"Remember me": "Ingat saya",
|
||||||
|
Login: "Masuk",
|
||||||
|
"No Monitors, please": "Tidak ada monitor, silakan",
|
||||||
|
"add one": "tambahkan satu",
|
||||||
|
"Notification Type": "Tipe Notifikasi",
|
||||||
|
Email: "Surel",
|
||||||
|
Test: "Tes",
|
||||||
|
"Certificate Info": "Info Sertifikasi",
|
||||||
|
"Resolver Server": "Resolver Server",
|
||||||
|
"Resource Record Type": "Resource Record Type",
|
||||||
|
"Last Result": "Hasil Terakhir",
|
||||||
|
"Create your admin account": "Buat admin akun Anda",
|
||||||
|
"Repeat Password": "Ulangi Sandi",
|
||||||
|
"Import Backup": "Impor Cadangan",
|
||||||
|
"Export Backup": "Expor Cadangan",
|
||||||
|
Export: "Expor",
|
||||||
|
Import: "Impor",
|
||||||
|
respTime: "Tanggapan. Waktu (milidetik)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "Bawaan diaktifkan",
|
||||||
|
"Apply on all existing monitors": "Terapkan pada semua monitor yang ada",
|
||||||
|
Create: "Buat",
|
||||||
|
"Clear Data": "Bersihkan Data",
|
||||||
|
Events: "Peristiwa",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Ambil Otomatis",
|
||||||
|
backupDescription: "Anda dapat mencadangkan semua monitor dan semua notifikasi ke dalam berkas JSON.",
|
||||||
|
backupDescription2: "Catatan: Data sejarah dan peristiwa tidak disertakan.",
|
||||||
|
backupDescription3: "Data sensitif seperti notifikasi token disertakan dalam berkas ekspor, harap simpan dengan hati-hati.",
|
||||||
|
alertNoFile: "Silakan pilih berkas untuk diimpor.",
|
||||||
|
alertWrongFileType: "Silakan pilih berkas JSON.",
|
||||||
|
"Clear all statistics": "Hapus semua statistik",
|
||||||
|
"Skip existing": "Lewati yang ada",
|
||||||
|
Overwrite: "Timpa",
|
||||||
|
Options: "Opsi",
|
||||||
|
"Keep both": "Simpan keduanya",
|
||||||
|
"Verify Token": "Verifikasi Token",
|
||||||
|
"Setup 2FA": "Pengaturan 2FA",
|
||||||
|
"Enable 2FA": "Aktifkan 2FA",
|
||||||
|
"Disable 2FA": "Nonaktifkan 2FA",
|
||||||
|
"2FA Settings": "Pengaturan 2FA",
|
||||||
|
"Two Factor Authentication": "Autentikasi Dua Faktor",
|
||||||
|
Active: "Aktif",
|
||||||
|
Inactive: "Tidak Aktif",
|
||||||
|
Token: "Token",
|
||||||
|
"Show URI": "Lihat URI",
|
||||||
|
Tags: "Tanda",
|
||||||
|
"Add New below or Select...": "Tambahkan Baru di bawah atau Pilih...",
|
||||||
|
"Tag with this name already exist.": "Tanda dengan nama ini sudah ada.",
|
||||||
|
"Tag with this value already exist.": "Tanda dengan nilai ini sudah ada.",
|
||||||
|
color: "warna",
|
||||||
|
"value (optional)": "nilai (harus diisi)",
|
||||||
|
Gray: "Abu-abu",
|
||||||
|
Red: "Merah",
|
||||||
|
Orange: "Jingga",
|
||||||
|
Green: "Hijau",
|
||||||
|
Blue: "Biru",
|
||||||
|
Indigo: "Biru Tua",
|
||||||
|
Purple: "Ungu",
|
||||||
|
Pink: "Merah Muda",
|
||||||
|
"Search...": "Cari...",
|
||||||
|
"Avg. Ping": "Rata-rata Ping",
|
||||||
|
"Avg. Response": "Rata-rata Tanggapan",
|
||||||
|
"Entry Page": "Halaman Masuk",
|
||||||
|
statusPageNothing: "Tidak ada di sini, silakan tambahkan grup atau monitor.",
|
||||||
|
"No Services": "Tidak ada Layanan",
|
||||||
|
"All Systems Operational": "Semua Sistem Berfungsi",
|
||||||
|
"Partially Degraded Service": "Layanan Terdegradasi Sebagian",
|
||||||
|
"Degraded Service": "Layanan Terdegradasi",
|
||||||
|
"Add Group": "Tambah Grup",
|
||||||
|
"Add a monitor": "Tambah monitor",
|
||||||
|
"Edit Status Page": "Edit Halaman Status",
|
||||||
|
"Go to Dashboard": "Pergi ke Dasbor",
|
||||||
|
"Status Page": "Halaman Status",
|
||||||
|
defaultNotificationName: "{notification} saya Peringatan ({number})",
|
||||||
|
here: "di sini",
|
||||||
|
Required: "Dibutuhkan",
|
||||||
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "Bot Token",
|
||||||
|
"You can get a token from": "Anda bisa mendapatkan token dari",
|
||||||
|
"Chat ID": "Chat ID",
|
||||||
|
supportTelegramChatID: "Mendukung Obrolan Langsung / Grup / Channel Chat ID",
|
||||||
|
wayToGetTelegramChatID: "Anda bisa mendapatkan chat id Anda dengan mengirim pesan ke bot dan pergi ke url ini untuk melihat chat_id:",
|
||||||
|
"YOUR BOT TOKEN HERE": "BOT TOKEN ANDA DI SINI",
|
||||||
|
chatIDNotFound: "Chat ID tidak ditemukan, tolong kirim pesan ke bot ini dulu",
|
||||||
|
webhook: "Webhook",
|
||||||
|
"Post URL": "Post URL",
|
||||||
|
"Content Type": "Tipe konten",
|
||||||
|
webhookJsonDesc: "{0} bagus untuk peladen http modern seperti express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} bagus untuk PHP, Anda hanya perlu mengurai json dengan {decodeFunction}",
|
||||||
|
smtp: "Surel (SMTP)",
|
||||||
|
secureOptionNone: "None / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "Abaikan Kesalahan TLS",
|
||||||
|
"From Email": "Dari Surel",
|
||||||
|
"To Email": "Ke Surel",
|
||||||
|
smtpCC: "CC",
|
||||||
|
smtpBCC: "BCC",
|
||||||
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "Anda bisa mendapatkan ini dengan pergi ke Server Settings -> Integrations -> Create Webhook",
|
||||||
|
"Bot Display Name": "Nama Bot",
|
||||||
|
"Prefix Custom Message": "Awalan Pesan",
|
||||||
|
"Hello @everyone is...": "Halo {'@'}everyone is...",
|
||||||
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "Webhook URL",
|
||||||
|
wayToGetTeamsURL: "Anda dapat mempelajari cara membuat url webhook {0}.",
|
||||||
|
signal: "Sinyal",
|
||||||
|
Number: "Nomer",
|
||||||
|
Recipients: "Penerima",
|
||||||
|
needSignalAPI: "Anda harus memiliki klien sinyal dengan REST API.",
|
||||||
|
wayToCheckSignalURL: "Anda dapat memeriksa url ini untuk melihat cara menyiapkannya:",
|
||||||
|
signalImportant: "PENTING: Anda tidak dapat mencampur grup dan nomor di penerima!",
|
||||||
|
gotify: "Gotify",
|
||||||
|
"Application Token": "Token Aplikasi",
|
||||||
|
"Server URL": "URL Peladen",
|
||||||
|
Priority: "Prioritas",
|
||||||
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "Ikon Emoji",
|
||||||
|
"Channel Name": "Nama Saluran",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Info lain tentang webhook: {0}",
|
||||||
|
aboutChannelName: "Masukan nama saluran di {0} Kolom Nama Saluran jika Anda ingin melewati saluran webhook. Contoh: #saluran-lain",
|
||||||
|
aboutKumaURL: "Jika Anda membiarkan bidang URL Uptime Kuma kosong, itu akan menjadi bawaan ke halaman Proyek Github.",
|
||||||
|
emojiCheatSheet: "Lembar contekan emoji: {0}",
|
||||||
|
"rocket.chat": "Rocket.chat",
|
||||||
|
pushover: "Pushover",
|
||||||
|
pushy: "Pushy",
|
||||||
|
octopush: "Octopush",
|
||||||
|
promosms: "PromoSMS",
|
||||||
|
lunasea: "LunaSea",
|
||||||
|
apprise: "Apprise (Mendukung 50+ layanan notifikasi)",
|
||||||
|
pushbullet: "Pushbullet",
|
||||||
|
line: "Line Messenger",
|
||||||
|
mattermost: "Mattermost",
|
||||||
|
"User Key": "Kunci pengguna",
|
||||||
|
Device: "Perangkat",
|
||||||
|
"Message Title": "Judul Pesan",
|
||||||
|
"Notification Sound": "Suara Nofifikasi",
|
||||||
|
"More info on:": "Info lebih lanjut tentang: {0}",
|
||||||
|
pushoverDesc1: "Prioritas darurat (2) memiliki batas waktu bawaan 30 detik antara percobaan ulang dan akan kadaluwarsa setelah 1 jam.",
|
||||||
|
pushoverDesc2: "Jika Anda ingin mengirim pemberitahuan ke perangkat yang berbeda, isi kolom Perangkat.",
|
||||||
|
"SMS Type": "Tipe SMS",
|
||||||
|
octopushTypePremium: "Premium (Cepat - direkomendasikan untuk mengingatkan)",
|
||||||
|
octopushTypeLowCost: "Low Cost (Lambat, terkadang diblokir oleh operator)",
|
||||||
|
"Check octopush prices": "Cek harga octopush {0}.",
|
||||||
|
octopushPhoneNumber: "Nomer Telpon/HP (format internasional, contoh : +33612345678) ",
|
||||||
|
octopushSMSSender: "Nama Pengirim SMS : 3-11 karakter alfanumerik dan spasi (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "LunaSea Device ID",
|
||||||
|
"Apprise URL": "Apprise URL",
|
||||||
|
"Example:": "Contoh: {0}",
|
||||||
|
"Read more:": "Baca lebih lajut: {0}",
|
||||||
|
"Status:": "Status: {0}",
|
||||||
|
"Read more": "Baca lebih lajut",
|
||||||
|
appriseInstalled: "Apprise diinstall.",
|
||||||
|
appriseNotInstalled: "Apprise tidak diinstall. {0}",
|
||||||
|
"Access Token": "Token Akses",
|
||||||
|
"Channel access token": "Token akses saluran",
|
||||||
|
"Line Developers Console": "Konsol Pengembang Line",
|
||||||
|
lineDevConsoleTo: "Konsol Pengembang Line - {0}",
|
||||||
|
"Basic Settings": "Pengaturan Dasar",
|
||||||
|
"User ID": "ID User",
|
||||||
|
"Messaging API": "Messaging API",
|
||||||
|
wayToGetLineChannelToken: "Pertama akses {0}, buat penyedia dan saluran (Messaging API), lalu Anda bisa mendapatkan token akses saluran dan id pengguna dari item menu yang disebutkan di atas.",
|
||||||
|
"Icon URL": "Icon URL",
|
||||||
|
aboutIconURL: "Anda dapat memberikan tautan ke gambar di \"Icon URL\" untuk mengganti gambar profil bawaan. Tidak akan digunakan jika Ikon Emoji diset.",
|
||||||
|
aboutMattermostChannelName: "Anda dapat mengganti saluran bawaan tujuan posting webhook dengan memasukkan nama saluran ke dalam Kolom \"Channel Name\". Ini perlu diaktifkan di pengaturan webhook Mattermost. contoh: #other-channel",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO - murah tapi lambat dan sering kelebihan beban. Terbatas hanya untuk penerima Polandia.",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - Pesan akan otomatis muncul di perangkat penerima. Terbatas hanya untuk penerima Polandia.",
|
||||||
|
promosmsTypeFull: "SMS FULL - SMS tingkat premium, Anda dapat menggunakan Nama Pengirim Anda (Anda harus mendaftarkan nama terlebih dahulu). Dapat diAndalkan untuk peringatan.",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - Prioritas tertinggi dalam sistem. Sangat cepat dan dapat diAndalkan tetapi mahal (sekitar dua kali lipat dari harga SMS FULL).",
|
||||||
|
promosmsPhoneNumber: "Nomor telepon (untuk penerima Polandia Anda dapat melewati kode area)",
|
||||||
|
promosmsSMSSender: "Nama Pengirim SMS : Nama pra-registrasi atau salah satu bawaan: InfoSMS, Info SMS, MaxSMS, INFO, SMS",
|
||||||
|
"Feishu WebHookUrl": "Feishu WebHookUrl",
|
||||||
|
};
|
@@ -1,20 +1,31 @@
|
|||||||
export default {
|
export default {
|
||||||
languageName: "한국어",
|
languageName: "한국어",
|
||||||
checkEverySecond: "{0} 초마다 체크해요.",
|
checkEverySecond: "{0}초마다 확인해요.",
|
||||||
|
retryCheckEverySecond: "{0}초마다 다시 확인해요.",
|
||||||
retriesDescription: "서비스가 중단된 후 알림을 보내기 전 최대 재시도 횟수",
|
retriesDescription: "서비스가 중단된 후 알림을 보내기 전 최대 재시도 횟수",
|
||||||
ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 에러 무시하기",
|
ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 에러 무시하기",
|
||||||
upsideDownModeDescription: "서버 상태를 반대로 표시해요. 서버가 작동하면 오프라인으로 표시할 거에요.",
|
upsideDownModeDescription: "서버 상태를 반대로 표시해요. 서버가 작동하면 오프라인으로 표시할 거예요.",
|
||||||
maxRedirectDescription: "최대 리다이렉트 횟수에요. 0을 입력하면 리다이렉트를 꺼요.",
|
maxRedirectDescription: "최대 리다이렉트 횟수예요. 0을 입력하면 리다이렉트를 꺼요.",
|
||||||
acceptedStatusCodesDescription: "응답 성공으로 간주할 상태 코드를 정해요.",
|
acceptedStatusCodesDescription: "응답 성공으로 간주할 상태 코드를 정해요.",
|
||||||
passwordNotMatchMsg: "비밀번호 재입력이 일치하지 않아요.",
|
passwordNotMatchMsg: "비밀번호 재입력이 일치하지 않아요.",
|
||||||
notificationDescription: "모니터링에 알림을 설정할 수 있어요.",
|
notificationDescription: "모니터링에 알림을 설정할 수 있어요.",
|
||||||
keywordDescription: "Html 이나 JSON에서 대소문자를 구분해 키워드를 검색해요.",
|
keywordDescription: "HTML 이나 JSON에서 대소문자를 구분해 키워드를 검색해요.",
|
||||||
pauseDashboardHome: "일시 정지",
|
pauseDashboardHome: "일시 정지",
|
||||||
deleteMonitorMsg: "정말 이 모니터링을 삭제할까요?",
|
deleteMonitorMsg: "정말 이 모니터링을 삭제할까요?",
|
||||||
deleteNotificationMsg: "정말 이 알림을 모든 모니터링에서 삭제할까요?",
|
deleteNotificationMsg: "정말 이 알림을 모든 모니터링에서 삭제할까요?",
|
||||||
resoverserverDescription: "Cloudflare가 기본 서버에요, 원한다면 언제나 다른 resolver 서버로 변경할 수 있어요.",
|
resoverserverDescription: "Cloudflare가 기본 서버예요, 원한다면 언제나 다른 Resolver 서버로 변경할 수 있어요.",
|
||||||
rrtypeDescription: "모니터링할 RR-Type을 선택해요.",
|
rrtypeDescription: "모니터링할 RR-Type을 선택해요.",
|
||||||
pauseMonitorMsg: "정말 이 모니터링을 일시 정지 할까요?",
|
pauseMonitorMsg: "정말 이 모니터링을 일시 정지할까요?",
|
||||||
|
enableDefaultNotificationDescription: "새로 추가하는 모든 모니터링에 이 알림을 기본적으로 활성화해요. 각 모니터에 대해 별도로 알림을 비활성화할 수 있어요.",
|
||||||
|
clearEventsMsg: "정말 이 모니터링에 대한 모든 이벤트를 삭제할까요?",
|
||||||
|
clearHeartbeatsMsg: "정말 이 모니터링에 대한 모든 하트비트를 삭제할까요?",
|
||||||
|
confirmClearStatisticsMsg: "정말 모든 통계를 삭제할까요?",
|
||||||
|
importHandleDescription: "이름이 같은 모든 모니터링이나 알림을 건너뛰려면 '기존값 건너뛰기'를 선택해주세요. '덮어쓰기'는 기존의 모든 모니터링과 알림을 삭제해요.",
|
||||||
|
confirmImportMsg: "정말 백업을 가져올까요? 가져오기 옵션을 제대로 설정했는지 다시 확인해주세요.",
|
||||||
|
twoFAVerifyLabel: "토큰을 입력해 2단계 인증이 작동하는지 확인해주세요.",
|
||||||
|
tokenValidSettingsMsg: "토큰이 유효해요! 이제 2단계 인증 설정을 저장할 수 있어요.",
|
||||||
|
confirmEnableTwoFAMsg: "정말 2단계 인증을 활성화할까요?",
|
||||||
|
confirmDisableTwoFAMsg: "정말 2단계 인증을 비활성화할까요?",
|
||||||
Settings: "설정",
|
Settings: "설정",
|
||||||
Dashboard: "대시보드",
|
Dashboard: "대시보드",
|
||||||
"New Update": "새로운 업데이트",
|
"New Update": "새로운 업데이트",
|
||||||
@@ -59,13 +70,14 @@ export default {
|
|||||||
Port: "포트",
|
Port: "포트",
|
||||||
"Heartbeat Interval": "하트비트 주기",
|
"Heartbeat Interval": "하트비트 주기",
|
||||||
Retries: "재시도",
|
Retries: "재시도",
|
||||||
|
"Heartbeat Retry Interval": "하트비드 재시도 주기",
|
||||||
Advanced: "고급",
|
Advanced: "고급",
|
||||||
"Upside Down Mode": "상태 반전 모드",
|
"Upside Down Mode": "상태 반전 모드",
|
||||||
"Max. Redirects": "최대 리다이렉트",
|
"Max. Redirects": "최대 리다이렉트",
|
||||||
"Accepted Status Codes": "응답 성공 상태 코드",
|
"Accepted Status Codes": "응답 성공 상태 코드",
|
||||||
Save: "저장",
|
Save: "저장",
|
||||||
Notifications: "알림",
|
Notifications: "알림",
|
||||||
"Not available, please setup.": "존재하지 않아요, 새로운거 하나 만드는건 어때요?",
|
"Not available, please setup.": "존재하지 않아요, 새로운 거 하나 만드는 건 어때요?",
|
||||||
"Setup Notification": "알림 설정",
|
"Setup Notification": "알림 설정",
|
||||||
Light: "라이트",
|
Light: "라이트",
|
||||||
Dark: "다크",
|
Dark: "다크",
|
||||||
@@ -73,7 +85,7 @@ export default {
|
|||||||
"Theme - Heartbeat Bar": "테마 - 하트비트 바",
|
"Theme - Heartbeat Bar": "테마 - 하트비트 바",
|
||||||
Normal: "기본값",
|
Normal: "기본값",
|
||||||
Bottom: "가운데",
|
Bottom: "가운데",
|
||||||
None: "제거",
|
None: "없애기",
|
||||||
Timezone: "시간대",
|
Timezone: "시간대",
|
||||||
"Search Engine Visibility": "검색 엔진 활성화",
|
"Search Engine Visibility": "검색 엔진 활성화",
|
||||||
"Allow indexing": "인덱싱 허용",
|
"Allow indexing": "인덱싱 허용",
|
||||||
@@ -83,8 +95,8 @@ export default {
|
|||||||
"New Password": "새로운 비밀번호",
|
"New Password": "새로운 비밀번호",
|
||||||
"Repeat New Password": "새로운 비밀번호 재입력",
|
"Repeat New Password": "새로운 비밀번호 재입력",
|
||||||
"Update Password": "비밀번호 변경",
|
"Update Password": "비밀번호 변경",
|
||||||
"Disable Auth": "인증 끄기",
|
"Disable Auth": "인증 비활성화",
|
||||||
"Enable Auth": "인증 켜기",
|
"Enable Auth": "인증 활성화",
|
||||||
Logout: "로그아웃",
|
Logout: "로그아웃",
|
||||||
Leave: "나가기",
|
Leave: "나가기",
|
||||||
"I understand, please disable": "기능에 대해 이해했으니 꺼주세요.",
|
"I understand, please disable": "기능에 대해 이해했으니 꺼주세요.",
|
||||||
@@ -106,31 +118,29 @@ export default {
|
|||||||
"Last Result": "최근 결과",
|
"Last Result": "최근 결과",
|
||||||
"Create your admin account": "관리자 계정 만들기",
|
"Create your admin account": "관리자 계정 만들기",
|
||||||
"Repeat Password": "비밀번호 재입력",
|
"Repeat Password": "비밀번호 재입력",
|
||||||
|
"Import Backup": "백업 가져오기",
|
||||||
|
"Export Backup": "백업 내보내기",
|
||||||
|
Export: "내보내기",
|
||||||
|
Import: "가져오기",
|
||||||
respTime: "응답 시간 (ms)",
|
respTime: "응답 시간 (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "기본 알림으로 설정",
|
||||||
|
"Apply on all existing monitors": "기존 모니터링에 모두 적용하기",
|
||||||
Create: "생성하기",
|
Create: "생성하기",
|
||||||
clearEventsMsg: "정말로 이 모니터링부터 모든 이벤트를 제거할까요?",
|
"Clear Data": "데이터 삭제",
|
||||||
clearHeartbeatsMsg: "정말로 이 모니터링부터 모든 하트비트를 제거할까요?",
|
|
||||||
confirmClearStatisticsMsg: "정말로 모든 통계치를 제거할까요?",
|
|
||||||
"Clear Data": "데이터 클리어",
|
|
||||||
Events: "이벤트",
|
Events: "이벤트",
|
||||||
Heartbeats: "하트비트",
|
Heartbeats: "하트비트",
|
||||||
"Auto Get": "자동 Get",
|
"Auto Get": "자동 Get",
|
||||||
enableDefaultNotificationDescription: "모든 모니터링에 이 알림이 기본값으로 설정될거에요. 각각 모니터링에서 이 알림을 비활성화 할 수 있어요.",
|
|
||||||
"Default enabled": "기본값 ",
|
|
||||||
"Also apply to existing monitors": "기존 모니터링에도 적용되요.",
|
|
||||||
Export: "내보내기",
|
|
||||||
Import: "가져오기",
|
|
||||||
backupDescription: "모든 모니터링과 알림을 JSON 파일 형식에 저장할 수 있어요.",
|
backupDescription: "모든 모니터링과 알림을 JSON 파일 형식에 저장할 수 있어요.",
|
||||||
backupDescription2: "(히스토리와 이벤트 데이터는 포함되어 있지 않아요.)",
|
backupDescription2: "히스토리와 이벤트 데이터는 포함되어 있지 않아요.",
|
||||||
backupDescription3: "알림 토큰과 같은 보안 데이터가 내보내기 파일에 포함되어 있으므로 관리에 주의해주세요.",
|
backupDescription3: "알림 토큰과 같은 보안 데이터가 내보내기 파일에 포함되어 있으므로 관리에 주의해주세요.",
|
||||||
alertNoFile: "가져오기를 하기 위해 파일을 선택해주세요.",
|
alertNoFile: "가져오기를 하기 위해 파일을 선택해주세요.",
|
||||||
alertWrongFileType: "JSON 파일을 선택해주세요.",
|
alertWrongFileType: "JSON 파일을 선택해주세요.",
|
||||||
twoFAVerifyLabel: "2단계 인증이 정상적으로 등록됬는지 확인하기 위해 토큰을 입력해주세요.",
|
"Clear all statistics": "모든 통계치 삭제",
|
||||||
tokenValidSettingsMsg: "토큰이 정상 값 이에요! 2단계 인증 설정을 저장할 수 있어요.",
|
"Skip existing": "기존값 건너뛰기",
|
||||||
confirmEnableTwoFAMsg: "정말로 2단계 인증을 활성화 할까요?",
|
Overwrite: "덮어쓰기",
|
||||||
confirmDisableTwoFAMsg: "정말로 2단계 인증을 비활성화 할까요?",
|
Options: "옵션",
|
||||||
"Apply on all existing monitors": "기존 모니터링에 모두 적용하기",
|
"Keep both": "두개 모두 보존",
|
||||||
"Verify Token": "토큰 검증",
|
"Verify Token": "토큰 검증",
|
||||||
"Setup 2FA": "2단계 인증 설정하기",
|
"Setup 2FA": "2단계 인증 설정하기",
|
||||||
"Enable 2FA": "2단계 인증 활성화",
|
"Enable 2FA": "2단계 인증 활성화",
|
||||||
@@ -141,17 +151,6 @@ export default {
|
|||||||
Inactive: "비활성화",
|
Inactive: "비활성화",
|
||||||
Token: "토큰",
|
Token: "토큰",
|
||||||
"Show URI": "URI 보기",
|
"Show URI": "URI 보기",
|
||||||
"Clear all statistics": "모든 통계치 ",
|
|
||||||
retryCheckEverySecond: "{0} 초마다 재시도",
|
|
||||||
importHandleDescription: "같은 이름을 가진 모든 모니터링 또는 알림들을 건너뛰기를 원하시면, '기존값 건너뛰기'를 눌러주세요. 기존 모니터링과 알림을 지우고 싶으면, '덮어쓰기'를 눌러주세요.",
|
|
||||||
confirmImportMsg: "정말로 백업을 가져올까요? 정확한 백업 설정인지 다시 확인해주세요.",
|
|
||||||
"Heartbeat Retry Interval": "하트비트 재시도 주기",
|
|
||||||
"Import Backup": "백업 가져오기",
|
|
||||||
"Export Backup": "백업 내보내기",
|
|
||||||
"Skip existing": "기존값 건너뛰기",
|
|
||||||
Overwrite: "덮어쓰기",
|
|
||||||
Options: "옵션",
|
|
||||||
"Keep both": "두개 모두 보존",
|
|
||||||
Tags: "태그",
|
Tags: "태그",
|
||||||
"Add New below or Select...": "아래 새롭게 추가 또는 선택...",
|
"Add New below or Select...": "아래 새롭게 추가 또는 선택...",
|
||||||
"Tag with this name already exist.": "같은 태그 이름이 이미 존재해요.",
|
"Tag with this name already exist.": "같은 태그 이름이 이미 존재해요.",
|
||||||
@@ -159,10 +158,10 @@ export default {
|
|||||||
color: "색상",
|
color: "색상",
|
||||||
"value (optional)": "값 (선택)",
|
"value (optional)": "값 (선택)",
|
||||||
Gray: "회색",
|
Gray: "회색",
|
||||||
Red: "빨강색",
|
Red: "빨간색",
|
||||||
Orange: "주황색",
|
Orange: "주황색",
|
||||||
Green: "초록색",
|
Green: "초록색",
|
||||||
Blue: "파랑색",
|
Blue: "파란색",
|
||||||
Indigo: "남색",
|
Indigo: "남색",
|
||||||
Purple: "보라색",
|
Purple: "보라색",
|
||||||
Pink: "핑크색",
|
Pink: "핑크색",
|
||||||
@@ -176,26 +175,108 @@ export default {
|
|||||||
"Partially Degraded Service": "일부 시스템 비정상",
|
"Partially Degraded Service": "일부 시스템 비정상",
|
||||||
"Degraded Service": "모든 시스템 비정상",
|
"Degraded Service": "모든 시스템 비정상",
|
||||||
"Add Group": "그룹 추가",
|
"Add Group": "그룹 추가",
|
||||||
"Add a monitor": "모니터링 추가r",
|
"Add a monitor": "모니터링 추가",
|
||||||
"Edit Status Page": "상태 페이지 수정",
|
"Edit Status Page": "상태 페이지 수정",
|
||||||
"Go to Dashboard": "대쉬보드로 가기",
|
"Go to Dashboard": "대시보드로 가기",
|
||||||
"Status Page": "상태 페이지",
|
"Status Page": "상태 페이지",
|
||||||
|
defaultNotificationName: "내 {notification} 알림 ({number})",
|
||||||
|
here: "여기",
|
||||||
|
Required: "필수",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "봇 토큰",
|
||||||
|
wayToGetTelegramToken: "토큰은 여기서 얻을 수 있어요: {0}.",
|
||||||
|
"Chat ID": "채팅 ID",
|
||||||
|
supportTelegramChatID: "Direct Chat / Group / Channel's Chat ID를 지원해요.",
|
||||||
|
wayToGetTelegramChatID: "봇에 메시지를 보내 채팅 ID를 얻고 밑에 URL로 이동해 chat_id를 볼 수 있어요.",
|
||||||
|
"YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE",
|
||||||
|
chatIDNotFound: "채팅 ID를 찾을 수 없어요. 먼저 봇에게 메시지를 보내주세요.",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
|
"Post URL": "Post URL",
|
||||||
|
"Content Type": "Content Type",
|
||||||
|
webhookJsonDesc: "{0}은 express.js와 같은 최신 HTTP 서버에 적합해요.",
|
||||||
|
webhookFormDataDesc: "{multipart}은 PHP에 적합해요. {decodeFunction}를 기준으로 json을 디코딩하면 돼요.",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
|
secureOptionNone: "없음 / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "TLS 에러 무시하기",
|
||||||
|
"From Email": "보내는 이메일",
|
||||||
|
"To Email": "받는 이메일",
|
||||||
|
smtpCC: "참조",
|
||||||
|
smtpBCC: "숨은 참조",
|
||||||
discord: "Discord",
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "서버 설정 -> 연동 -> 웹후크 보기 -> 새 웹후크에서 얻을 수 있어요.",
|
||||||
|
"Bot Display Name": "표시 이름",
|
||||||
|
"Prefix Custom Message": "접두사 메시지",
|
||||||
|
"Hello @everyone is...": "{'@'}everyone 서버 상태 알림이에요...",
|
||||||
teams: "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "Webhook URL",
|
||||||
|
wayToGetTeamsURL: "{0}에서 Webhook을 어떻게 만드는지 알아봐요.",
|
||||||
signal: "Signal",
|
signal: "Signal",
|
||||||
|
Number: "숫자",
|
||||||
|
Recipients: "받는 사람",
|
||||||
|
needSignalAPI: "REST API를 사용하는 Signal 클라이언트가 있어야 해요.",
|
||||||
|
wayToCheckSignalURL: "밑에 URL을 확인해 URL 설정 방법을 볼 수 있어요.",
|
||||||
|
signalImportant: "중요: 받는 사람의 그룹과 숫자는 섞을 수 없어요!",
|
||||||
gotify: "Gotify",
|
gotify: "Gotify",
|
||||||
|
"Application Token": "애플리케이션 토큰",
|
||||||
|
"Server URL": "서버 URL",
|
||||||
|
Priority: "Priority",
|
||||||
slack: "Slack",
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "아이콘 이모지",
|
||||||
|
"Channel Name": "채널 이름",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Webhook에 대한 설명: {0}",
|
||||||
|
aboutChannelName: "Webhook 채널을 우회하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널",
|
||||||
|
aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Project Github 페이지로 설정해요.",
|
||||||
|
emojiCheatSheet: "이모지 목록 시트: {0}",
|
||||||
"rocket.chat": "Rocket.chat",
|
"rocket.chat": "Rocket.chat",
|
||||||
pushover: "Pushover",
|
pushover: "Pushover",
|
||||||
pushy: "Pushy",
|
pushy: "Pushy",
|
||||||
octopush: "Octopush",
|
octopush: "Octopush",
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
lunasea: "LunaSea",
|
lunasea: "LunaSea",
|
||||||
apprise: "Apprise (50개 이상 알림 서비스 )",
|
apprise: "Apprise (50개 이상 알림 서비스)",
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
"User Key": "사용자 키",
|
||||||
|
Device: "장치",
|
||||||
|
"Message Title": "메시지 제목",
|
||||||
|
"Notification Sound": "알림음",
|
||||||
|
"More info on:": "자세한 정보: {0}",
|
||||||
|
pushoverDesc1: "긴급 우선 순위 (2)는 재시도 사이에 기본적으로 30초의 타임아웃이 있고, 1시간 후에 만료돼요.",
|
||||||
|
pushoverDesc2: "다른 장치에 알림을 보내려면 장치칸을 입력해주세요.",
|
||||||
|
"SMS Type": "SMS 종류",
|
||||||
|
octopushTypePremium: "프리미엄 (빠름) - 알림 기능에 적합해요)",
|
||||||
|
octopushTypeLowCost: "저렴한 요금 (느림) - 가끔 차단될 수 있어요)",
|
||||||
|
"Check octopush prices": "{0}에서 Octopush 가격을 확인할 수 있어요.",
|
||||||
|
octopushPhoneNumber: "휴대전화 번호 (intl format, eg : +33612345678) ",
|
||||||
|
octopushSMSSender: "보내는 사람 이름 : 3-11개의 영숫자 및 여백공간 (a-z, A-Z, 0-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": "Messaging API 메뉴",
|
||||||
|
wayToGetLineChannelToken: "먼저 {0}에 액세스하고, 공급자 및 채널 (Messaging API)을 만든 다음, 각 메뉴 밑에 언급된 메뉴에서 채널 액세스 토큰과 사용자 ID를 얻을 수 있어요.",
|
||||||
|
"Icon URL": "아이콘 URL",
|
||||||
|
aboutIconURL: "\"Icon URL\"에 사진 링크를 입력해 프로필 사진을 설정할 수 있어요. 아이콘 이모지가 설정되어 있으면 적용되지 않을 거예요.",
|
||||||
|
aboutMattermostChannelName: "채널 이름을 입력하면 Webhook이 게시할 기본 채널을 재설정할 수 있어요. 이 설정은 Mattermost 웹훅 설정에서 활성화해야 해요. 예: #기타-채널",
|
||||||
|
matrix: "매트릭스",
|
||||||
|
promosmsTypeEco: "SMS ECO - 저렴하지만 느리고 가끔 과부하에 걸려요. 폴란드 수신자만 사용할 수 있어요. ",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - 메시지가 받는 사람 장치에 자동으로 표시돼요. 폴란드 수신자만 사용할 수 있어요.",
|
||||||
|
promosmsTypeFull: "SMS FULL - SMS 프리미엄 티어, 보내는 사람 이름을 먼저 등록해야 해요. 알림 기능에 적합해요.",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - 시스템에서 가장 높은 우선순위예요. 매우 빠르고 신뢰할 수 있지만 비용이 많이 들어요 (SMS 전체 가격의 약 두 배).",
|
||||||
|
promosmsPhoneNumber: "전화 번호 (폴란드 수신자라면 지역번호를 적지 않아도 돼요.)",
|
||||||
|
promosmsSMSSender: "SMS 보내는 사람 이름 : 미리 등록된 이름 혹은 기본값 중 하나예요: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
};
|
};
|
||||||
|
282
src/languages/nb-NO.js
Normal file
282
src/languages/nb-NO.js
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Norsk",
|
||||||
|
checkEverySecond: "Sjekk hvert {0} sekund.",
|
||||||
|
retryCheckEverySecond: "Prøv igjen hvert {0} sekund.",
|
||||||
|
retriesDescription: "Maksimalt antall forsøk før tjenesten er merket som nede og et varsel sendes",
|
||||||
|
ignoreTLSError: "Ignorer TLS/SSL-feil for HTTPS-nettsteder",
|
||||||
|
upsideDownModeDescription: "Snu statusen opp ned. Hvis tjenesten er tilgjengelig, er den NED.",
|
||||||
|
maxRedirectDescription: "Maksimalt antall viderekoblinger å følge. Sett til 0 for å deaktivere viderekoblinger.",
|
||||||
|
acceptedStatusCodesDescription: "Velg statuskoder som anses som et vellykket svar.",
|
||||||
|
passwordNotMatchMsg: "Passordene stemmer ikke overens.",
|
||||||
|
notificationDescription: "Tilordne et varsel for å overvåkningen for å få det til å fungere.",
|
||||||
|
keywordDescription: "Søk etter nøkkelord i vanlig HTML eller JSON, og det er versalfølsom",
|
||||||
|
pauseDashboardHome: "Pause",
|
||||||
|
deleteMonitorMsg: "Er du sikker på at du vil slette denne overvåkningen?",
|
||||||
|
deleteNotificationMsg: "Er du sikker på at du vil slette dette varselet for alle overvåkningene?",
|
||||||
|
resoverserverDescription: "Cloudflare er standardserveren, kan du når som helst endre DNS-serveren.",
|
||||||
|
rrtypeDescription: "Velg RR-typen du vil overvåke",
|
||||||
|
pauseMonitorMsg: "Er du sikker på at du vil sette en pause?",
|
||||||
|
enableDefaultNotificationDescription: "For hver ny overvåkning vil denne varslingen være aktivert som standard. Du kan fortsatt deaktivere varselet separat for hver overvåkning.",
|
||||||
|
clearEventsMsg: "Er du sikker på at du vil slette alle hendelser for denne overvåkningen?",
|
||||||
|
clearHeartbeatsMsg: "Er du sikker på at du vil slette alle hjerteslag for denne overvåkningen?",
|
||||||
|
confirmClearStatisticsMsg: "Er du sikker på at du vil slette ALL statistikk?",
|
||||||
|
importHandleDescription: "Velg 'Hopp over eksisterende' hvis du vil hoppe over hver overvåkning eller varsel med samme navn. 'Overskriv' sletter alle eksisterende overvåkninger og varsler.",
|
||||||
|
confirmImportMsg: "Er du sikker på å importere sikkerhetskopien? Sørg for at du har valgt riktig importalternativ.",
|
||||||
|
twoFAVerifyLabel: "Skriv inn tokenet ditt for å bekrefte at 2FA fungerer",
|
||||||
|
tokenValidSettingsMsg: "Token er gyldig! Du kan nå lagre 2FA-innstillingene.",
|
||||||
|
confirmEnableTwoFAMsg: "Er du sikker på at du vil aktivere 2FA?",
|
||||||
|
confirmDisableTwoFAMsg: "Er du sikker på at du vil deaktivere 2FA?",
|
||||||
|
Settings: "Innstillinger",
|
||||||
|
Dashboard: "Dashboard",
|
||||||
|
"New Update": "Ny Oppdatering",
|
||||||
|
Language: "Språk",
|
||||||
|
Appearance: "Utseende",
|
||||||
|
Theme: "Tema",
|
||||||
|
General: "Generelt",
|
||||||
|
Version: "Versjon",
|
||||||
|
"Check Update On GitHub": "Sjekk oppdatering på GitHub",
|
||||||
|
List: "Liste",
|
||||||
|
Add: "Legg til",
|
||||||
|
"Add New Monitor": "Legg til ny overvåkning",
|
||||||
|
"Quick Stats": "Statistikk",
|
||||||
|
Up: "Oppe",
|
||||||
|
Down: "Nede",
|
||||||
|
Pending: "Avventer",
|
||||||
|
Unknown: "Ukjent",
|
||||||
|
Pause: "Pause",
|
||||||
|
Name: "Navn",
|
||||||
|
Status: "Status",
|
||||||
|
DateTime: "Dato tid",
|
||||||
|
Message: "Melding",
|
||||||
|
"No important events": "Ingen viktige hendelser",
|
||||||
|
Resume: "Fortsett",
|
||||||
|
Edit: "Endre",
|
||||||
|
Delete: "Slett",
|
||||||
|
Current: "Nåværende",
|
||||||
|
Uptime: "Oppetid",
|
||||||
|
"Cert Exp.": "Sertifikat utløper",
|
||||||
|
days: "dager",
|
||||||
|
day: "dag",
|
||||||
|
"-day": "-dag",
|
||||||
|
hour: "time",
|
||||||
|
"-hour": "-time",
|
||||||
|
Response: "Respons",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Overvåkningstype",
|
||||||
|
Keyword: "Stikkord",
|
||||||
|
"Friendly Name": "Vennlig navn",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Vertsnavn",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Hjerteslagsintervall",
|
||||||
|
Retries: "Forsøk",
|
||||||
|
"Heartbeat Retry Interval": "Hjerteslagsforsøkintervall",
|
||||||
|
Advanced: "Avansert",
|
||||||
|
"Upside Down Mode": "Opp-ned-modus",
|
||||||
|
"Max. Redirects": "Maks. viderekoblinger",
|
||||||
|
"Accepted Status Codes": "Godkjente statuskoder",
|
||||||
|
Save: "Lagre",
|
||||||
|
Notifications: "Varsler",
|
||||||
|
"Not available, please setup.": "Ikke tilgjengelig, sett opp.",
|
||||||
|
"Setup Notification": "Sett opp varsel",
|
||||||
|
Light: "Lys",
|
||||||
|
Dark: "Mørk",
|
||||||
|
Auto: "Auto",
|
||||||
|
"Theme - Heartbeat Bar": "Theme - Heartbeat Bar",
|
||||||
|
Normal: "Normal",
|
||||||
|
Bottom: "Bunn",
|
||||||
|
None: "Ingen",
|
||||||
|
Timezone: "Tidssone",
|
||||||
|
"Search Engine Visibility": "Søkemotor synlighet",
|
||||||
|
"Allow indexing": "Tillat indeksering",
|
||||||
|
"Discourage search engines from indexing site": "Avskrekk søkemotorer fra å indeksere nettstedet",
|
||||||
|
"Change Password": "Endre passord",
|
||||||
|
"Current Password": "Nåværende passord",
|
||||||
|
"New Password": "Nytt passord",
|
||||||
|
"Repeat New Password": "Gjenta nytt passord",
|
||||||
|
"Update Password": "Oppdater passord",
|
||||||
|
"Disable Auth": "Deaktiver autentisering",
|
||||||
|
"Enable Auth": "Aktiver autentisering",
|
||||||
|
Logout: "Logg ut",
|
||||||
|
Leave: "Forlat",
|
||||||
|
"I understand, please disable": "Jeg forstår, deaktiver",
|
||||||
|
Confirm: "Bekreft",
|
||||||
|
Yes: "Ja",
|
||||||
|
No: "Nei",
|
||||||
|
Username: "Brukernavn",
|
||||||
|
Password: "Passord",
|
||||||
|
"Remember me": "Husk meg",
|
||||||
|
Login: "Logg inn",
|
||||||
|
"No Monitors, please": "Ingen overvåkning, vær så snill",
|
||||||
|
"add one": "legg til en",
|
||||||
|
"Notification Type": "Meldingstype",
|
||||||
|
Email: "E-post",
|
||||||
|
Test: "Test",
|
||||||
|
"Certificate Info": "Sertifikatinformasjon",
|
||||||
|
"Resolver Server": "DNS-server",
|
||||||
|
"Resource Record Type": "DNS-posttype",
|
||||||
|
"Last Result": "Siste resultat",
|
||||||
|
"Create your admin account": "Opprett en administratorkonto",
|
||||||
|
"Repeat Password": "Gjenta passord",
|
||||||
|
"Import Backup": "Importer sikkerhetskopi",
|
||||||
|
"Export Backup": "Eksporter sikkerhetskopi",
|
||||||
|
Export: "Eksporter",
|
||||||
|
Import: "Importer",
|
||||||
|
respTime: "Svartid (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "Standard aktivert",
|
||||||
|
"Apply on all existing monitors": "Påfør på alle eksisterende overvåkninger",
|
||||||
|
Create: "Opprett",
|
||||||
|
"Clear Data": "Slett data",
|
||||||
|
Events: "Hendelser",
|
||||||
|
Heartbeats: "Hjerteslag",
|
||||||
|
"Auto Get": "Auto Get",
|
||||||
|
backupDescription: "Du kan sikkerhetskopiere alle overvåkninger og alle varsler til en JSON-fil.",
|
||||||
|
backupDescription2: "PS: Historikk og hendelsesdata er ikke inkludert.",
|
||||||
|
backupDescription3: "Følsomme data som varslingstokener er inkludert i eksportfilen. Vennligst oppbevar dem nøye.",
|
||||||
|
alertNoFile: "Velg en fil som skal importeres.",
|
||||||
|
alertWrongFileType: "Velg en JSON-fil.",
|
||||||
|
"Clear all statistics": "Fjern all statistikk",
|
||||||
|
"Skip existing": "Hopp over eksisterende",
|
||||||
|
Overwrite: "Overskriv",
|
||||||
|
Options: "Alternativer",
|
||||||
|
"Keep both": "Behold begge",
|
||||||
|
"Verify Token": "Bekreft token",
|
||||||
|
"Setup 2FA": "Konfigurer 2FA",
|
||||||
|
"Enable 2FA": "Aktiver 2FA",
|
||||||
|
"Disable 2FA": "Deaktiver 2FA",
|
||||||
|
"2FA Settings": "2FA Innstillinger",
|
||||||
|
"Two Factor Authentication": "To-faktor autentisering",
|
||||||
|
Active: "Aktiv",
|
||||||
|
Inactive: "Inaktiv",
|
||||||
|
Token: "Token",
|
||||||
|
"Show URI": "Vis URI",
|
||||||
|
Tags: "Etiketter",
|
||||||
|
"Add New below or Select...": "Legg til nytt nedenfor eller Velg ...",
|
||||||
|
"Tag with this name already exist.": "Etikett med dette navnet eksisterer allerede.",
|
||||||
|
"Tag with this value already exist.": "Etikett med denne verdien finnes allerede.",
|
||||||
|
color: "farge",
|
||||||
|
"value (optional)": "verdi (valgfritt)",
|
||||||
|
Gray: "Grå",
|
||||||
|
Red: "Rød",
|
||||||
|
Orange: "Oransje",
|
||||||
|
Green: "Grønn",
|
||||||
|
Blue: "Blå",
|
||||||
|
Indigo: "Indigo",
|
||||||
|
Purple: "Lilla",
|
||||||
|
Pink: "Rosa",
|
||||||
|
"Search...": "Søk...",
|
||||||
|
"Avg. Ping": "Gj.sn. Ping",
|
||||||
|
"Avg. Response": "Gj.sn. Respons",
|
||||||
|
"Entry Page": "Oppføringsside",
|
||||||
|
statusPageNothing: "Ingenting her, vennligst legg til en gruppe eller en overvåkning.",
|
||||||
|
"No Services": "Ingen tjenester",
|
||||||
|
"All Systems Operational": "Alle systemer i drift",
|
||||||
|
"Partially Degraded Service": "Delvis degradert drift",
|
||||||
|
"Degraded Service": "Degradert drift",
|
||||||
|
"Add Group": "Legg til gruppe",
|
||||||
|
"Add a monitor": "Legg til en overvåkning",
|
||||||
|
"Edit Status Page": "Rediger statusside",
|
||||||
|
"Go to Dashboard": "Gå til Dashboard",
|
||||||
|
"Status Page": "Statusside",
|
||||||
|
defaultNotificationName: "Min {notification} varsling ({number})",
|
||||||
|
here: "here",
|
||||||
|
Required: "Obligatorisk",
|
||||||
|
telegram: "Telegram",
|
||||||
|
"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å chat-ID-en din ved å sende meldingen til boten og gå til denne nettadressen for å se chat_id:",
|
||||||
|
"YOUR BOT TOKEN HERE": "DITT BOT TOKEN HER",
|
||||||
|
chatIDNotFound: "Chat-ID ble ikke funnet. Send en melding til denne boten først",
|
||||||
|
webhook: "Webhook",
|
||||||
|
"Post URL": "Post URL",
|
||||||
|
"Content Type": "Content Type",
|
||||||
|
webhookJsonDesc: "{0} er bra for alle moderne HTTP-servere som express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} er bra for PHP, du trenger bare å analysere JSON etter {decodeFunction}",
|
||||||
|
smtp: "E-post (SMTP)",
|
||||||
|
secureOptionNone: "None / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "Ignorer TLS feilmelding",
|
||||||
|
"From Email": "Fra E-post",
|
||||||
|
"To Email": "Til E-post",
|
||||||
|
smtpCC: "CC",
|
||||||
|
smtpBCC: "BCC",
|
||||||
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "Du kan få dette ved å gå til Serverinnstillinger -> Integrasjoner -> Webhooks -> Ny webhook",
|
||||||
|
"Bot Display Name": "Bot Visningsnavn",
|
||||||
|
"Prefix Custom Message": "Prefiks tilpasset melding",
|
||||||
|
"Hello @everyone is...": "Hei {'@'}everyone det er...",
|
||||||
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "Webhook URL",
|
||||||
|
wayToGetTeamsURL: "Du kan lære hvordan du oppretter en webhook-URL {0}.",
|
||||||
|
signal: "Signal",
|
||||||
|
Number: "Nummer",
|
||||||
|
Recipients: "Mottakere",
|
||||||
|
needSignalAPI: "Du må ha en Signal-klient med REST API.",
|
||||||
|
wayToCheckSignalURL: "Du kan sjekke denne nettadressen for å se hvordan du konfigurerer en:",
|
||||||
|
signalImportant: "VIKTIG: Du kan ikke blande grupper og nummere i mottakere!",
|
||||||
|
gotify: "Gotify",
|
||||||
|
"Application Token": "Application Token",
|
||||||
|
"Server URL": "Server URL",
|
||||||
|
Priority: "Prioritet",
|
||||||
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "Icon Emoji",
|
||||||
|
"Channel Name": "Kanal navn",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Mer informasjon om webhooks på: {0}",
|
||||||
|
aboutChannelName: "Skriv inn kanalnavnet på {0} Kanalnavn-feltet hvis du vil omgå webhook-kanalen. Eks: #other-channel",
|
||||||
|
aboutKumaURL: "Hvis du lar Uptime Kuma URL feltet være blank, den blir som standard til Github-siden for dette prosjektet.",
|
||||||
|
emojiCheatSheet: "Emoji cheat sheet: {0}",
|
||||||
|
"rocket.chat": "Rocket.chat",
|
||||||
|
pushover: "Pushover",
|
||||||
|
pushy: "Pushy",
|
||||||
|
octopush: "Octopush",
|
||||||
|
promosms: "PromoSMS",
|
||||||
|
lunasea: "LunaSea",
|
||||||
|
apprise: "Apprise (Support 50+ Notification services)",
|
||||||
|
pushbullet: "Pushbullet",
|
||||||
|
line: "Line Messenger",
|
||||||
|
mattermost: "Mattermost",
|
||||||
|
"User Key": "User Key",
|
||||||
|
Device: "Device",
|
||||||
|
"Message Title": "Message Title",
|
||||||
|
"Notification Sound": "Notification Sound",
|
||||||
|
"More info on:": "More info on: {0}",
|
||||||
|
pushoverDesc1: "Emergency priority (2) has default 30 second timeout between retries and will expire after 1 hour.",
|
||||||
|
pushoverDesc2: "If you want to send notifications to different devices, fill out Device field.",
|
||||||
|
"SMS Type": "SMS Type",
|
||||||
|
octopushTypePremium: "Premium (Fast - recommended for alerting)",
|
||||||
|
octopushTypeLowCost: "Low Cost (Slow, sometimes blocked by operator)",
|
||||||
|
"Check octopush prices": "Check octopush prices {0}.",
|
||||||
|
octopushPhoneNumber: "Phone number (intl format, eg : +33612345678) ",
|
||||||
|
octopushSMSSender: "SMS Sender Name : 3-11 alphanumeric characters and space (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "LunaSea Device ID",
|
||||||
|
"Apprise URL": "Apprise URL",
|
||||||
|
"Example:": "Example: {0}",
|
||||||
|
"Read more:": "Read more: {0}",
|
||||||
|
"Status:": "Status: {0}",
|
||||||
|
"Read more": "Read more",
|
||||||
|
appriseInstalled: "Apprise is installed.",
|
||||||
|
appriseNotInstalled: "Apprise is not installed. {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: "First access the {0}, create a provider and channel (Messaging API), then you can get the channel access token and user id from the above mentioned menu items.",
|
||||||
|
"Icon URL": "Icon URL",
|
||||||
|
aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.",
|
||||||
|
aboutMattermostChannelName: "You can override the default channel that webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in Mattermost webhook settings. Ex: #other-channel",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO - cheap but slow and often overloaded. Limited only to Polish recipients.",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - Message will automatically show on recipient device. Limited only to Polish recipients.",
|
||||||
|
promosmsTypeFull: "SMS FULL - Premium tier of SMS, You can use Your Sender Name (You need to register name first). Reliable for alerts.",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - Highest priority in system. Very quick and reliable but costly (about twice of SMS FULL price).",
|
||||||
|
promosmsPhoneNumber: "Phone number (for Polish recipient You can skip area codes)",
|
||||||
|
promosmsSMSSender: "SMS Sender Name : Pre-registred name or one of defaults: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
|
};
|
@@ -198,4 +198,10 @@ export default {
|
|||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
Method: "Methode",
|
||||||
|
Body: "Body",
|
||||||
|
Headers: "Headers",
|
||||||
|
PushUrl: "Push URL",
|
||||||
|
HeadersInvalidFormat: "The request headers is geen geldige JSON: ",
|
||||||
|
BodyInvalidFormat: "De request body is geen geldige JSON: ",
|
||||||
};
|
};
|
||||||
|
@@ -10,7 +10,7 @@ export default {
|
|||||||
passwordNotMatchMsg: "Powtórzone hasło nie pasuje.",
|
passwordNotMatchMsg: "Powtórzone hasło nie pasuje.",
|
||||||
notificationDescription: "Proszę przypisać powiadomienie do monitora(ów), aby działało.",
|
notificationDescription: "Proszę przypisać powiadomienie do monitora(ów), aby działało.",
|
||||||
keywordDescription: "Wyszukiwanie słów kluczowych w zwykłym html lub odpowiedzi JSON. Wielkość liter ma znaczenie.",
|
keywordDescription: "Wyszukiwanie słów kluczowych w zwykłym html lub odpowiedzi JSON. Wielkość liter ma znaczenie.",
|
||||||
pauseDashboardHome: "Wstrzymaj",
|
pauseDashboardHome: "Wstrzymane",
|
||||||
deleteMonitorMsg: "Czy na pewno chcesz usunąć ten monitor?",
|
deleteMonitorMsg: "Czy na pewno chcesz usunąć ten monitor?",
|
||||||
deleteNotificationMsg: "Czy na pewno chcesz usunąć to powiadomienie dla wszystkich monitorów?",
|
deleteNotificationMsg: "Czy na pewno chcesz usunąć to powiadomienie dla wszystkich monitorów?",
|
||||||
resoverserverDescription: "Cloudflare jest domyślnym serwerem, możesz zmienić serwer resolver w każdej chwili.",
|
resoverserverDescription: "Cloudflare jest domyślnym serwerem, możesz zmienić serwer resolver w każdej chwili.",
|
||||||
@@ -28,7 +28,7 @@ export default {
|
|||||||
confirmDisableTwoFAMsg: "Jesteś pewien, że chcesz wyłączyć 2FA?",
|
confirmDisableTwoFAMsg: "Jesteś pewien, że chcesz wyłączyć 2FA?",
|
||||||
Settings: "Ustawienia",
|
Settings: "Ustawienia",
|
||||||
Dashboard: "Panel",
|
Dashboard: "Panel",
|
||||||
"New Update": "Nowa Aktualizacja",
|
"New Update": "Nowa aktualizacja",
|
||||||
Language: "Język",
|
Language: "Język",
|
||||||
Appearance: "Wygląd",
|
Appearance: "Wygląd",
|
||||||
Theme: "Motyw",
|
Theme: "Motyw",
|
||||||
@@ -37,13 +37,13 @@ export default {
|
|||||||
"Check Update On GitHub": "Sprawdź aktualizację na GitHub",
|
"Check Update On GitHub": "Sprawdź aktualizację na GitHub",
|
||||||
List: "Lista",
|
List: "Lista",
|
||||||
Add: "Dodaj",
|
Add: "Dodaj",
|
||||||
"Add New Monitor": "Dodaj Monitor",
|
"Add New Monitor": "Dodaj monitor",
|
||||||
"Quick Stats": "Szybki podgląd statystyk",
|
"Quick Stats": "Szybki podgląd statystyk",
|
||||||
Up: "Online",
|
Up: "Online",
|
||||||
Down: "Offline",
|
Down: "Offline",
|
||||||
Pending: "Oczekuje",
|
Pending: "Oczekuje",
|
||||||
Unknown: "Nieznane",
|
Unknown: "Nieznane",
|
||||||
Pause: "Wstrzymane",
|
Pause: "Wstrzymaj",
|
||||||
Name: "Nazwa",
|
Name: "Nazwa",
|
||||||
Status: "Status",
|
Status: "Status",
|
||||||
DateTime: "Data i godzina",
|
DateTime: "Data i godzina",
|
||||||
@@ -53,8 +53,8 @@ export default {
|
|||||||
Edit: "Edytuj",
|
Edit: "Edytuj",
|
||||||
Delete: "Usuń",
|
Delete: "Usuń",
|
||||||
Current: "Aktualny",
|
Current: "Aktualny",
|
||||||
Uptime: "Czas Pracy",
|
Uptime: "Czas pracy",
|
||||||
"Cert Exp.": "Certyfikat Wygasa",
|
"Cert Exp.": "Certyfikat wygasa",
|
||||||
days: "dni",
|
days: "dni",
|
||||||
day: "dzień",
|
day: "dzień",
|
||||||
"-day": " dni",
|
"-day": " dni",
|
||||||
@@ -62,9 +62,9 @@ export default {
|
|||||||
"-hour": " godzin",
|
"-hour": " godzin",
|
||||||
Response: "Odpowiedź",
|
Response: "Odpowiedź",
|
||||||
Ping: "Ping",
|
Ping: "Ping",
|
||||||
"Monitor Type": "Rodzaj Monitora",
|
"Monitor Type": "Rodzaj monitora",
|
||||||
Keyword: "Słowo kluczowe",
|
Keyword: "Słowo kluczowe",
|
||||||
"Friendly Name": "Przyjazna Nazwa",
|
"Friendly Name": "Przyjazna nazwa",
|
||||||
URL: "URL",
|
URL: "URL",
|
||||||
Hostname: "Hostname",
|
Hostname: "Hostname",
|
||||||
Port: "Port",
|
Port: "Port",
|
||||||
@@ -73,12 +73,12 @@ export default {
|
|||||||
"Heartbeat Retry Interval": "Częstotliwość ponawiania bicia serca",
|
"Heartbeat Retry Interval": "Częstotliwość ponawiania bicia serca",
|
||||||
Advanced: "Zaawansowane",
|
Advanced: "Zaawansowane",
|
||||||
"Upside Down Mode": "Tryb odwrócony",
|
"Upside Down Mode": "Tryb odwrócony",
|
||||||
"Max. Redirects": "Maks. Przekierowań",
|
"Max. Redirects": "Maks. przekierowań",
|
||||||
"Accepted Status Codes": "Akceptowane kody statusu",
|
"Accepted Status Codes": "Akceptowane kody statusu",
|
||||||
Save: "Zapisz",
|
Save: "Zapisz",
|
||||||
Notifications: "Powiadomienia",
|
Notifications: "Powiadomienia",
|
||||||
"Not available, please setup.": "Niedostępne, proszę skonfigurować.",
|
"Not available, please setup.": "Niedostępne, proszę skonfigurować.",
|
||||||
"Setup Notification": "Skonfiguruj Powiadomienie",
|
"Setup Notification": "Skonfiguruj powiadomienie",
|
||||||
Light: "Jasny",
|
Light: "Jasny",
|
||||||
Dark: "Ciemny",
|
Dark: "Ciemny",
|
||||||
Auto: "Automatyczny",
|
Auto: "Automatyczny",
|
||||||
@@ -100,7 +100,7 @@ export default {
|
|||||||
Logout: "Wyloguj",
|
Logout: "Wyloguj",
|
||||||
Leave: "Zostaw",
|
Leave: "Zostaw",
|
||||||
"I understand, please disable": "Rozumiem, proszę wyłączyć",
|
"I understand, please disable": "Rozumiem, proszę wyłączyć",
|
||||||
Confirm: "Potiwerdź",
|
Confirm: "Potwierdź",
|
||||||
Yes: "Tak",
|
Yes: "Tak",
|
||||||
No: "Nie",
|
No: "Nie",
|
||||||
Username: "Nazwa użytkownika",
|
Username: "Nazwa użytkownika",
|
||||||
@@ -118,16 +118,16 @@ export default {
|
|||||||
"Last Result": "Ostatni wynik",
|
"Last Result": "Ostatni wynik",
|
||||||
"Create your admin account": "Utwórz swoje konto administratora",
|
"Create your admin account": "Utwórz swoje konto administratora",
|
||||||
"Repeat Password": "Powtórz hasło",
|
"Repeat Password": "Powtórz hasło",
|
||||||
"Import Backup": "Importuj Kopię",
|
"Import Backup": "Importuj kopię zapasową",
|
||||||
"Export Backup": "Eksportuj Kopię",
|
"Export Backup": "Eksportuj kopię zapasową",
|
||||||
Export: "Eksportuj",
|
Export: "Eksportuj",
|
||||||
Import: "Importuj",
|
Import: "Importuj",
|
||||||
respTime: "Czas Odp. (ms)",
|
respTime: "Czas odp. (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
"Default enabled": "Włącz domyślnie",
|
"Default enabled": "Włącz domyślnie",
|
||||||
"Apply on all existing monitors": "Zastosuj do istniejących monitorów",
|
"Apply on all existing monitors": "Zastosuj do istniejących monitorów",
|
||||||
Create: "Stwórz",
|
Create: "Stwórz",
|
||||||
"Clear Data": "Usuń Dane",
|
"Clear Data": "Usuń dane",
|
||||||
Events: "Wydarzenia",
|
Events: "Wydarzenia",
|
||||||
Heartbeats: "Bicia serca",
|
Heartbeats: "Bicia serca",
|
||||||
"Auto Get": "Wykryj",
|
"Auto Get": "Wykryj",
|
||||||
@@ -179,106 +179,132 @@ export default {
|
|||||||
"Edit Status Page": "Edytuj stronę statusu",
|
"Edit Status Page": "Edytuj stronę statusu",
|
||||||
"Go to Dashboard": "Idź do panelu",
|
"Go to Dashboard": "Idź do panelu",
|
||||||
"Status Page": "Strona statusu",
|
"Status Page": "Strona statusu",
|
||||||
// Start notification form
|
|
||||||
defaultNotificationName: "Moje powiadomienie {notification} ({number})",
|
defaultNotificationName: "Moje powiadomienie {notification} ({number})",
|
||||||
here: "tutaj",
|
here: "tutaj",
|
||||||
"Required": "Wymagane",
|
Required: "Wymagane",
|
||||||
"telegram": "Telegram",
|
telegram: "Telegram",
|
||||||
"Bot Token": "Token Bota",
|
"Bot Token": "Token bota",
|
||||||
"You can get a token from": "Token można uzyskać z",
|
wayToGetTelegramToken: "Token można uzyskać z {0}.",
|
||||||
"Chat ID": "Identyfikator Czatu",
|
"Chat ID": "Identyfikator czatu",
|
||||||
supportTelegramChatID: "Czat wsprarcia technicznego / Bezpośrednia Rozmowa / Czat Grupowy",
|
supportTelegramChatID: "Czat wsparcia technicznego / Bezpośrednia rozmowa / Czat grupowy",
|
||||||
wayToGetTelegramChatID: "Możesz uzyskać swój identyfikator czatu, wysyłając wiadomość do bota i przechodząc pod ten adres URL, aby wyświetlić identyfikator czatu:",
|
wayToGetTelegramChatID: "Możesz uzyskać swój identyfikator czatu, wysyłając wiadomość do bota i przechodząc pod ten adres URL, aby wyświetlić identyfikator czatu:",
|
||||||
"YOUR BOT TOKEN HERE": "TWOJ TOKEN BOTA",
|
"YOUR BOT TOKEN HERE": "TWOJ TOKEN BOTA",
|
||||||
chatIDNotFound: "Identyfikator czatu nie znaleziony, najpierw napisz do bota",
|
chatIDNotFound: "Identyfikator czatu nie znaleziony, najpierw napisz do bota",
|
||||||
"webhook": "Webhook",
|
webhook: "Webhook",
|
||||||
"Post URL": "Adres URL",
|
"Post URL": "Adres URL",
|
||||||
"Content Type": "Rodzaj danych",
|
"Content Type": "Rodzaj danych",
|
||||||
webhookJsonDesc: "{0} jest dobry w przypadku serwerów HTTP, takich jak express.js",
|
webhookJsonDesc: "{0} jest dobry w przypadku serwerów HTTP, takich jak express.js",
|
||||||
webhookFormDataDesc: "{multipart} jest dobry dla PHP, musisz jedynie przetowrzyć dane przez {decodeFunction}",
|
webhookFormDataDesc: "{multipart} jest dobry dla PHP, musisz jedynie przetowrzyć dane przez {decodeFunction}",
|
||||||
"smtp": "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
secureOptionNone: "Brak / STARTTLS (25, 587)",
|
secureOptionNone: "Brak / STARTTLS (25, 587)",
|
||||||
secureOptionTLS: "TLS (465)",
|
secureOptionTLS: "TLS (465)",
|
||||||
"Ignore TLS Error": "Zignrouj Błędy TLS",
|
"Ignore TLS Error": "Zignoruj błędy TLS",
|
||||||
"From Email": "Nadawca (OD)",
|
"From Email": "Nadawca (OD)",
|
||||||
"To Email": "Odbiorca (DO)",
|
"To Email": "Odbiorca (DO)",
|
||||||
smtpCC: "DW",
|
smtpCC: "DW",
|
||||||
smtpBCC: "UDW",
|
smtpBCC: "UDW",
|
||||||
"discord": "Discord",
|
discord: "Discord",
|
||||||
"Discord Webhook URL": "URL Webhook Discorda",
|
"Discord Webhook URL": "URL webhook Discorda",
|
||||||
wayToGetDiscordURL: "Możesz go uzyskać przechodząc do Ustawienia Serwera -> Integracje -> Tworzenie Webhooka",
|
wayToGetDiscordURL: "Możesz go uzyskać przechodząc do Ustawienia serwera -> Integracje -> Tworzenie webhooka",
|
||||||
"Bot Display Name": "Wyświetlana Nazwa Bota",
|
"Bot Display Name": "Wyświetlana nazwa bota",
|
||||||
"Prefix Custom Message": "Własny Początek Wiadomości",
|
"Prefix Custom Message": "Własny początek wiadomości",
|
||||||
"Hello @everyone is...": "Hej {'@'}everyone ...",
|
"Hello @everyone is...": "Hej {'@'}everyone ...",
|
||||||
"teams": "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
"Webhook URL": "URL Webhooka",
|
"Webhook URL": "URL webhooka",
|
||||||
wayToGetTeamsURL: "You can learn how to create a webhook url {0}.",
|
wayToGetTeamsURL: "Możesz dowiedzieć się, jak utworzyć adres url webhooka {0}.",
|
||||||
"signal": "Signal",
|
signal: "Signal",
|
||||||
"Number": "Numer",
|
Number: "Numer",
|
||||||
"Recipients": "Odbiorcy",
|
Recipients: "Odbiorcy",
|
||||||
needSignalAPI: "Musisz posiadać klienta Signal z REST API.",
|
needSignalAPI: "Musisz posiadać klienta Signal z REST API.",
|
||||||
wayToCheckSignalURL: "W celu dowiedzenia się, jak go skonfigurować, odwiedź poniższy link:",
|
wayToCheckSignalURL: "W celu dowiedzenia się, jak go skonfigurować, odwiedź poniższy link:",
|
||||||
signalImportant: "UWAGA: Nie można mieszać nazw grup i numerów odbiorców!",
|
signalImportant: "UWAGA: Nie można mieszać nazw grup i numerów odbiorców!",
|
||||||
"gotify": "Gotify",
|
gotify: "Gotify",
|
||||||
"Application Token": "Token Aplikacji",
|
"Application Token": "Token aplikacji",
|
||||||
"Server URL": "Server URL",
|
"Server URL": "Server URL",
|
||||||
"Priority": "Priorytet",
|
Priority: "Priorytet",
|
||||||
"slack": "Slack",
|
slack: "Slack",
|
||||||
"Icon Emoji": "Ikona Emoji",
|
"Icon Emoji": "Ikona emoji",
|
||||||
"Channel Name": "Nazwa Kanału",
|
"Channel Name": "Nazwa kanału",
|
||||||
"Uptime Kuma URL": "Adres Uptime Kuma",
|
"Uptime Kuma URL": "Adres Uptime Kuma",
|
||||||
aboutWebhooks: "Więcej informacji na temat webhooków: {0}",
|
aboutWebhooks: "Więcej informacji na temat webhooków: {0}",
|
||||||
aboutChannelName: "Podaj nazwę kanału {0} w polu Nazwa Kanału, jeśli chcesz pominąć kanał webhooka. Np.: #inny-kanal",
|
aboutChannelName: "Podaj nazwę kanału {0} w polu Nazwa kanału, jeśli chcesz pominąć kanał webhooka. Np.: #inny-kanal",
|
||||||
aboutKumaURL: "Jeśli pozostawisz pole Adres Uptime Kuma puste, domyślnie będzie to strona projektu na Github.",
|
aboutKumaURL: "Jeśli pozostawisz pole Adres Uptime Kuma puste, domyślnie będzie to strona projektu na GitHub.",
|
||||||
emojiCheatSheet: "Ściąga Emoji: {0}",
|
emojiCheatSheet: "Ściąga emoji: {0}",
|
||||||
"rocket.chat": "Rocket.chat",
|
"rocket.chat": "Rocket.chat",
|
||||||
pushover: "Pushover",
|
pushover: "Pushover",
|
||||||
pushy: "Pushy",
|
pushy: "Pushy",
|
||||||
octopush: "Octopush",
|
octopush: "Octopush",
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
lunasea: "LunaSea",
|
lunasea: "LunaSea",
|
||||||
apprise: "Apprise (Obsługuje 50+ usług powiadomień)",
|
apprise: "Apprise (obsługuje 50+ usług powiadomień)",
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
"User Key": "Klucz Użytkownika",
|
"User Key": "Klucz użytkownika",
|
||||||
"Device": "Urządzenie",
|
Device: "Urządzenie",
|
||||||
"Message Title": "Tytuł Wiadomości",
|
"Message Title": "Tytuł wiadomości",
|
||||||
"Notification Sound": "Dźwięk Powiadomienia",
|
"Notification Sound": "Dźwięk powiadomienia",
|
||||||
"More info on:": "Więcej informacji na: {0}",
|
"More info on:": "Więcej informacji na: {0}",
|
||||||
pushoverDesc1: "Priorytet awaryjny (2) ma domyślny 30-sekundowy limit czasu między kolejnymi próbami i wygaśnie po 1 godzinie.",
|
pushoverDesc1: "Priorytet awaryjny (2) ma domyślny 30-sekundowy limit czasu między kolejnymi próbami i wygaśnie po 1 godzinie.",
|
||||||
pushoverDesc2: "Jeśli chcesz wysyłać powiadomienia na różne urządzenia, wypełnij pole Urządzenie.",
|
pushoverDesc2: "Jeśli chcesz wysyłać powiadomienia na różne urządzenia, wypełnij pole Urządzenie.",
|
||||||
"SMS Type": "Rodzaj SMS",
|
"SMS Type": "Rodzaj SMS",
|
||||||
octopushTypePremium: "Premium (Szybki - rekomendowany dla powiadomień)",
|
octopushTypePremium: "Premium (szybki - rekomendowany dla powiadomień)",
|
||||||
octopushTypeLowCost: "Low Cost (Wolny, czasami blokowany przez operatorów)",
|
octopushTypeLowCost: "Low Cost (wolny, czasami blokowany przez operatorów)",
|
||||||
"Check octopush prices": "Sprawdź ceny Octopush {0}.",
|
"Check octopush prices": "Sprawdź ceny Octopush {0}.",
|
||||||
octopushPhoneNumber: "Numer Telefonu (Format międzynarodowy np.: +33612345678)",
|
octopushPhoneNumber: "Numer telefonu (format międzynarodowy np.: +33612345678)",
|
||||||
octopushSMSSender: "Nadawca SMS : 3-11 znaków alfanumerycznych i spacji (a-zA-Z0-9)",
|
octopushSMSSender: "Nadawca SMS: 3-11 znaków alfanumerycznych i spacji (a-zA-Z0-9)",
|
||||||
"LunaSea Device ID": "Idetyfikator Urządzenia LunaSea",
|
"LunaSea Device ID": "Identyfikator urządzenia LunaSea",
|
||||||
"Apprise URL": "URL Apprise",
|
"Apprise URL": "URL Apprise",
|
||||||
"Example:": "Przykład: {0}",
|
"Example:": "Przykład: {0}",
|
||||||
"Read more:": "Czytaj Dalej: {0}",
|
"Read more:": "Czytaj dalej: {0}",
|
||||||
"Status:": "Status: {0}",
|
"Status:": "Status: {0}",
|
||||||
"Read more": "Czytaj dalej",
|
"Read more": "Czytaj dalej",
|
||||||
appriseInstalled: "Apprise jest zostało zainstalowane.",
|
appriseInstalled: "Apprise jest zostało zainstalowane.",
|
||||||
appriseNotInstalled: "Apprise nie zostało zainstalowane. {0}",
|
appriseNotInstalled: "Apprise nie zostało zainstalowane. {0}",
|
||||||
"Access Token": "Token Dostępu",
|
"Access Token": "Token dostępu",
|
||||||
"Channel access token": "Token Dostępu Kanału",
|
"Channel access token": "Token dostępu kanału",
|
||||||
"Line Developers Console": "Konsola Dewelopersja Line",
|
"Line Developers Console": "Konsola deweloperska Line",
|
||||||
lineDevConsoleTo: "Konsola Dewelopersja Line - {0}",
|
lineDevConsoleTo: "Konsola deweloperska Line - {0}",
|
||||||
"Basic Settings": "Ustawienia Ogólne",
|
"Basic Settings": "Ustawienia ogólne",
|
||||||
"User ID": "Idetyfikator Użytkownika",
|
"User ID": "Identyfikator użytkownika",
|
||||||
"Messaging API": "API Wiadomości",
|
"Messaging API": "API wiadomości",
|
||||||
wayToGetLineChannelToken: "Najpierw uzyskaj dostęp do {0}, utwórz dostawcę i kanał (Messaging API), a następnie możesz uzyskać token dostępu do kanału i identyfikator użytkownika z wyżej wymienionych pozycji menu.",
|
wayToGetLineChannelToken: "Najpierw uzyskaj dostęp do {0}, utwórz dostawcę i kanał (Messaging API), a następnie możesz uzyskać token dostępu do kanału i identyfikator użytkownika z wyżej wymienionych pozycji menu.",
|
||||||
"Icon URL": "Adres Ikony",
|
"Icon URL": "Adres Ikony",
|
||||||
aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.",
|
aboutIconURL: "Możesz podać link do zdjęcia w \"Adres URL ikony\", aby zastąpić domyślne zdjęcie profilowe. Nie będzie używany, jeśli ustawiona jest ikona emoji.",
|
||||||
aboutMattermostChannelName: "You can override the default channel that webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in Mattermost webhook settings. Ex: #other-channel",
|
aboutMattermostChannelName: "Możesz zastąpić domyślny kanał, na którym publikowane są posty webhooka, wpisując nazwę kanału w polu \"Nazwa kanału\". Należy to włączyć w ustawieniach webhooka Mattermost. Np.: #inny-kanał",
|
||||||
"matrix": "Matrix",
|
matrix: "Matrix",
|
||||||
promosmsTypeEco: "SMS ECO - Tanie, lecz wolne. Dostępne tylko w Polsce",
|
promosmsTypeEco: "SMS ECO - tanie, lecz wolne. Dostępne tylko w Polsce",
|
||||||
promosmsTypeFlash: "SMS FLASH - Wiadomość automatycznie wyświetli się na urządzeniu. Dostępne tylko w Polsce.",
|
promosmsTypeFlash: "SMS FLASH - wiadomość automatycznie wyświetli się na urządzeniu. Dostępne tylko w Polsce.",
|
||||||
promosmsTypeFull: "SMS FULL - Szybkie i dostępne międzynarodowo. Wersja premium usługi, która pozwala min. ustawić własną nazwę nadawcy.",
|
promosmsTypeFull: "SMS FULL - szybkie i dostępne międzynarodowo. Wersja premium usługi, która pozwala min. ustawić własną nazwę nadawcy.",
|
||||||
promosmsTypeSpeed: "SMS SPEED - Wysyłka priorytetowa, posiada wszystkie zalety SMS FULL",
|
promosmsTypeSpeed: "SMS SPEED - wysyłka priorytetowa, posiada wszystkie zalety SMS FULL",
|
||||||
promosmsPhoneNumber: "Numer Odbiorcy",
|
promosmsPhoneNumber: "Numer odbiorcy",
|
||||||
promosmsSMSSender: "Nadawca SMS (Wcześniej zatwierdzone nazwy z panelu PromoSMS)",
|
promosmsSMSSender: "Nadawca SMS (wcześniej zatwierdzone nazwy z panelu PromoSMS)",
|
||||||
// End notification form
|
"Primary Base URL": "Główny URL",
|
||||||
|
"Push URL": "Push URL",
|
||||||
|
needPushEvery: "Powinieneś wywoływać ten URL co {0} sekund",
|
||||||
|
pushOptionalParams: "Parametry opcjonalne: {0}",
|
||||||
|
emailCustomSubject: "Niestandardowy temat",
|
||||||
|
checkPrice: "Sprawdź ceny {0}:",
|
||||||
|
octopushLegacyHint: "Czy używasz starszej wersji Octopush (2011-2020) czy nowej wersji?",
|
||||||
|
"Feishu WebHookUrl": "Feishu WebHookURL",
|
||||||
|
matrixHomeserverURL: "Adres URL serwera domowego (z http(s):// i opcjonalnie port)",
|
||||||
|
"Internal Room Id": "Wewnętrzne ID pokoju",
|
||||||
|
matrixDesc1: "Możesz znaleźć wewnętrzne ID pokoju patrząc w zaawansowanej sekcji ustawień pokoju w twoim kliencie Matrix. Powinien on wyglądać jak !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
|
matrixDesc2: "Jest wysoce zalecane, abyś stworzył nowego użytkownika i nie używał tokena dostępu swojego użytkownika Matrix, ponieważ pozwoli on na pełny dostęp do twojego konta i wszystkich pokoi, do których dołączyłeś. Zamiast tego, utwórz nowego użytkownika i zaproś go tylko do pokoju, w którym chcesz otrzymywać powiadomienia. Możesz uzyskać token dostępu przez uruchomienie {0}",
|
||||||
|
Method: "Metoda",
|
||||||
|
Body: "Treść",
|
||||||
|
Headers: "Nagłówki",
|
||||||
|
PushUrl: "Push URL",
|
||||||
|
HeadersInvalidFormat: "Nagłówki żądania nie są w poprawnym formacie JSON: ",
|
||||||
|
BodyInvalidFormat: "Treść żądania nie jest w poprawnym formacie JSON: ",
|
||||||
|
"Monitor History": "Historia monitorów",
|
||||||
|
clearDataOlderThan: "Przechowuj dane dotyczące historii monitorowania {0} dni.",
|
||||||
|
PasswordsDoNotMatch: "Hasła nie pasują.",
|
||||||
|
records: "rekordy",
|
||||||
|
"One record": "Jeden rekord",
|
||||||
|
steamApiKeyDescription: "Do monitorowania serwera gier Steam potrzebny jest klucz Steam Web-API. Możesz zarejestrować swój klucz API tutaj: ",
|
||||||
|
"Current User": "Aktualny użytkownik",
|
||||||
|
recent: "Ostatnie",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
|
apiCredentials: "Poświadczenia API",
|
||||||
};
|
};
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
export default {
|
export default {
|
||||||
languageName: "Русский",
|
languageName: "Русский",
|
||||||
checkEverySecond: "проверять каждые {0} секунд",
|
checkEverySecond: "Проверка каждые {0} секунд",
|
||||||
retriesDescription: "Максимальное количество попыток перед пометкой сервиса как недоступного и отправкой уведомления",
|
retriesDescription: "Максимальное количество попыток перед пометкой сервиса как недоступного и отправкой уведомления",
|
||||||
ignoreTLSError: "Игнорировать ошибку TLS/SSL для HTTPS сайтов",
|
ignoreTLSError: "Игнорировать ошибку TLS/SSL для HTTPS сайтов",
|
||||||
upsideDownModeDescription: "Реверс статуса сервиса. Если сервис доступен, то он помечается как НЕДОСТУПНЫЙ.",
|
upsideDownModeDescription: "Реверс статуса сервиса. Если сервис доступен, то он помечается как НЕДОСТУПНЫЙ.",
|
||||||
@@ -29,7 +29,7 @@ export default {
|
|||||||
"Add New Monitor": "Новый монитор",
|
"Add New Monitor": "Новый монитор",
|
||||||
"Quick Stats": "Статистика",
|
"Quick Stats": "Статистика",
|
||||||
Up: "Доступен",
|
Up: "Доступен",
|
||||||
Down: "Н/Д",
|
Down: "Недоступен",
|
||||||
Pending: "Ожидание",
|
Pending: "Ожидание",
|
||||||
Unknown: "Неизвестно",
|
Unknown: "Неизвестно",
|
||||||
Pause: "Пауза",
|
Pause: "Пауза",
|
||||||
@@ -65,8 +65,8 @@ export default {
|
|||||||
"Accepted Status Codes": "Допустимые коды статуса",
|
"Accepted Status Codes": "Допустимые коды статуса",
|
||||||
Save: "Сохранить",
|
Save: "Сохранить",
|
||||||
Notifications: "Уведомления",
|
Notifications: "Уведомления",
|
||||||
"Not available, please setup.": "Доступных уведомлений нет, необходима настройка.",
|
"Not available, please setup.": "Доступных уведомлений нет, необходимо создать.",
|
||||||
"Setup Notification": "Настроить уведомления",
|
"Setup Notification": "Создать уведомление",
|
||||||
Light: "Светлая",
|
Light: "Светлая",
|
||||||
Dark: "Тёмная",
|
Dark: "Тёмная",
|
||||||
Auto: "Авто",
|
Auto: "Авто",
|
||||||
@@ -142,7 +142,7 @@ export default {
|
|||||||
Token: "Токен",
|
Token: "Токен",
|
||||||
"Show URI": "Показать URI",
|
"Show URI": "Показать URI",
|
||||||
"Clear all statistics": "Удалить всю статистику",
|
"Clear all statistics": "Удалить всю статистику",
|
||||||
retryCheckEverySecond: "повторять каждые {0} секунд",
|
retryCheckEverySecond: "Повтор каждые {0} секунд",
|
||||||
importHandleDescription: "Выберите \"Пропустить существующие\", если вы хотите пропустить каждый монитор или уведомление с таким же именем. \"Перезаписать\" удалит каждый существующий монитор или уведомление и добавит заново. Вариант \"Не проверять\" принудительно восстанавливает все мониторы и уведомления, даже если они уже существуют.",
|
importHandleDescription: "Выберите \"Пропустить существующие\", если вы хотите пропустить каждый монитор или уведомление с таким же именем. \"Перезаписать\" удалит каждый существующий монитор или уведомление и добавит заново. Вариант \"Не проверять\" принудительно восстанавливает все мониторы и уведомления, даже если они уже существуют.",
|
||||||
confirmImportMsg: "Вы действительно хотите восстановить резервную копию? Убедитесь, что вы выбрали подходящий вариант импорта.",
|
confirmImportMsg: "Вы действительно хотите восстановить резервную копию? Убедитесь, что вы выбрали подходящий вариант импорта.",
|
||||||
"Heartbeat Retry Interval": "Интервал повтора опроса",
|
"Heartbeat Retry Interval": "Интервал повтора опроса",
|
||||||
@@ -185,7 +185,7 @@ export default {
|
|||||||
"Switch to Dark Theme": "Тёмная тема",
|
"Switch to Dark Theme": "Тёмная тема",
|
||||||
"Switch to Light Theme": "Светлая тема",
|
"Switch to Light Theme": "Светлая тема",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Вебхук",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
discord: "Discord",
|
discord: "Discord",
|
||||||
teams: "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
@@ -198,8 +198,114 @@ export default {
|
|||||||
octopush: "Octopush",
|
octopush: "Octopush",
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
lunasea: "LunaSea",
|
lunasea: "LunaSea",
|
||||||
apprise: "Apprise (Support 50+ Notification services)",
|
apprise: "Apprise (Поддержка 50+ сервисов уведомлений)",
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
"Primary Base URL": "Основной URL",
|
||||||
|
"Push URL": "URL пуша",
|
||||||
|
needPushEvery: "К этому URL необходимо обращаться каждые {0} секунд",
|
||||||
|
pushOptionalParams: "Опциональные параметры: {0}",
|
||||||
|
defaultNotificationName: "Моё уведомление {notification} ({number})",
|
||||||
|
here: "здесь",
|
||||||
|
Required: "Требуется",
|
||||||
|
"Bot Token": "Токен бота",
|
||||||
|
wayToGetTelegramToken: "Вы можете взять токен здесь - {0}.",
|
||||||
|
"Chat ID": "ID чата",
|
||||||
|
supportTelegramChatID: "Поддерживаются ID чатов, групп и каналов",
|
||||||
|
wayToGetTelegramChatID: "Вы можете взять ID вашего чата, отправив сообщение боту и перейдя по этому URL для просмотра chat_id:",
|
||||||
|
"YOUR BOT TOKEN HERE": "ВАШ ТОКЕН БОТА ЗДЕСЬ",
|
||||||
|
chatIDNotFound: "ID чата не найден; пожалуйста отправьте сначала сообщение боту",
|
||||||
|
"Post URL": "Post URL",
|
||||||
|
"Content Type": "Тип контента",
|
||||||
|
webhookJsonDesc: "{0} подходит для любых современных HTTP-серверов, например Express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} подходит для PHP. JSON-вывод необходимо будет обработать с помощью {decodeFunction}",
|
||||||
|
secureOptionNone: "Нет / STARTTLS (25, 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": "Иконка Emoji",
|
||||||
|
"Channel Name": "Имя канала",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Больше информации о вебхуках: {0}",
|
||||||
|
aboutChannelName: "Введите имя канала в поле {0} Имя канала, если вы хотите обойти канал вебхука. Например: #other-channel",
|
||||||
|
aboutKumaURL: "Если поле Uptime Kuma URL в настройках останется пустым, по умолчанию будет использоваться ссылка на проект на GitHub.",
|
||||||
|
emojiCheatSheet: "Шпаргалка по Emoji: {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: "Номер телефона (межд. формат, например: +79831234567) ",
|
||||||
|
octopushSMSSender: "Имя отправителя SMS: 3-11 символов алвафита, цифр и пробелов (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "ID устройства LunaSea",
|
||||||
|
"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}, создайте провайдера и канал (API сообщений), затем вы сможете получить токен доступа канала и ID пользователя из вышеупомянутых пунктов меню.",
|
||||||
|
"Icon URL": "URL иконки",
|
||||||
|
aboutIconURL: "Вы можете предоставить ссылку на иконку в поле \"URL иконки\" чтобы переопределить картинку профиля по умолчанию. Не используется, если задана иконка Emoji.",
|
||||||
|
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 WebHookURL",
|
||||||
|
matrixHomeserverURL: "URL сервера (вместе с http(s):// и опционально порт)",
|
||||||
|
"Internal Room Id": "Внутренний ID комнаты",
|
||||||
|
matrixDesc1: "Внутренний ID комнаты можно найти в Подробностях в параметрах канала вашего Matrix клиента. Он должен выглядеть примерно как !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
|
matrixDesc2: "Рекомендуется создать нового пользователя и не использовать токен доступа личного пользователя Matrix, т.к. это влечёт за собой полный доступ к аккаунту и к комнатам, в которых вы состоите. Вместо этого создайте нового пользователя и пригласите его только в ту комнату, в которой вы хотите получать уведомления. Токен доступа можно получить, выполнив команду {0}",
|
||||||
|
Method: "Метод",
|
||||||
|
Body: "Тело",
|
||||||
|
Headers: "Заголовки",
|
||||||
|
PushUrl: "URL пуша",
|
||||||
|
HeadersInvalidFormat: "Заголовки запроса некорректны JSON: ",
|
||||||
|
BodyInvalidFormat: "Тело запроса некорректно JSON: ",
|
||||||
|
"Monitor History": "История мониторов",
|
||||||
|
clearDataOlderThan: "Сохранять историю мониторов в течение {0} дней.",
|
||||||
|
PasswordsDoNotMatch: "Пароли не совпадают.",
|
||||||
|
records: "записей",
|
||||||
|
"One record": "Одна запись",
|
||||||
|
steamApiKeyDescription: "Для мониторинга игрового сервера Steam вам необходим Web-API ключ Steam. Зарегистрировать его можно здесь: ",
|
||||||
};
|
};
|
||||||
|
@@ -116,39 +116,39 @@ export default {
|
|||||||
Events: "Olaylar",
|
Events: "Olaylar",
|
||||||
Heartbeats: "Sağlık Durumları",
|
Heartbeats: "Sağlık Durumları",
|
||||||
"Auto Get": "Otomatik Al",
|
"Auto Get": "Otomatik Al",
|
||||||
retryCheckEverySecond: "Retry every {0} seconds.",
|
retryCheckEverySecond: "{0} Saniyede bir dene.",
|
||||||
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
enableDefaultNotificationDescription: "Bu bildirim her yeni serviste aktif olacaktır. Bildirimi servisler için ayrı ayrı deaktive edebilirsiniz. ",
|
||||||
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
|
importHandleDescription: "Aynı isimdeki bütün servisleri ve bildirimleri atlamak için 'Var olanı atla' seçiniz. 'Üzerine yaz' var olan bütün servisleri ve bildirimleri silecektir. ",
|
||||||
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
|
confirmImportMsg: "Yedeği içeri aktarmak istediğinize emin misiniz? Lütfen doğru içeri aktarma seçeneğini seçtiğinizden emin olunuz. ",
|
||||||
twoFAVerifyLabel: "Please type in your token to verify that 2FA is working",
|
twoFAVerifyLabel: "Lütfen tokeni yazarak 2FA doğrulamanın çalıştığından emin olunuz.",
|
||||||
tokenValidSettingsMsg: "Token is valid! You can now save the 2FA settings.",
|
tokenValidSettingsMsg: "Token geçerli! Şimdi 2FA ayarlarını kaydedebilirsiniz. ",
|
||||||
confirmEnableTwoFAMsg: "Are you sure you want to enable 2FA?",
|
confirmEnableTwoFAMsg: "2FA'ı etkinleştirmek istediğinizden emin misiniz?",
|
||||||
confirmDisableTwoFAMsg: "Are you sure you want to disable 2FA?",
|
confirmDisableTwoFAMsg: "2FA'ı devre dışı bırakmak istediğinize emin misiniz?",
|
||||||
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
|
"Heartbeat Retry Interval": "Sağlık Dırımları Tekrar Deneme Sıklığı",
|
||||||
"Import Backup": "Import Backup",
|
"Import Backup": "Yedeği içe aktar",
|
||||||
"Export Backup": "Export Backup",
|
"Export Backup": "Yedeği dışa aktar",
|
||||||
Export: "Export",
|
Export: "Dışa aktar",
|
||||||
Import: "Import",
|
Import: "İçe aktar",
|
||||||
"Default enabled": "Default enabled",
|
"Default enabled": "Varsayılan etkinleştirilmiş",
|
||||||
"Apply on all existing monitors": "Apply on all existing monitors",
|
"Apply on all existing monitors": "Var olan bütün servislere uygula",
|
||||||
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
backupDescription: "Bütün servisleri ve bildirimleri JSON dosyasına yedekleyebilirsiniz.",
|
||||||
backupDescription2: "PS: History and event data is not included.",
|
backupDescription2: "Not: Geçmiş ve etkinlik verileri içinde değildir.",
|
||||||
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
backupDescription3: "Dışa aktarma dosyasında bildirim tokeni gibi hassas veriler bulunur, dikkatli bir şekilde saklayınız.",
|
||||||
alertNoFile: "Please select a file to import.",
|
alertNoFile: "İçeri aktarmak için bir dosya seçiniz.",
|
||||||
alertWrongFileType: "Please select a JSON file.",
|
alertWrongFileType: "Lütfen bir JSON dosyası seçiniz.",
|
||||||
"Clear all statistics": "Clear all Statistics",
|
"Clear all statistics": "Bütün istatistikleri temizle",
|
||||||
"Skip existing": "Skip existing",
|
"Skip existing": "Var olanı atla",
|
||||||
Overwrite: "Overwrite",
|
Overwrite: "Üzerine yaz",
|
||||||
Options: "Options",
|
Options: "Seçenekler",
|
||||||
"Keep both": "Keep both",
|
"Keep both": "İkisini sakla",
|
||||||
"Verify Token": "Verify Token",
|
"Verify Token": "Tokeni doğrula",
|
||||||
"Setup 2FA": "Setup 2FA",
|
"Setup 2FA": "2FA Kur",
|
||||||
"Enable 2FA": "Enable 2FA",
|
"Enable 2FA": "2FA Etkinleştir",
|
||||||
"Disable 2FA": "Disable 2FA",
|
"Disable 2FA": "2FA Devre dışı bırak",
|
||||||
"2FA Settings": "2FA Settings",
|
"2FA Settings": "2FA Ayarları",
|
||||||
"Two Factor Authentication": "Two Factor Authentication",
|
"Two Factor Authentication": "İki Faktörlü Kimlik Doğrulama (2FA)",
|
||||||
Active: "Active",
|
Active: "Aktif",
|
||||||
Inactive: "Inactive",
|
Inactive: "İnaktif",
|
||||||
Token: "Token",
|
Token: "Token",
|
||||||
"Show URI": "Show URI",
|
"Show URI": "Show URI",
|
||||||
Tags: "Tags",
|
Tags: "Tags",
|
||||||
|
283
src/languages/vi.js
Normal file
283
src/languages/vi.js
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Vietnamese",
|
||||||
|
checkEverySecond: "Kiểm tra mỗi {0} giây.",
|
||||||
|
retryCheckEverySecond: "Thử lại mỗi {0} giây.",
|
||||||
|
retriesDescription: "Số lần thử lại tối đa trước khi dịch vụ được đánh dấu là down và gửi thông báo.",
|
||||||
|
ignoreTLSError: "Bỏ qua lỗi TLS/SSL với các web HTTPS.",
|
||||||
|
upsideDownModeDescription: "Trạng thái đảo ngược, nếu dịch vụ có thể truy cập được nghĩa là DOWN.",
|
||||||
|
maxRedirectDescription: "Số lần chuyển hướng (redirect) tối đa. Đặt thành 0 để tắt chuyển hướng",
|
||||||
|
acceptedStatusCodesDescription: "Chọn mã code trạng thái được coi là phản hồi thành công.",
|
||||||
|
passwordNotMatchMsg: "Mật khẩu nhập lại không khớp.",
|
||||||
|
notificationDescription: "Vui lòng chỉ định một kênh thông báo.",
|
||||||
|
keywordDescription: "Từ khoá tìm kiếm phản hồi ở dạng html hoặc JSON, có phân biệt chữ HOA - thường",
|
||||||
|
pauseDashboardHome: "Tạm dừng",
|
||||||
|
deleteMonitorMsg: "Bạn chắc chắn muốn xóa monitor này chứ?",
|
||||||
|
deleteNotificationMsg: "Bạn có chắc chắn muốn xóa kênh thông báo này cho tất cả monitor?",
|
||||||
|
resoverserverDescription: "Cloudflare là máy chủ mặc định, bạn có thể thay đổi bất cứ lúc nào.",
|
||||||
|
rrtypeDescription: "Hãy chọn RR-Type mà bạn muốn giám sát",
|
||||||
|
pauseMonitorMsg: "Bạn chắc chắn muốn tạm dừng chứ?",
|
||||||
|
enableDefaultNotificationDescription: "Bật làm mặc định cho mọi monitor mới về sau. Bạn vẫn có thể tắt thông báo riêng cho từng monitor.",
|
||||||
|
clearEventsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ sự kiện cho monitor này chứ?",
|
||||||
|
clearHeartbeatsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ heartbeats cho monitor này chứ?",
|
||||||
|
confirmClearStatisticsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ số liệu thống kê?",
|
||||||
|
importHandleDescription: "Chọn 'Skip existing' nếu bạn muốn bỏ qua mọi monitor và kênh thông báo trùng tên. 'Overwrite' sẽ ghi đè lên tất cả các monitor và kênh thông báo.",
|
||||||
|
confirmImportMsg: "Bạn có chắc chắn muốn khôi phục bản bản sao lưu này không?.",
|
||||||
|
twoFAVerifyLabel: "Vui lòng nhập mã token của bạn để xác minh rằng 2FA đang hoạt động",
|
||||||
|
tokenValidSettingsMsg: "Mã token hợp lệ! Bạn có thể lưu cài đặt 2FA bây giờ.",
|
||||||
|
confirmEnableTwoFAMsg: "Bạn chắc chắn muốn bật 2FA chứ?",
|
||||||
|
confirmDisableTwoFAMsg: "Bạn chắc chắn muốn tắt 2FA chứ?",
|
||||||
|
Settings: "Cài đặt",
|
||||||
|
Dashboard: "Dashboard",
|
||||||
|
"New Update": "Bản cập nhật mới",
|
||||||
|
Language: "Ngôn ngữ",
|
||||||
|
Appearance: "Giao diện",
|
||||||
|
Theme: "Theme",
|
||||||
|
General: "Chung",
|
||||||
|
Version: "Phiên bản",
|
||||||
|
"Check Update On GitHub": "Kiểm tra bản cập nhật mới trên GitHub",
|
||||||
|
List: "List",
|
||||||
|
Add: "Thêm",
|
||||||
|
"Add New Monitor": "Thêm mới Monitor",
|
||||||
|
"Quick Stats": "Thống kê nhanh",
|
||||||
|
Up: "Lên",
|
||||||
|
Down: "Xuống",
|
||||||
|
Pending: "Chờ xử lý",
|
||||||
|
Unknown: "Không xác định",
|
||||||
|
Pause: "Tạm dừng",
|
||||||
|
Name: "Tên",
|
||||||
|
Status: "Trạng thái",
|
||||||
|
DateTime: "Ngày tháng",
|
||||||
|
Message: "Tin nhắn",
|
||||||
|
"No important events": "Không có sự kiện quan trọng nào",
|
||||||
|
Resume: "Khôi phục",
|
||||||
|
Edit: "Sửa",
|
||||||
|
Delete: "Xoá",
|
||||||
|
Current: "Hiện tại",
|
||||||
|
Uptime: "Uptime",
|
||||||
|
"Cert Exp.": "Cert hết hạn",
|
||||||
|
days: "ngày",
|
||||||
|
day: "ngày",
|
||||||
|
"-day": "-ngày",
|
||||||
|
hour: "giờ",
|
||||||
|
"-hour": "-giờ",
|
||||||
|
Response: "Phản hồi",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Kiểu monitor",
|
||||||
|
Keyword: "Từ khoá",
|
||||||
|
"Friendly Name": "Tên dễ hiểu",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Hostname",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Tần suất heartbeat",
|
||||||
|
Retries: "Thử lại",
|
||||||
|
"Heartbeat Retry Interval": "Tần suất thử lại của Heartbeat",
|
||||||
|
Advanced: "Nâng cao",
|
||||||
|
"Upside Down Mode": "Trạng thái đảo ngược",
|
||||||
|
"Max. Redirects": "Chuyển hướng tối đa",
|
||||||
|
"Accepted Status Codes": "Codes trạng thái chấp nhận",
|
||||||
|
Save: "Lưu",
|
||||||
|
Notifications: "Thông báo",
|
||||||
|
"Not available, please setup.": "Chưa sẵn sàng, hãy cài đặt.",
|
||||||
|
"Setup Notification": "Cài đặt thông báo",
|
||||||
|
Light: "Sáng",
|
||||||
|
Dark: "Tối",
|
||||||
|
Auto: "Tự động",
|
||||||
|
"Theme - Heartbeat Bar": "Theme - Heartbeat Bar",
|
||||||
|
Normal: "Bình thường",
|
||||||
|
Bottom: "Dưới",
|
||||||
|
None: "Không có",
|
||||||
|
Timezone: "Múi giờ",
|
||||||
|
"Search Engine Visibility": "Hiển thị với các công cụ tìm kiếm",
|
||||||
|
"Allow indexing": "Cho phép indexing",
|
||||||
|
"Discourage search engines from indexing site": "Ngăn chặn các công cụ tìm kiếm indexing trang",
|
||||||
|
"Change Password": "Thay đổi mật khẩu",
|
||||||
|
"Current Password": "Mật khẩu hiện tại",
|
||||||
|
"New Password": "Mật khẩu mới",
|
||||||
|
"Repeat New Password": "Lặp lại mật khẩu mới",
|
||||||
|
"Update Password": "Cập nhật mật khẩu",
|
||||||
|
"Disable Auth": "Tắt xác minh",
|
||||||
|
"Enable Auth": "Bật xác minh",
|
||||||
|
Logout: "Đăng xuất",
|
||||||
|
Leave: "Rời",
|
||||||
|
"I understand, please disable": "Tôi hiểu, làm ơn hãy tắt!",
|
||||||
|
Confirm: "Xác nhận",
|
||||||
|
Yes: "Có",
|
||||||
|
No: "Không",
|
||||||
|
Username: "Tài khoản",
|
||||||
|
Password: "Mật khẩu",
|
||||||
|
"Remember me": "Lưu phiên đăng nhập",
|
||||||
|
Login: "Đăng nhập",
|
||||||
|
"No Monitors, please": "Không có monitor nào",
|
||||||
|
"add one": "Thêm mới",
|
||||||
|
"Notification Type": "Kiểu thông báo",
|
||||||
|
Email: "Email",
|
||||||
|
Test: "Thử",
|
||||||
|
"Certificate Info": "Thông tin Certificate",
|
||||||
|
"Resolver Server": "Máy chủ Resolver",
|
||||||
|
"Resource Record Type": "Loại bản ghi",
|
||||||
|
"Last Result": "Kết quả cuối cùng",
|
||||||
|
"Create your admin account": "Tạo tài khoản quản trị",
|
||||||
|
"Repeat Password": "Lặp lại mật khẩu",
|
||||||
|
"Import Backup": "Khôi phục bản sao lưu",
|
||||||
|
"Export Backup": "Xuất bản sao lưu",
|
||||||
|
Export: "Xuất",
|
||||||
|
Import: "Khôi phục",
|
||||||
|
respTime: "Thời gian phản hồi (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
"Default enabled": "Mặc định bật",
|
||||||
|
"Apply on all existing monitors": "Áp dụng cho tất cả monitor đang có",
|
||||||
|
Create: "Tạo",
|
||||||
|
"Clear Data": "Xoá dữ liệu",
|
||||||
|
Events: "Sự kiện",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Tự động lấy",
|
||||||
|
backupDescription: "Bạn có thể sao lưu tất cả các màn hình và tất cả các thông báo vào một file JSON.",
|
||||||
|
backupDescription2: "PS: Không bao gồm dữ liệu lịch sử các sự kiện.",
|
||||||
|
backupDescription3: "Hãy lưu giữ file này cẩn thận vì trong file đó chứa cả các mã token thông báo.",
|
||||||
|
alertNoFile: "Hãy chọn file để khôi phục.",
|
||||||
|
alertWrongFileType: "Hãy chọn file JSON.",
|
||||||
|
"Clear all statistics": "Xoá tất cả thống kê",
|
||||||
|
"Skip existing": "Skip existing",
|
||||||
|
Overwrite: "Ghi đè",
|
||||||
|
Options: "Tuỳ chọn",
|
||||||
|
"Keep both": "Giữ lại cả hai",
|
||||||
|
"Verify Token": "Xác minh Token",
|
||||||
|
"Setup 2FA": "Cài đặt 2FA",
|
||||||
|
"Enable 2FA": "Bật 2FA",
|
||||||
|
"Disable 2FA": "Tắt 2FA",
|
||||||
|
"2FA Settings": "Cài đặt 2FA",
|
||||||
|
"Two Factor Authentication": "Xác thực hai yếu tố",
|
||||||
|
Active: "Hoạt động",
|
||||||
|
Inactive: "Ngừng hoạt động",
|
||||||
|
Token: "Token",
|
||||||
|
"Show URI": "Hiển thị URI",
|
||||||
|
Tags: "Tags",
|
||||||
|
"Add New below or Select...": "Thêm mới ở dưới hoặc Chọn...",
|
||||||
|
"Tag with this name already exist.": "Tag với tên đã tồn tại.",
|
||||||
|
"Tag with this value already exist.": "Tag với value đã tồn tại.",
|
||||||
|
color: "Màu sắc",
|
||||||
|
"value (optional)": "Value (tuỳ chọn)",
|
||||||
|
Gray: "Xám",
|
||||||
|
Red: "Đỏ",
|
||||||
|
Orange: "Cam",
|
||||||
|
Green: "Xanh lá",
|
||||||
|
Blue: "Xanh da trời",
|
||||||
|
Indigo: "Chàm",
|
||||||
|
Purple: "Tím",
|
||||||
|
Pink: "Hồng",
|
||||||
|
"Search...": "Tìm kiếm...",
|
||||||
|
"Avg. Ping": "Ping Trung bình",
|
||||||
|
"Avg. Response": "Phản hồi trung bình",
|
||||||
|
"Entry Page": "Entry Page",
|
||||||
|
statusPageNothing: "Không có gì, hãy thêm nhóm monitor hoặc monitor.",
|
||||||
|
"No Services": "Không có dịch vụ",
|
||||||
|
"All Systems Operational": "Tất cả các hệ thống hoạt động",
|
||||||
|
"Partially Degraded Service": "Dịch vụ xuống cấp một phần",
|
||||||
|
"Degraded Service": "Degraded Service",
|
||||||
|
"Add Group": "Thêm nhóm",
|
||||||
|
"Add a monitor": "Thêm monitor",
|
||||||
|
"Edit Status Page": "Sửa trang trạng thái",
|
||||||
|
"Go to Dashboard": "Đi tới Dashboard",
|
||||||
|
"Status Page": "Trang trạng thái",
|
||||||
|
defaultNotificationName: "My {notification} Alerts ({number})",
|
||||||
|
here: "tại đây",
|
||||||
|
Required: "Bắt buộc",
|
||||||
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "Bot Token",
|
||||||
|
"You can get a token from": "Bạn có thể lấy mã token từ",
|
||||||
|
"Chat ID": "Chat ID",
|
||||||
|
supportTelegramChatID: "Hỗ trợ chat trực tiếp / Nhóm / Kênh Chat ID",
|
||||||
|
wayToGetTelegramChatID: "Bạn có thể lấy chat id của mình bằng cách gửi tin nhắn tới bot và truy cập url này để xem chat_id:",
|
||||||
|
"YOUR BOT TOKEN HERE": "MÃ BOT TOKEN CỦA BẠN",
|
||||||
|
chatIDNotFound: "Không tìm thấy Chat ID, vui lòng gửi tin nhắn cho bot này trước",
|
||||||
|
webhook: "Webhook",
|
||||||
|
"Post URL": "URL đăng",
|
||||||
|
"Content Type": "Loại nội dung",
|
||||||
|
webhookJsonDesc: "{0} phù hợp với bất kỳ máy chủ http hiện đại nào như express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} phù hợp với PHP, bạn chỉ cần phân tích cú pháp json bằng {decodeFunction}",
|
||||||
|
smtp: "Email (SMTP)",
|
||||||
|
secureOptionNone: "None / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "Bỏ qua lỗi TLS",
|
||||||
|
"From Email": "Từ Email",
|
||||||
|
"To Email": "Tới Email",
|
||||||
|
smtpCC: "CC",
|
||||||
|
smtpBCC: "BCC",
|
||||||
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook URL",
|
||||||
|
wayToGetDiscordURL: "Để lấy Discord, hãy vào: Server Settings -> Integrations -> Create Webhook",
|
||||||
|
"Bot Display Name": "Tên hiển thị của Bot",
|
||||||
|
"Prefix Custom Message": "Tiền tố tin nhắn tuỳ chọn",
|
||||||
|
"Hello @everyone is...": "Xin chào {'@'} mọi người đang...",
|
||||||
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "Webhook URL",
|
||||||
|
wayToGetTeamsURL: "Bạn có thể học cách tạo webhook url {0}.",
|
||||||
|
signal: "Signal",
|
||||||
|
Number: "Số",
|
||||||
|
Recipients: "Người nhận",
|
||||||
|
needSignalAPI: "Bạn cần một tín hiệu client với REST API.",
|
||||||
|
wayToCheckSignalURL: "Bạn có thể kiểm tra url này để xem cách thiết lập:",
|
||||||
|
signalImportant: "QUAN TRỌNG: Bạn không thể kết hợp các nhóm và số trong người nhận!",
|
||||||
|
gotify: "Gotify",
|
||||||
|
"Application Token": "Mã Token ứng dụng",
|
||||||
|
"Server URL": "URL máy chủ",
|
||||||
|
Priority: "Mức ưu tiên",
|
||||||
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "Icon Emoji",
|
||||||
|
"Channel Name": "Tên Channel",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma URL",
|
||||||
|
aboutWebhooks: "Thông tin thêm về webhook trên: {0}",
|
||||||
|
aboutChannelName: "Nhập tên kênh trên {0} trường Channel Name nếu bạn muốn bỏ qua kênh webhook. vd: #other-channel",
|
||||||
|
aboutKumaURL: "Nếu bạn để trống trường Uptime Kuma URL, mặc định sẽ là trang Project Github.",
|
||||||
|
emojiCheatSheet: "Bảng tra cứu Emoji: {0}",
|
||||||
|
"rocket.chat": "Rocket.chat",
|
||||||
|
pushover: "Pushover",
|
||||||
|
pushy: "Pushy",
|
||||||
|
octopush: "Octopush",
|
||||||
|
promosms: "PromoSMS",
|
||||||
|
lunasea: "LunaSea",
|
||||||
|
apprise: "Thông báo (Hỗ trợ 50+ dịch vụ thông báo)",
|
||||||
|
pushbullet: "Pushbullet",
|
||||||
|
line: "Line Messenger",
|
||||||
|
mattermost: "Mattermost",
|
||||||
|
"User Key": "User Key",
|
||||||
|
Device: "Thiết bị",
|
||||||
|
"Message Title": "Tiêu đề tin nhắn",
|
||||||
|
"Notification Sound": "Âm thanh thông báo",
|
||||||
|
"More info on:": "Thông tin chi tiết tại: {0}",
|
||||||
|
pushoverDesc1: "Mức ưu tiên khẩn cấp (2) có thời gian chờ mặc định là 30 giây giữa các lần thử lại và sẽ hết hạn sau 1 giờ.",
|
||||||
|
pushoverDesc2: "Nếu bạn muốn gửi thông báo đến các thiết bị khác nhau, hãy điền vào trường Thiết bị.",
|
||||||
|
"SMS Type": "SMS Type",
|
||||||
|
octopushTypePremium: "Premium (Nhanh - Khuyến nghị nên dùng cho cảnh báo)",
|
||||||
|
octopushTypeLowCost: "Giá rẻ (Chậm, thỉnh thoảng bị chặn)",
|
||||||
|
"Check octopush prices": "Kiểm tra giá octopush {0}.",
|
||||||
|
octopushPhoneNumber: "Số điện thoại (Định dạng intl, vd : +33612345678) ",
|
||||||
|
octopushSMSSender: "SMS người gửi : 3-11 ký tự chữ, số và dấu cách (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "LunaSea ID thiết bị",
|
||||||
|
"Apprise URL": "Apprise URL",
|
||||||
|
"Example:": "Ví dụ: {0}",
|
||||||
|
"Read more:": "Đọc thêm: {0}",
|
||||||
|
"Status:": "Trạng thái: {0}",
|
||||||
|
"Read more": "Đọc thêm",
|
||||||
|
appriseInstalled: "Đã cài đặt Apprise.",
|
||||||
|
appriseNotInstalled: "Chưa cài đặt Apprise. {0}",
|
||||||
|
"Access Token": "Token truy cập",
|
||||||
|
"Channel access token": "Token kênh truy cập",
|
||||||
|
"Line Developers Console": "Line Developers Console",
|
||||||
|
lineDevConsoleTo: "Line Developers Console - {0}",
|
||||||
|
"Basic Settings": "Cài đặt cơ bản",
|
||||||
|
"User ID": "User ID",
|
||||||
|
"Messaging API": "Messaging API",
|
||||||
|
wayToGetLineChannelToken: "Trước tiên, hãy truy cập {0},tạo nhà cung cấp và kênh (Messaging API), sau đó bạn có thể nhận mã token truy cập kênh và id người dùng từ các mục menu được đề cập ở trên.",
|
||||||
|
"Icon URL": "Icon URL",
|
||||||
|
aboutIconURL: "Bạn có thể cung cấp liên kết đến ảnh trong \"Icon URL\" để ghi đè ảnh hồ sơ mặc định. Sẽ không được sử dụng nếu Biểu tượng cảm xúc được thiết lập.",
|
||||||
|
aboutMattermostChannelName: "Bạn có thể ghi đè kênh mặc định mà webhook đăng lên bằng cách nhập tên kênh vào trường \"Channel Name\". Điều này cần được bật trong cài đặt Mattermost webhook. Ví dụ: #other-channel",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO - rẻ nhưng chậm và thường xuyên quá tải. Chỉ dành cho người Ba Lan.",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - Tin nhắn sẽ tự động hiển thị trên thiết bị của người nhận. Chỉ dành cho người Ba Lan.",
|
||||||
|
promosmsTypeFull: "SMS FULL - SMS cao cấp, Bạn có thể sử dụng Tên Người gửi (Bạn cần đăng ký tên trước). Đáng tin cậy cho các cảnh báo.",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - Ưu tiên cao nhất trong hệ thống. Rất nhanh chóng và đáng tin cậy nhưng tốn kém, (giá gấp đôi SMS FULL).",
|
||||||
|
promosmsPhoneNumber: "Số điện thoại (Bỏ qua mã vùng với người Ba Lan)",
|
||||||
|
promosmsSMSSender: "SMS Tên người gửi: Tên đã đăng ký trước hoặc tên mặc định: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
|
||||||
|
"Feishu WebHookUrl": "Feishu WebHookUrl",
|
||||||
|
};
|
@@ -22,7 +22,8 @@ export default {
|
|||||||
Appearance: "外观设置",
|
Appearance: "外观设置",
|
||||||
Theme: "主题",
|
Theme: "主题",
|
||||||
General: "基本设置",
|
General: "基本设置",
|
||||||
Version: "Version",
|
"Primary Base URL": "站点地址(URL)",
|
||||||
|
Version: "版本",
|
||||||
"Check Update On GitHub": "检查更新",
|
"Check Update On GitHub": "检查更新",
|
||||||
List: "列表",
|
List: "列表",
|
||||||
Add: "添加",
|
Add: "添加",
|
||||||
@@ -43,7 +44,7 @@ export default {
|
|||||||
Delete: "删除",
|
Delete: "删除",
|
||||||
Current: "当前",
|
Current: "当前",
|
||||||
Uptime: "可用率",
|
Uptime: "可用率",
|
||||||
"Cert Exp.": "证书过期",
|
"Cert Exp.": "证书有效期",
|
||||||
days: "天",
|
days: "天",
|
||||||
day: "天",
|
day: "天",
|
||||||
"-day": " 天",
|
"-day": " 天",
|
||||||
@@ -63,6 +64,9 @@ export default {
|
|||||||
"Upside Down Mode": "反向监控",
|
"Upside Down Mode": "反向监控",
|
||||||
"Max. Redirects": "重定向次数",
|
"Max. Redirects": "重定向次数",
|
||||||
"Accepted Status Codes": "有效状态码",
|
"Accepted Status Codes": "有效状态码",
|
||||||
|
"Push URL": "推送链接",
|
||||||
|
needPushEvery: "你需要每 {0} 秒调用一次",
|
||||||
|
pushOptionalParams: "可选参数:{0}",
|
||||||
Save: "保存",
|
Save: "保存",
|
||||||
Notifications: "消息通知",
|
Notifications: "消息通知",
|
||||||
"Not available, please setup.": "无可用通道,请先设置",
|
"Not available, please setup.": "无可用通道,请先设置",
|
||||||
@@ -103,10 +107,10 @@ export default {
|
|||||||
"Certificate Info": "证书信息",
|
"Certificate Info": "证书信息",
|
||||||
"Resolver Server": "解析服务器",
|
"Resolver Server": "解析服务器",
|
||||||
"Resource Record Type": "资源记录类型",
|
"Resource Record Type": "资源记录类型",
|
||||||
"Last Result": "Last Result",
|
"Last Result": "最后结果",
|
||||||
"Create your admin account": "创建管理员账号",
|
"Create your admin account": "创建管理员账号",
|
||||||
"Repeat Password": "重复密码",
|
"Repeat Password": "重复密码",
|
||||||
respTime: "Resp. Time (ms)",
|
respTime: "响应时间(毫秒)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
Create: "创建",
|
Create: "创建",
|
||||||
clearEventsMsg: "确定要删除此监控项的所有事件吗?",
|
clearEventsMsg: "确定要删除此监控项的所有事件吗?",
|
||||||
@@ -126,21 +130,21 @@ export default {
|
|||||||
backupDescription3: "导出的文件中可能包含敏感信息,如消息通知的 Token 信息,请小心存放!",
|
backupDescription3: "导出的文件中可能包含敏感信息,如消息通知的 Token 信息,请小心存放!",
|
||||||
alertNoFile: "请选择一个文件导入",
|
alertNoFile: "请选择一个文件导入",
|
||||||
alertWrongFileType: "请选择一个 JSON 格式的文件",
|
alertWrongFileType: "请选择一个 JSON 格式的文件",
|
||||||
twoFAVerifyLabel: "请输入Token以验证2FA(二次验证)是否正常工作",
|
twoFAVerifyLabel: "请输入Token以验证 2FA(二次验证)是否正常工作",
|
||||||
tokenValidSettingsMsg: "Token有效!您现在可以保存2FA(二次验证)设置",
|
tokenValidSettingsMsg: "Token有效!您现在可以保存 2FA(二次验证)设置",
|
||||||
confirmEnableTwoFAMsg: "确定要启用2FA(二次验证)吗?",
|
confirmEnableTwoFAMsg: "确定要启用 2FA(二次验证)吗?",
|
||||||
confirmDisableTwoFAMsg: "确定要禁用2FA(二次验证)吗?",
|
confirmDisableTwoFAMsg: "确定要禁用 2FA(二次验证)吗?",
|
||||||
"Apply on all existing monitors": "应用到所有监控项",
|
"Apply on all existing monitors": "应用到所有监控项",
|
||||||
"Verify Token": "验证Token",
|
"Verify Token": "验证 Token",
|
||||||
"Setup 2FA": "设置2FA",
|
"Setup 2FA": "设置 2FA",
|
||||||
"Enable 2FA": "启用2FA",
|
"Enable 2FA": "启用 2FA",
|
||||||
"Disable 2FA": "禁用2FA",
|
"Disable 2FA": "禁用 2FA",
|
||||||
"2FA Settings": "2FA设置",
|
"2FA Settings": "2FA 设置",
|
||||||
"Two Factor Authentication": "双因素认证",
|
"Two Factor Authentication": "双因素认证",
|
||||||
Active: "有效",
|
Active: "生效",
|
||||||
Inactive: "无效",
|
Inactive: "未生效",
|
||||||
Token: "Token",
|
Token: "Token",
|
||||||
"Show URI": "显示URI",
|
"Show URI": "显示链接",
|
||||||
"Clear all statistics": "清除所有统计数据",
|
"Clear all statistics": "清除所有统计数据",
|
||||||
retryCheckEverySecond: "重试间隔 {0} 秒",
|
retryCheckEverySecond: "重试间隔 {0} 秒",
|
||||||
importHandleDescription: "如果想跳过同名的监控项或通知,请选择“跳过”;“覆盖”将删除所有现有的监控项和通知。",
|
importHandleDescription: "如果想跳过同名的监控项或通知,请选择“跳过”;“覆盖”将删除所有现有的监控项和通知。",
|
||||||
@@ -167,7 +171,7 @@ export default {
|
|||||||
Purple: "紫色",
|
Purple: "紫色",
|
||||||
Pink: "粉色",
|
Pink: "粉色",
|
||||||
"Search...": "搜索...",
|
"Search...": "搜索...",
|
||||||
"Avg. Ping": "平均Ping",
|
"Avg. Ping": "平均 Ping",
|
||||||
"Avg. Response": "平均响应",
|
"Avg. Response": "平均响应",
|
||||||
"Entry Page": "入口页面",
|
"Entry Page": "入口页面",
|
||||||
statusPageNothing: "这里什么也没有,请添加一个分组或一个监控项。",
|
statusPageNothing: "这里什么也没有,请添加一个分组或一个监控项。",
|
||||||
@@ -182,7 +186,7 @@ export default {
|
|||||||
"Status Page": "状态页",
|
"Status Page": "状态页",
|
||||||
telegram: "Telegram",
|
telegram: "Telegram",
|
||||||
webhook: "Webhook",
|
webhook: "Webhook",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "电子邮件(SMTP)",
|
||||||
discord: "Discord",
|
discord: "Discord",
|
||||||
teams: "Microsoft Teams",
|
teams: "Microsoft Teams",
|
||||||
signal: "Signal",
|
signal: "Signal",
|
||||||
@@ -194,8 +198,97 @@ export default {
|
|||||||
octopush: "Octopush",
|
octopush: "Octopush",
|
||||||
promosms: "PromoSMS",
|
promosms: "PromoSMS",
|
||||||
lunasea: "LunaSea",
|
lunasea: "LunaSea",
|
||||||
apprise: "Apprise (Support 50+ Notification services)",
|
apprise: "Apprise (支持50+种通知服务)",
|
||||||
pushbullet: "Pushbullet",
|
pushbullet: "Pushbullet",
|
||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
|
"Feishu WebHookUrl": "飞书 WebHook 地址",
|
||||||
|
defaultNotificationName: "{notification} 通知({number})",
|
||||||
|
here: "这里",
|
||||||
|
Required: "必填",
|
||||||
|
"Bot Token": "Bot Token",
|
||||||
|
wayToGetTelegramToken: "你可以从 {0} 获取 Token。",
|
||||||
|
"Chat ID": "Chat ID",
|
||||||
|
supportTelegramChatID: "支持对话/群组/频道的 ID",
|
||||||
|
wayToGetTelegramChatID: "你可以发送一条消息给你的机器人然后到下面的链接来查看你的 chat_id:",
|
||||||
|
"YOUR BOT TOKEN HERE": "这里替换成你的 BOT TOKEN",
|
||||||
|
chatIDNotFound: "没有找到 Chat ID,请先给你的机器人发送一条消息。",
|
||||||
|
"Post URL": "目标链接",
|
||||||
|
"Content Type": "Content Type",
|
||||||
|
webhookJsonDesc: "{0} 适合现代的服务,比如 express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} 适合PHP,解码使用 {decodeFunction}",
|
||||||
|
secureOptionNone: "无 / STARTTLS(25,587)",
|
||||||
|
secureOptionTLS: "TLS(465)",
|
||||||
|
"Ignore TLS Error": "忽略 TLS 错误",
|
||||||
|
"From Email": "发信人",
|
||||||
|
"To Email": "收信人",
|
||||||
|
smtpCC: "抄送",
|
||||||
|
smtpBCC: "密送",
|
||||||
|
"Discord Webhook URL": "Discord Webhook 链接",
|
||||||
|
wayToGetDiscordURL: "获取方式:服务器设置 -> 整合 -> 创建 Webhook",
|
||||||
|
"Bot Display Name": "机器人显示名称",
|
||||||
|
"Prefix Custom Message": "自定义消息前缀",
|
||||||
|
"Hello @everyone is...": "{'@'}所有人,……",
|
||||||
|
"Webhook URL": "Webhook 链接",
|
||||||
|
wayToGetTeamsURL: "你可以在 {0} 获取 Webhook 链接。",
|
||||||
|
Number: "号码",
|
||||||
|
Recipients: "收件人",
|
||||||
|
needSignalAPI: "你需要有一个带 REST API 的 Signal 客户端。",
|
||||||
|
wayToCheckSignalURL: "你可以通过下面的链接来了解如何设置:",
|
||||||
|
signalImportant: "重要:你不能混合设定收件人的分组和号码!",
|
||||||
|
"Application Token": "Application Token",
|
||||||
|
"Server URL": "服务器链接",
|
||||||
|
Priority: "优先级",
|
||||||
|
"Icon Emoji": "Emoji 图标",
|
||||||
|
"Channel Name": "频道名称",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma 链接",
|
||||||
|
aboutWebhooks: "关于 Webhook 的更多信息:{0}",
|
||||||
|
aboutChannelName: "如果你想绕过 Webhook 设定的频道,请在设定 {0} 的频道名称字段为你想要的频道。例:#other-channel",
|
||||||
|
aboutKumaURL: "如果保留 Uptime Kuma 链接为空,将会默认指向项目的 Github 页面。",
|
||||||
|
emojiCheatSheet: "Emoji 参考表:{0}",
|
||||||
|
"User Key": "User Key",
|
||||||
|
Device: "设备",
|
||||||
|
"Message Title": "消息标题",
|
||||||
|
"Notification Sound": "通知铃声",
|
||||||
|
"More info on:": "更多信息:{0}",
|
||||||
|
pushoverDesc1: "紧急优先级(2)会在一小时内每30秒重试一次。",
|
||||||
|
pushoverDesc2: "如果你想发送通知给不同的设备,请填写“设备”字段。",
|
||||||
|
"SMS Type": "短信类型",
|
||||||
|
octopushTypePremium: "Premium(快 - 推荐用于警报)",
|
||||||
|
octopushTypeLowCost: "Low Cost(慢 - 有时会被运营商屏蔽)",
|
||||||
|
"Check octopush prices": "查看 Octopush 的价格 {0}。",
|
||||||
|
octopushPhoneNumber: "电话号码(国际格式,例:+33612345678)",
|
||||||
|
octopushSMSSender: "短信发送名称:3-11位大小写字母、数字和空格(a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "LunaSea 设备 ID",
|
||||||
|
"Apprise URL": "Apprise 链接",
|
||||||
|
"Example:": "例:{0}",
|
||||||
|
"Read more:": "了解更多:{0}",
|
||||||
|
"Status:": "状态:{0}",
|
||||||
|
"Read more": "了解更多",
|
||||||
|
appriseInstalled: "Apprise 已安装",
|
||||||
|
appriseNotInstalled: "Apprise 未安装。{0}",
|
||||||
|
"Access Token": "Access Token",
|
||||||
|
"Channel access token": "频道 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: "首先访问 {0},创建一个提供者和频道(Messaging API),然后你就可以从上面提到的地方获取频道的 access token 和用户 ID。",
|
||||||
|
"Icon URL": "图标链接",
|
||||||
|
aboutIconURL: "你可以在“Icon URL”中提供一个图片地址来覆盖默认的资料图片。如果设置了 Emoji 图标此字段会被忽略。",
|
||||||
|
aboutMattermostChannelName: "如果你想覆盖 Webhook 设定的频道,请在“频道名称”字段为你想要的频道。这需要在 Mattermost 的 Webhook 设定中启用。例:#other-channel",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO - 便宜但是慢,并且容易超负荷。仅限波兰地区的收件人。",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - 消息会自动显示在收件人设备上。仅限波兰地区的收件人。",
|
||||||
|
promosmsTypeFull: "SMS FULL - 高等级,你可以使用你自己的发件人名称(你需要先注册一个). 对于警报来说更可靠。",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - 最高优先级。非常快速可靠,但更贵(越两倍 SMS FULL 等级的价格)。",
|
||||||
|
promosmsPhoneNumber: "电话号码(波兰地区收件人可以不填区号)",
|
||||||
|
promosmsSMSSender: "短信发件人名称:已注册的名称或以下默认值之一:InfoSMS,SMS Info,MaxSMS,INFO,SMS",
|
||||||
|
checkPrice: "查看 {0} 的价格:",
|
||||||
|
octopushLegacyHint: "你是否在使用旧版本的 Octopush(2011-2020)?",
|
||||||
|
matrixHomeserverURL: "服务器链接(开头带 http(s):// 和可能的需要的端口号)",
|
||||||
|
"Internal Room Id": "Internal Room Id",
|
||||||
|
matrixDesc1: "你可以在 Matrix 客户端房间设置的高级选项找到 Internal Room Id。格式类似于 !QMdRCpUIfLwsfjxye6:home.server。",
|
||||||
|
matrixDesc2: "请不要使用你自己的 Access Token,这将开放你所有的账户权限和你加入的房间权限。你可以创建一个新的用户并邀请它至你允许的的房间中。你可以运行以下命令来获取 Access Token:{0}",
|
||||||
};
|
};
|
||||||
|
310
src/languages/zh-TW.js
Normal file
310
src/languages/zh-TW.js
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "繁體中文 (台灣)",
|
||||||
|
checkEverySecond: "每 {0} 秒檢查一次",
|
||||||
|
retryCheckEverySecond: "每 {0} 秒重試一次",
|
||||||
|
retriesDescription: "在服務被標記為離線並傳送通知前的最大重試次數",
|
||||||
|
ignoreTLSError: "忽略 HTTPS 網站的 TLS/SSL 錯誤",
|
||||||
|
upsideDownModeDescription: "反轉顯示狀態。若服務可以連線,將顯示離線。",
|
||||||
|
maxRedirectDescription: "最大重新導向跟隨次數。設為 0 將停用重新導向。",
|
||||||
|
acceptedStatusCodesDescription: "選擇視為成功回應的狀態碼。",
|
||||||
|
passwordNotMatchMsg: "密碼不相符。",
|
||||||
|
notificationDescription: "必須將通知指派給監測器才能運作。",
|
||||||
|
keywordDescription: "HTML 或 JSON 回應的搜尋關鍵字。區分大小寫。",
|
||||||
|
pauseDashboardHome: "暫停",
|
||||||
|
deleteMonitorMsg: "您確定要刪除此監測器嗎?",
|
||||||
|
deleteNotificationMsg: "您確定要為所有監測器刪除此通知嗎?",
|
||||||
|
resoverserverDescription: "Cloudflare 為預設伺服器。您可以隨時更換解析伺服器。",
|
||||||
|
rrtypeDescription: "選擇您想要監測的資源記錄",
|
||||||
|
pauseMonitorMsg: "您確定要暫停嗎?",
|
||||||
|
enableDefaultNotificationDescription: "預設情況下,新監測器將啟用此通知。您仍可分別停用各監測器的通知。",
|
||||||
|
clearEventsMsg: "您確定要刪除此監測器的所有事件嗎?",
|
||||||
|
clearHeartbeatsMsg: "您確定要刪除此監測器的所有心跳嗎?",
|
||||||
|
confirmClearStatisticsMsg: "您確定要刪除所有統計資料嗎?",
|
||||||
|
importHandleDescription: "若您想跳過所有相同名稱的監測器或通知,請選擇 '略過現有'。選擇 '覆寫' 將刪除所有現有的監測器及通知。",
|
||||||
|
confirmImportMsg: "您確定要匯入備份嗎?請確認是否選擇正確的匯入設定。",
|
||||||
|
twoFAVerifyLabel: "請輸入權杖以驗證雙步驟驗證:",
|
||||||
|
tokenValidSettingsMsg: "權杖有效!您可以儲存雙步驟驗證設定了。",
|
||||||
|
confirmEnableTwoFAMsg: "您確定要啟用雙步驟驗證嗎?",
|
||||||
|
confirmDisableTwoFAMsg: "您確定要停用雙步驟驗證嗎?",
|
||||||
|
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.": "憑證期限",
|
||||||
|
days: "天",
|
||||||
|
day: "天",
|
||||||
|
"-day": "天",
|
||||||
|
hour: "小時",
|
||||||
|
"-hour": "小時",
|
||||||
|
Response: "回應",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "監測器類型",
|
||||||
|
Keyword: "關鍵字",
|
||||||
|
"Friendly Name": "易記名稱",
|
||||||
|
URL: "網址",
|
||||||
|
Hostname: "主機名稱",
|
||||||
|
Port: "連接埠",
|
||||||
|
"Heartbeat Interval": "心跳間隔",
|
||||||
|
Retries: "重試次數",
|
||||||
|
"Heartbeat Retry Interval": "心跳重試間隔",
|
||||||
|
Advanced: "進階",
|
||||||
|
"Upside Down Mode": "顛倒模式",
|
||||||
|
"Max. Redirects": "最大重新導向次數",
|
||||||
|
"Accepted Status Codes": "可接受的狀態碼",
|
||||||
|
"Push URL": "推送網址",
|
||||||
|
needPushEvery: "您應每 {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": "啟用驗證",
|
||||||
|
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": "解析伺服器",
|
||||||
|
"Resource Record Type": "資源記錄類型",
|
||||||
|
"Last Result": "最後結果",
|
||||||
|
"Create your admin account": "建立您的管理員帳號",
|
||||||
|
"Repeat Password": "確認密碼",
|
||||||
|
"Import Backup": "匯入備份",
|
||||||
|
"Export Backup": "匯出備份",
|
||||||
|
Export: "匯出",
|
||||||
|
Import: "匯入",
|
||||||
|
respTime: "回應時間 (毫秒)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
"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": "設置雙步驟驗證",
|
||||||
|
"Enable 2FA": "啟用雙步驟驗證",
|
||||||
|
"Disable 2FA": "停用雙步驟驗證",
|
||||||
|
"2FA Settings": "雙步驟驗證設定",
|
||||||
|
"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": "平均 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": "狀態頁",
|
||||||
|
defaultNotificationName: "我的 {notification} 通知 ({number})",
|
||||||
|
here: "此處",
|
||||||
|
Required: "必填",
|
||||||
|
telegram: "Telegram",
|
||||||
|
"Bot Token": "機器人權杖",
|
||||||
|
wayToGetTelegramToken: "您可以從 {0} 取得權杖。",
|
||||||
|
"Chat ID": "聊天 ID",
|
||||||
|
supportTelegramChatID: "支援 對話/群組/頻道的聊天 ID",
|
||||||
|
wayToGetTelegramChatID: "傳送訊息給機器人,並前往以下網址以取得您的 chat ID:",
|
||||||
|
"YOUR BOT TOKEN HERE": "在此填入您的機器人權杖",
|
||||||
|
chatIDNotFound: "找不到 Chat ID;請先傳送訊息給機器人",
|
||||||
|
webhook: "Webhook",
|
||||||
|
"Post URL": "Post 網址",
|
||||||
|
"Content Type": "內容類型",
|
||||||
|
webhookJsonDesc: "{0} 適合任何現代的 HTTP 伺服器,如 Express.js",
|
||||||
|
webhookFormDataDesc: "{multipart} 適合 PHP。 JSON 必須先經由 {decodeFunction} 剖析。",
|
||||||
|
smtp: "Email (SMTP)",
|
||||||
|
secureOptionNone: "無 / STARTTLS (25, 587)",
|
||||||
|
secureOptionTLS: "TLS (465)",
|
||||||
|
"Ignore TLS Error": "忽略 TLS 錯誤",
|
||||||
|
"From Email": "寄件人",
|
||||||
|
emailCustomSubject: "自訂主旨",
|
||||||
|
"To Email": "收件人",
|
||||||
|
smtpCC: "CC",
|
||||||
|
smtpBCC: "BCC",
|
||||||
|
discord: "Discord",
|
||||||
|
"Discord Webhook URL": "Discord Webhook 網址",
|
||||||
|
wayToGetDiscordURL: "您可以前往伺服器設定 -> 整合 -> Webhook -> 新 Webhook 以取得",
|
||||||
|
"Bot Display Name": "機器人顯示名稱",
|
||||||
|
"Prefix Custom Message": "前綴自訂訊息",
|
||||||
|
"Hello @everyone is...": "Hello {'@'}everyone is...",
|
||||||
|
teams: "Microsoft Teams",
|
||||||
|
"Webhook URL": "Webhook 網址",
|
||||||
|
wayToGetTeamsURL: "您可以前往此頁面以了解如何建立 Webhook 網址 {0}。",
|
||||||
|
signal: "Signal",
|
||||||
|
Number: "號碼",
|
||||||
|
Recipients: "收件人",
|
||||||
|
needSignalAPI: "您需要有 REST API 的 Signal 客戶端。",
|
||||||
|
wayToCheckSignalURL: "您可以前往下列網址以了解如何設定:",
|
||||||
|
signalImportant: "注意: 不得混合收件人的群組和號碼!",
|
||||||
|
gotify: "Gotify",
|
||||||
|
"Application Token": "應用程式權杖",
|
||||||
|
"Server URL": "伺服器網址",
|
||||||
|
Priority: "優先度",
|
||||||
|
slack: "Slack",
|
||||||
|
"Icon Emoji": "Emoji 圖示",
|
||||||
|
"Channel Name": "頻道名稱",
|
||||||
|
"Uptime Kuma URL": "Uptime Kuma 網址",
|
||||||
|
aboutWebhooks: "更多關於 Webhook 的資訊: {0}",
|
||||||
|
aboutChannelName: "如果您不想使用 Webhook 頻道,請在 {0} 頻道名稱欄位填入您想使用的頻道。例如: #其他頻道",
|
||||||
|
aboutKumaURL: "如果您未填入 Uptime Kuma 網址。將預設使用專案 Github 頁面。",
|
||||||
|
emojiCheatSheet: "Emoji 一覽表: {0}",
|
||||||
|
"rocket.chat": "Rocket.Chat",
|
||||||
|
pushover: "Pushover",
|
||||||
|
pushy: "Pushy",
|
||||||
|
octopush: "Octopush",
|
||||||
|
promosms: "PromoSMS",
|
||||||
|
clicksendsms: "ClickSend SMS",
|
||||||
|
lunasea: "LunaSea",
|
||||||
|
apprise: "Apprise (支援 50 種以上的通知服務)",
|
||||||
|
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": "簡訊類型",
|
||||||
|
octopushTypePremium: "Premium (快速 - 建議用於警報)",
|
||||||
|
octopushTypeLowCost: "Low Cost (緩慢 - 有時會被營運商阻擋)",
|
||||||
|
checkPrice: "查看 {0} 價格:",
|
||||||
|
apiCredentials: "API 認證",
|
||||||
|
octopushLegacyHint: "您使用的是舊版的 Octopush (2011-2020) 還是新版?",
|
||||||
|
"Check octopush prices": "查看 octopush 價格 {0}。",
|
||||||
|
octopushPhoneNumber: "電話號碼 (intl 格式,例如:+33612345678) ",
|
||||||
|
octopushSMSSender: "簡訊寄件人名稱:3-11位英數字元及空白 (a-zA-Z0-9)",
|
||||||
|
"LunaSea Device ID": "LunaSea 裝置 ID",
|
||||||
|
"Apprise URL": "Apprise 網址",
|
||||||
|
"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": "Messaging API",
|
||||||
|
wayToGetLineChannelToken: "首先,前往 {0},建立 provider 和 channel (Messaging API)。接著您就可以從上面提到的選單項目中取得頻道存取權杖及使用者 ID。",
|
||||||
|
"Icon URL": "圖示網址",
|
||||||
|
aboutIconURL: "您可以在 \"圖示網址\" 中提供圖片網址以覆蓋預設個人檔案圖片。若已設定 Emoji 圖示,將忽略此設定。",
|
||||||
|
aboutMattermostChannelName: "您可以在 \"頻道名稱\" 欄位中填寫頻道名稱以覆蓋 Webhook 的預設頻道。必須在 Mattermost 的 Webhook 設定中啟用。例如:#其他頻道",
|
||||||
|
matrix: "Matrix",
|
||||||
|
promosmsTypeEco: "SMS ECO - 便宜,但是很慢且經常過載。僅限位於波蘭的收件人。",
|
||||||
|
promosmsTypeFlash: "SMS FLASH - 訊息會自動在收件人的裝置上顯示。僅限位於波蘭的收件人。",
|
||||||
|
promosmsTypeFull: "SMS FULL - 高級版,您可以使用您的寄件人名稱 (必須先註冊名稱。對於警報來說十分可靠。",
|
||||||
|
promosmsTypeSpeed: "SMS SPEED - 系統中的最高優先度。快速、可靠,但昂貴 (約 SMS FULL 的兩倍價格)。",
|
||||||
|
promosmsPhoneNumber: "電話號碼 (若收件人位於波蘭則無需輸入區域代碼)",
|
||||||
|
promosmsSMSSender: "簡訊寄件人名稱:預先註冊的名稱或以下的預設名稱:InfoSMS、SMS Info、MaxSMS、INFO、SMS",
|
||||||
|
"Feishu WebHookUrl": "飛書 WebHook 網址",
|
||||||
|
matrixHomeserverURL: "Homeserver 網址 (開頭為 http(s)://,結尾可能帶連接埠)",
|
||||||
|
"Internal Room Id": "Internal Room ID",
|
||||||
|
matrixDesc1: "您可以在 Matrix 客戶端的房間設定中的進階選項找到 internal room ID。應該看起來像 !QMdRCpUIfLwsfjxye6:home.server。",
|
||||||
|
matrixDesc2: "使用您自己的 Matrix 使用者存取權杖將賦予存取您的帳號和您加入的房間的完整權限。建議建立新使用者,並邀請至您想要接收通知的房間中。您可以執行 {0} 以取得存取權杖",
|
||||||
|
Method: "方法",
|
||||||
|
Body: "主體",
|
||||||
|
Headers: "標頭",
|
||||||
|
PushUrl: "Push URL",
|
||||||
|
HeadersInvalidFormat: "要求標頭不是有效的 JSON:",
|
||||||
|
BodyInvalidFormat: "請求主體不是有效的 JSON:",
|
||||||
|
"Monitor History": "監測器歷史紀錄",
|
||||||
|
clearDataOlderThan: "保留 {0} 天內的監測器歷史紀錄。",
|
||||||
|
PasswordsDoNotMatch: "密碼不相符。",
|
||||||
|
records: "記錄",
|
||||||
|
"One record": "一項記錄",
|
||||||
|
"Showing {from} to {to} of {count} records": "正在顯示 {count} 項記錄中的 {from} 至 {to} 項",
|
||||||
|
steamApiKeyDescription: "若要監測 Steam 遊戲伺服器,您將需要 Steam Web-API 金鑰。您可以在此註冊您的 API 金鑰:",
|
||||||
|
"Current User": "目前使用者",
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user