Compare commits

..

145 Commits

Author SHA1 Message Date
Louis Lam
6d4a45f18c Update to 1.23.5 2023-11-18 01:23:53 +08:00
Louis Lam
f0975cd929 Should be a final ulitmate fix for request timeout issue (#4045)
* Try to fix timeout again

* Ops
2023-11-18 01:17:54 +08:00
Louis Lam
40d6a21453 Fix kafka migration script again (#4043) 2023-11-17 15:21:29 +08:00
Louis Lam
b383392e8f Remains Node.js 16' SSL behavior for 1.23.X (#4044) 2023-11-17 15:21:08 +08:00
Nelson Chan
9964b6c4d8 Fix: Update monitor object on pause (#4032) 2023-11-16 20:41:35 +08:00
Louis Lam
d56bf08cd7 Update to 1.23.4 2023-11-13 15:23:32 +08:00
Louis Lam
291d5d7c55 Update dependencies 2023-11-13 15:22:51 +08:00
Louis Lam
8e3ff25f7b Followup #3864, rebase for 1.23.x (#4016)
* Fix: Use ActionSelect Docker Host & validate input

* Fix: Handle docker host deleted while editing

* UI: Use add for ActionSelect & prevent delete instead

---------

Co-authored-by: Nelson Chan <chakflying@hotmail.com>
2023-11-12 20:32:40 +08:00
Louis Lam
6e80c850f4 Should be an ulitmate fix for request timeout issue (#4011) 2023-11-12 13:50:51 +08:00
Muhammed Hussein karimi
0608881954 🐛 fix: kafka producer booleans migration null values (#3984)
Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>
2023-11-10 00:32:54 +08:00
Nelson Chan
38efd97b28 Fix: Support float ping in push route (#3987) 2023-11-09 23:39:44 +08:00
Louis Lam
ce0ba6c0ca Fix/axios abort signal for 1.23.X (#3971)
* Fix: Add axios abort signal

* Chore: Fix comment

---------

Co-authored-by: Nelson Chan <chakflying@hotmail.com>
2023-11-01 10:10:48 +08:00
Louis Lam
c43223a16d Restart running monitors if no heartbeat (#3952) 2023-11-01 09:36:12 +08:00
Muhammed Hussein karimi
9f170a68d7 🐛 fix: boolean fields in kafka producer monitor (#3949)
* 🐛 fix: boolean fields in kafka producer monitor

Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>

* 🐛 fix: boolean fields db patch table modify

Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>

* ✏️  typo: remove `_old` COLUMNs in patch-fix-kafka-producer-booleans

Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>

---------

Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>
2023-10-28 14:42:55 +08:00
Louis Lam
1a862e47ab Check if the password changed when user is not null 2023-10-23 06:21:39 +08:00
Nelson Chan
e64bf0e3fe Fix: Stop notification check on root certs (#3874)
* Fix: Stop notification check on root certs

* Chore: Use Set for optimization

* Fix: Manually calculate SHA256 to support node v14
2023-10-16 02:20:38 +08:00
Louis Lam
523d137e2b Lint 2023-10-16 00:43:07 +08:00
Louis Lam
18169c59a1 [MySQL monitor] Split password into a standalone field (#3899) 2023-10-16 00:38:56 +08:00
Louis Lam
4ccf263481 Update docker image base from Node.js 16 to Node.js 18 for Uptime Kuma v1 (#3901) 2023-10-16 00:27:47 +08:00
Louis Lam
1c13a75970 Fix #3868 postgres monitor could possibly crash Uptime Kuma (#3880)
* Bump pg

* Handle uncaughtException

* Fix parsing issue of postgres connection and fix the query example
2023-10-13 02:50:10 +08:00
Louis Lam
c3e3f27457 Update to 1.23.3 2023-10-09 20:26:18 +08:00
Louis Lam
794f1810bf Minor 2023-10-09 20:09:29 +08:00
Louis Lam
168357d93c Update dependencies 2023-10-09 20:05:50 +08:00
Louis Lam
476deb9fec Pin npm@9 2023-10-09 07:33:52 +08:00
Louis Lam
a36f2a75ca Enable auto-test for 1.23.X branch 2023-10-09 07:23:30 +08:00
Louis Lam
88afab6571 Merge pull request from GHSA-g9v2-wqcj-j99g
* Fix attempt

* Update message
2023-10-09 07:01:54 +08:00
Nelson Chan
bd9c44cccf Fix: Disable status page saving before getData 2023-10-09 06:41:07 +08:00
前端小武
1b148786a5 Fix: Update x-forwarded-host field when using reverse proxy (#3726) 2023-10-09 06:31:52 +08:00
Louis Lam
66a10b8993 Pump gamedig from 4.0.X to 4.1.X and update dependencies 2023-10-03 04:51:02 +08:00
Muhammed Hussein karimi
2ab21ccf8a 🐛 fix: kafka producer bugs (#3771)
* 🐛 fix: missing Kafka Producer SSL option in frontend object

Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>

* ♻️  refactor: better error handling of kafka producer

Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>

---------

Signed-off-by: Muhammed Hussein Karimi <info@karimi.dev>
2023-09-24 03:30:15 +08:00
Marvin A. Ruder
90d0e8ccde Enable status page certificate expiry badge for all HTTP(s) monitors (#3649) 2023-09-24 03:18:18 +08:00
Louis Lam
16a396debb Similar to #3763, but for 1.23.3 2023-09-21 20:38:54 +08:00
Louis Lam
6b3d69e1d3 Ignore /extra/healthcheck-armv7 2023-09-18 03:59:56 +08:00
Louis Lam
b3b8e9f3a0 Update to 1.23.2 2023-09-18 03:04:29 +08:00
Louis Lam
e5345848a2 Update dependencies 2023-09-18 03:01:58 +08:00
FC (Fay) Stegerman
d8a8f6c08b EditMonitor: add missing config UI for json-query (#3751) 2023-09-17 20:39:07 +08:00
Louis Lam
f98a1ce077 Ignore some build files 2023-09-17 20:32:49 +08:00
Louis Lam
86fa57449e Fix #3596 2023-09-17 02:56:19 +08:00
Louis Lam
ff51704cdf Fix #3712 2023-09-17 02:40:08 +08:00
Henrik Gerdes
33804d8823 fix: respect the user defined oauth2 auth method (#3727) 2023-09-16 05:13:20 +08:00
Nelson Chan
1e12ca4786 Fix: Disable save button on submit (#3729) 2023-09-16 05:11:18 +08:00
Nelson Chan
0af4ee6c34 Fix: Missing await for isActive (#3717) 2023-09-10 01:54:03 +08:00
ZaneL1u
1f29fabe64 fix: fix the judgment condition of Tailscale (#3701) 2023-09-07 16:15:21 +08:00
Louis Lam
c4e222d1e6 Update README.md 2023-08-29 20:49:03 +08:00
Louis Lam
f2a1c26ef8 Update to 1.23.1 2023-08-29 03:52:53 +08:00
Louis Lam
8772baad9a Update dependencies 2023-08-29 03:39:47 +08:00
Louis Lam
215c89e8d3 Merge pull request #3612 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations Update from Weblate
2023-08-29 03:09:48 +08:00
Unai Tolosa Pontesta
e6a055af19 Translated using Weblate (Basque)
Currently translated at 68.9% (557 of 808 strings)

Co-authored-by: Unai Tolosa Pontesta <utolosa002@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/eu/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
Yoswaris Lawpaiboon
88d71d2c7a Translated using Weblate (Thai)
Currently translated at 79.9% (646 of 808 strings)

Co-authored-by: Yoswaris Lawpaiboon <konglha19@outlook.co.th>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
Mirinek
cd2d5325df Translated using Weblate (Slovak)
Currently translated at 26.7% (216 of 808 strings)

Co-authored-by: Mirinek <mirek.nozicka77@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sk/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
AlwaleedAlwabel
75a1245b70 Translated using Weblate (Arabic)
Currently translated at 83.9% (678 of 808 strings)

Co-authored-by: AlwaleedAlwabel <xomsd1@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ar/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
DevMirza
f666eb6d83 Translated using Weblate (Urdu)
Currently translated at 59.1% (478 of 808 strings)

Co-authored-by: DevMirza <pzhafeez@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
Haim Cohen
cb10643f57 Translated using Weblate (Hebrew (Israel))
Currently translated at 87.6% (708 of 808 strings)

Co-authored-by: Haim Cohen <haim1979@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/he_IL/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
Wishw
c9ba4e7e8b Translated using Weblate (Telugu)
Currently translated at 23.3% (189 of 808 strings)

Added translation using Weblate (Telugu)

Co-authored-by: Wishw <62600445+Wisw@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/te/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
stanol
94187bca5d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
Matteo Mazzoni
39b4aa5966 Translated using Weblate (Italian)
Currently translated at 73.0% (590 of 808 strings)

Co-authored-by: Matteo Mazzoni <matteo@matteomazzoni.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translation: Uptime Kuma/Uptime Kuma
2023-08-28 08:15:57 +00:00
Louis Lam
cd79df07e1 Add an ability to enable/disable nscd (#3652) 2023-08-28 16:15:48 +08:00
Louis Lam
0c40f02584 Put Monitor Group under Advanced section 2023-08-28 04:59:47 +08:00
Nelson Chan
db42c13e05 Fix: Remove legacy unused tags cleanup (#3651) 2023-08-27 18:56:50 +08:00
Nelson Chan
5f85d8f749 Fix: Focus & styling on safari (#3650) 2023-08-27 18:55:36 +08:00
Lior Slakman
c0e273df5b Show hostname:port for gamedig monitor on Discord notification (#3643) 2023-08-27 02:24:33 +08:00
Nelson Chan
4da1341aa5 Fix: Improve dnsMessage handling (#3614) 2023-08-26 21:27:32 +08:00
James Osborn
e765e6a1b8 Spelling & Grammar updates (#3638)
* Spelling & Grammar updates to SECURITY.md

No policy changes were made in this change, only improving readability.

* Spelling & Grammar updates to README.md

No policy changes were made in this change, only improving readability.

* Spelling & Grammar updates to CONTRIBUTING.md

No policy changes were made in this change, only improving readability.
2023-08-25 00:01:47 +08:00
bt90
eee9a1f004 Passwordmanager friendly inputs (#3593)
* Mark username/password inputs as required

* Mark 2FA input as required

* Add autocomplete attributes

* Add autocomplete suggestion to password change

* Add autocomplete to 2FA dialog

* Mark 2fa input as required
2023-08-21 02:25:35 +08:00
Frank Elsinga
4d07b65bdd fixed local docker not working anymore (#3606) 2023-08-20 04:45:58 +08:00
Frank Elsinga
1772158d62 fixed opsgenieRegion not being the same enum between the frontend and backend (#3616) 2023-08-20 04:41:42 +08:00
Frank Elsinga
7bfdb82f5d bug: fixed the curser being a pointer if hovering above the dropdown-item's (#3607)
* fixed the curser being a pointer if hovering above the `dropdown-item`'s

* formatting fix
2023-08-20 04:40:12 +08:00
Frank Elsinga
8945316ce6 added helptexs to the installation script (#3603) 2023-08-20 03:01:37 +08:00
Louis Lam
9564550d5f Update to 1.23.0 2023-08-17 22:30:28 +08:00
Louis Lam
a78e7a423e Merge pull request #3569 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations Update from Weblate
2023-08-17 22:02:41 +08:00
Alex Javadi
9dddd0b657 Translated using Weblate (Persian)
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: Alex Javadi <15309978+aljvdi@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2023-08-16 11:16:35 +00:00
astroking362
d04d86d74e Translated using Weblate (Portuguese)
Currently translated at 4.5% (37 of 808 strings)

Co-authored-by: astroking362 <astroking362@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt/
Translation: Uptime Kuma/Uptime Kuma
2023-08-16 11:16:35 +00:00
ITQ
eb11c18203 Translated using Weblate (Russian)
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: ITQ <itq.dev@ya.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-08-16 11:16:35 +00:00
Harry Suryapambagya
3da2d78ad9 Translated using Weblate (Indonesian)
Currently translated at 93.9% (759 of 808 strings)

Co-authored-by: Harry Suryapambagya <harsxv@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translation: Uptime Kuma/Uptime Kuma
2023-08-16 11:16:35 +00:00
Buchtič
2b4ec765ff Translated using Weblate (Czech)
Currently translated at 100.0% (808 of 808 strings)

Co-authored-by: Buchtič <martin.buchta@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-08-16 11:16:35 +00:00
losing
72dcefff76 Translated using Weblate (Slovak)
Currently translated at 26.6% (215 of 808 strings)

Co-authored-by: losing <me@losing.top>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sk/
Translation: Uptime Kuma/Uptime Kuma
2023-08-16 11:16:35 +00:00
Nelson Chan
3a894958eb Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 86.7% (701 of 808 strings)

Co-authored-by: Nelson Chan <chakflying@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-08-16 11:16:35 +00:00
Nelson Chan
fe431d6385 Chore: Run test on PR to v2 branch (#3582) 2023-08-16 16:05:52 +08:00
Louis Lam
ce0289855d Remove hard-coded node versions as upstream fixed (#3576) 2023-08-15 17:13:35 +08:00
zhenqiang
c0174dc1c4 fix(notification-aliyun-sms): throw error when sending SMS failed (#3573) 2023-08-15 04:14:28 +08:00
M1CK431
e745bd69da [webapp] Setup: translate fields placeholders (#3563) 2023-08-15 02:00:42 +08:00
UptimeKumaBot
72741ebb10 Translations Update from Weblate (#3560)
* Translated using Weblate (Portuguese)

Currently translated at 4.1% (33 of 801 strings)

Added translation using Weblate (Portuguese)

Co-authored-by: Miguel Castilho Dias <miguelcastilhodias@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Czech)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (French)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (French)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Turkish)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (German)

Currently translated at 98.3% (788 of 801 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 98.3% (788 of 801 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Spanish)

Currently translated at 91.2% (733 of 803 strings)

Co-authored-by: Jorge Sanz Sanfructuoso <sanchi2@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Spanish)

Currently translated at 91.2% (733 of 803 strings)

Co-authored-by: rubesaca <rubesaca@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (Czech)

Currently translated at 99.7% (806 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (French)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Polish)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/

* Translated using Weblate (German)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (Russian)

Currently translated at 98.2% (794 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Italian)

Currently translated at 72.8% (589 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/

* Translated using Weblate (Russian)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/

---------

Co-authored-by: Miguel Castilho Dias <miguelcastilhodias@gmail.com>
Co-authored-by: MrEddX <mreddx@chatrix.one>
Co-authored-by: Michal <black23@gmail.com>
Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Co-authored-by: stanol <stanol777@gmail.com>
Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Co-authored-by: Marco <marco@nanoweb.ch>
Co-authored-by: Jorge Sanz Sanfructuoso <sanchi2@gmail.com>
Co-authored-by: rubesaca <rubesaca@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Co-authored-by: sovushik <evgeniy@grachev.biz>
Co-authored-by: Lance <2124757129@qq.com>
Co-authored-by: diego <deiana.diego@icloud.com>
Co-authored-by: ITQ <itq.dev@ya.ru>
2023-08-12 22:37:55 +08:00
Frank Elsinga
ff88018b0c rephrased the dependency documentation (#3565) 2023-08-12 22:28:12 +08:00
Matthew Nickson
921c8f8100 Add noscript tag as stand in for #3553 (#3555)
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-08-10 19:35:13 +08:00
Louis Lam
de83863627 Update to 1.23.0-beta.1 2023-08-08 18:44:11 +08:00
Louis Lam
d7e0ff4b8c Update dependencies 2023-08-08 18:43:45 +08:00
UptimeKumaBot
112cc3d7b8 Translations Update from Weblate (#3536)
* Translated using Weblate (Portuguese)

Currently translated at 4.1% (33 of 801 strings)

Added translation using Weblate (Portuguese)

Co-authored-by: Miguel Castilho Dias <miguelcastilhodias@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Czech)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (French)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (French)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Turkish)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (German)

Currently translated at 98.3% (788 of 801 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 98.3% (788 of 801 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Spanish)

Currently translated at 91.2% (733 of 803 strings)

Co-authored-by: Jorge Sanz Sanfructuoso <sanchi2@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Spanish)

Currently translated at 91.2% (733 of 803 strings)

Co-authored-by: rubesaca <rubesaca@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (Czech)

Currently translated at 99.7% (806 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (French)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Polish)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (808 of 808 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

---------

Co-authored-by: Miguel Castilho Dias <miguelcastilhodias@gmail.com>
Co-authored-by: MrEddX <mreddx@chatrix.one>
Co-authored-by: Michal <black23@gmail.com>
Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Co-authored-by: stanol <stanol777@gmail.com>
Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Co-authored-by: Marco <marco@nanoweb.ch>
Co-authored-by: Jorge Sanz Sanfructuoso <sanchi2@gmail.com>
Co-authored-by: rubesaca <rubesaca@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2023-08-08 18:32:26 +08:00
Louis Lam
b44f6e4af2 Fix #3539 2023-08-08 18:29:48 +08:00
Louis Lam
18a2a8eb1e Update to 1.23.0-beta.0 2023-08-08 03:57:59 +08:00
Louis Lam
e9585ccbf4 Add .devcontainer to .dockerignore 2023-08-08 03:54:21 +08:00
UptimeKumaBot
5e39b0daf6 Translations Update from Weblate (#3512)
* Translated using Weblate (Portuguese)

Currently translated at 4.1% (33 of 801 strings)

Added translation using Weblate (Portuguese)

Co-authored-by: Miguel Castilho Dias <miguelcastilhodias@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Czech)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (French)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (French)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Turkish)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (803 of 803 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (801 of 801 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (German)

Currently translated at 98.3% (788 of 801 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 98.3% (788 of 801 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Spanish)

Currently translated at 91.2% (733 of 803 strings)

Co-authored-by: Jorge Sanz Sanfructuoso <sanchi2@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Spanish)

Currently translated at 91.2% (733 of 803 strings)

Co-authored-by: rubesaca <rubesaca@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma

---------

Co-authored-by: Miguel Castilho Dias <miguelcastilhodias@gmail.com>
Co-authored-by: MrEddX <mreddx@chatrix.one>
Co-authored-by: Michal <black23@gmail.com>
Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Co-authored-by: stanol <stanol777@gmail.com>
Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Co-authored-by: Marco <marco@nanoweb.ch>
Co-authored-by: Jorge Sanz Sanfructuoso <sanchi2@gmail.com>
Co-authored-by: rubesaca <rubesaca@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
2023-08-08 03:26:54 +08:00
Matthew Nickson
71fca3f0c3 Fixed #3520 Validate accepted status codes type (#3530)
* Fixed #3520 Validate accepted status codes type

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>

* Avoid crash on invalid status code

Instead of failing on an invalid status code, log the error and skip to
next.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>

---------

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-08-08 03:22:32 +08:00
Nelson Chan
2921f33c24 Feat: add givenPortOnly as gamedig option (#3532) 2023-08-08 03:14:21 +08:00
Louis Lam
4e0bb394db Minor 2023-08-08 03:10:21 +08:00
Nelson Chan
ced576feba Feat: Show elapsed time in HeartbeatBar (#3219)
* Feat: Show elapsed time in HeartbeatBar

* Chore: Fix lint

* Feat: Fix calculation & improve efficiency

* Fix: Fix getting tolerance in statusPage

* Chore: Improve comments & apply suggestions

* Optional elapsed time

---------

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2023-08-08 03:00:40 +08:00
Anders Kvist
ceb5708bfd Fix case for setting httpBodyEncoding to null - does work for http, b… (#3498)
* Fix case for setting httpBodyEncoding to null - does work for http, but not for keyword if anything else but json.

* Updating case.

* Update src/pages/EditMonitor.vue

Added suggestion from @CommanderStorm

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* Update src/pages/EditMonitor.vue

Co-authored-by: Frank Elsinga <frank@elsinga.de>

---------

Co-authored-by: Anders Kvist <ak@cego.dk>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2023-08-07 15:13:51 +08:00
Nelson Chan
23fdd32de0 Fix: filtersActive placed incorrectly (#3531) 2023-08-07 15:10:03 +08:00
Nelson Chan
36777c5eff Fix: Filtering works with group monitor (#3469)
* Fix: Filtering works with group monitor

* Chore: Update comment

* Apply suggestions from code review

Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>

---------

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-08-07 00:35:50 +08:00
Jinhyeok Lee
439b6517d1 Feat: Add http/http keyword timeout option (#2142)
* feat: Add timeoutMs field

* chore: Update Languages (incl. ko-KR)

* Revert "chore: Update Languages (incl. ko-KR)"

This reverts commit 349331a00b.

* chore: Update ko-KR selectively

* chore: Update en selectively

* Merge manually

* Reorder and show only if http related monitors

* fix: Update Korean translation

* fix: Rename timeoutMs to timeout, rename label, make DOUBLE

* fix: Change minimum step to 0.1, matching DOUBLE type

* Put the sql patch at the end

* Update EditMonitor.vue

* Colocate timeout with retry, fix clampTimeout logic, show default on 0

* Update src/pages/EditMonitor.vue to remove a comment

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* Fix merge issue

* Update the timeout value while finished editing the interval value

---------

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2023-08-07 00:14:56 +08:00
Louis Lam
c6e68fac97 Follow up #2852 (#3527) 2023-08-04 23:08:44 +08:00
Marcell Fülöp
bce4835362 FEAT: Allow client side TLS for Docker hosts (#2852)
* FEAT: Allow client side TLS for Docker hosts

Inlcude TLS certificate in HTTPS requests when certificate
files are locally available to Kuma for a host.

* fix: refactor to satisfy linter requirements

* fix: linter
2023-08-04 22:49:33 +08:00
Nelson Chan
a032e11a2e Feat: Create Group in EditMonitor page (#3379)
* Feat: Create Group in EditMonitor page

* Fix: Start group mon. after child is added

* Chore: Swap confirm & cancel for ergonomics

* Fix rarely issue that group monitor can throw an error if lastBeat is null

* Resume the group monitor in the callback

---------

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2023-08-04 14:48:21 +08:00
Louis Lam
d231a05526 Remove babel-plugin-rewire (#3522) 2023-08-04 01:10:15 +08:00
GitStart
f4967615c0 UPTM-14 - Dashboard Display on vertical 4K screen (#3451)
* Update src/pages/DashboardHome.vue

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* resolve comment

Co-authored-by: AqidaHaidari <aghida55@gmail.com>
Co-authored-by: Pascal Ojinnaka <56399504+passy4ucj@users.noreply.github.com>
Co-authored-by: Aqida <42426077+AqidaHaidari@users.noreply.github.com>

---------

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: AqidaHaidari <aghida55@gmail.com>
Co-authored-by: gitstart_bot <gitstart_bot@users.noreply.github.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Pascal Ojinnaka <56399504+passy4ucj@users.noreply.github.com>
Co-authored-by: Aqida <42426077+AqidaHaidari@users.noreply.github.com>
2023-08-03 21:07:01 +08:00
Louis Lam
67b1974718 Allow specifying DATA_DIR without a tailing slash 2023-08-03 20:54:11 +08:00
M1CK431
062e9db2a7 fix: typo in contributing guide (#3517) 2023-08-03 14:09:45 +08:00
DevMirza
90e1b4cf56 Update dependencies 2023-08-03 14:06:39 +08:00
Frank Elsinga
43698b23c6 Chore: Updated translation contributing guide (#3511)
* made the translation part of the contribution guide/Readme more clear

* made some formatting adjustments and added a few links

* fixed a typo

* Apply suggestions from code review

* Added DBeaver
2023-08-02 17:30:54 +08:00
DevMirza
f19b27c1c7 fix: readme (#3502) 2023-08-02 16:11:18 +08:00
Henrik Gerdes
42b5d30a33 feat: Implement oauth2 monitors (#3119)
* [empty commit] pull request for implement oauth2 monitor

* feat: implement oauth2 client credentials flow

* fix: auth methods clarification & error handling

* docs: fix JSdocs types and clarifications
2023-08-02 15:40:19 +08:00
Nelson Chan
cda77c1a32 Fix: Prevent race condition in toast (#3443) 2023-08-02 15:09:13 +08:00
UptimeKumaBot
157cf47d38 Translations Update from Weblate (#3318)
* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (762 of 762 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (754 of 754 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 78.1% (589 of 754 strings)

Co-authored-by: Bruno Guerreiro <brunogcarvalho@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (762 of 762 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (754 of 754 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Czech)

Currently translated at 99.8% (761 of 762 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (French)

Currently translated at 99.3% (757 of 762 strings)

Co-authored-by: Dim <DimitriDR@users.noreply.weblate.kuma.pet>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (757 of 757 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Turkish)

Currently translated at 100.0% (757 of 757 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (German)

Currently translated at 100.0% (757 of 757 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (757 of 757 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 77.9% (590 of 757 strings)

Co-authored-by: Paulo <git@pauloo27.dev>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Russian)

Currently translated at 100.0% (757 of 757 strings)

Translated using Weblate (Russian)

Currently translated at 99.7% (755 of 757 strings)

Co-authored-by: ITQ <itq.dev@ya.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Thai)

Currently translated at 85.3% (646 of 757 strings)

Co-authored-by: Yoswaris Lawpaiboon <konglha19@outlook.co.th>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Polish)

Currently translated at 99.4% (753 of 757 strings)

Co-authored-by: Tomasz Ad <djtms84@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Vietnamese)

Currently translated at 61.6% (467 of 757 strings)

Co-authored-by: Bond <xuantan97@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/vi/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Urdu)

Currently translated at 60.7% (460 of 757 strings)

Co-authored-by: DevMirza <pzhafeez@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma

* Translated using Weblate (Czech)

Currently translated at 100.0% (757 of 757 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 95.3% (722 of 757 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 95.3% (722 of 757 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/

* Translated using Weblate (Vietnamese)

Currently translated at 62.7% (475 of 757 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/vi/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (759 of 759 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (French)

Currently translated at 100.0% (759 of 759 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (759 of 759 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (German)

Currently translated at 100.0% (759 of 759 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (759 of 759 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (759 of 759 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (French)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (762 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Bulgarian)

Currently translated at 99.8% (762 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (Czech)

Currently translated at 99.6% (760 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Indonesian)

Currently translated at 81.3% (621 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/

* Translated using Weblate (Russian)

Currently translated at 99.2% (757 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Czech)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Danish)

Currently translated at 73.6% (562 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/

* Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/

* Translated using Weblate (German)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (Croatian)

Currently translated at 71.2% (544 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hr/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/

* Translated using Weblate (Portuguese (Portugal))

Currently translated at 57.0% (435 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_PT/

* Translated using Weblate (Thai)

Currently translated at 84.5% (645 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (763 of 763 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/

* Translated using Weblate (French)

Currently translated at 100.0% (767 of 767 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (767 of 767 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (767 of 767 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (767 of 767 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (Czech)

Currently translated at 99.6% (764 of 767 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Czech)

Currently translated at 99.8% (766 of 767 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (768 of 768 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (French)

Currently translated at 100.0% (768 of 768 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (768 of 768 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (768 of 768 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (770 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (French)

Currently translated at 100.0% (770 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (770 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Czech)

Currently translated at 99.8% (769 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Czech)

Currently translated at 99.8% (769 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (768 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (768 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (770 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (768 of 770 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (French)

Currently translated at 100.0% (772 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (772 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (772 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (Czech)

Currently translated at 99.8% (771 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (French)

Currently translated at 100.0% (772 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (772 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (772 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (770 of 772 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Czech)

Currently translated at 98.9% (778 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/

* Translated using Weblate (German)

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (French)

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (784 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 89.3% (702 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/

* Added translation using Weblate (Burmese)

* Translated using Weblate (Burmese)

Currently translated at 4.5% (36 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/my/

* Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/

* Translated using Weblate (German)

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (Russian)

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (786 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Burmese)

Currently translated at 11.4% (90 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/my/

* Translated using Weblate (French)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/

* Translated using Weblate (German)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (Russian)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (785 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Added translation using Weblate (Bengali)

* Translated using Weblate (English)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/

* Translated using Weblate (German)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (German)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (French)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.7% (785 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Japanese)

Currently translated at 69.5% (547 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/

* Translated using Weblate (Japanese)

Currently translated at 69.5% (547 of 786 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/

* Translated using Weblate (Czech)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/

* Translated using Weblate (German)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/

* Translated using Weblate (French)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Japanese)

Currently translated at 69.7% (549 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (787 of 787 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Czech)

Currently translated at 100.0% (790 of 790 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (French)

Currently translated at 100.0% (790 of 790 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (789 of 790 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (796 of 797 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Czech)

Currently translated at 99.7% (797 of 799 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (French)

Currently translated at 100.0% (799 of 799 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

---------

Co-authored-by: zappityzap <128872140+zappityzap@users.noreply.github.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: MrEddX <mreddx@chatrix.one>
Co-authored-by: Bruno Guerreiro <brunogcarvalho@gmail.com>
Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Co-authored-by: Michal <black23@gmail.com>
Co-authored-by: Dim <DimitriDR@users.noreply.weblate.kuma.pet>
Co-authored-by: stanol <stanol777@gmail.com>
Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Co-authored-by: Marco <marco@nanoweb.ch>
Co-authored-by: Paulo <git@pauloo27.dev>
Co-authored-by: ITQ <itq.dev@ya.ru>
Co-authored-by: Yoswaris Lawpaiboon <konglha19@outlook.co.th>
Co-authored-by: Tomasz Ad <djtms84@gmail.com>
Co-authored-by: Bond <xuantan97@gmail.com>
Co-authored-by: DevMirza <pzhafeez@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Tomy Hsieh <git@tomy.me>
Co-authored-by: melt-tscci <beta_hz@163.com>
Co-authored-by: AyanoKiru <tn0562260@gmail.com>
Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Co-authored-by: jonas <jonasriedel@pm.me>
Co-authored-by: Dikky Hardian <dikkyhardian@gmail.com>
Co-authored-by: Buchtič <martin.buchta@gmail.com>
Co-authored-by: deluxghost <deluxghost@gmail.com>
Co-authored-by: Justin Kruit <justinkruitnl@gmail.com>
Co-authored-by: Marco Li <macaty@gmail.com>
Co-authored-by: naing-htoo <nainghtoo@tnitech.net>
Co-authored-by: drshounak <contact@drshounak.com>
Co-authored-by: Simon Thiel <simon.thiel2+github@gmail.com>
Co-authored-by: Donker_Jumala <weareh0711@gmail.com>
Co-authored-by: mottcha <yuki627f@gmail.com>
2023-08-01 15:41:50 +08:00
Nelson Chan
09c6798a30 Fix: Add debounce to favicon update (#3442) 2023-08-01 15:12:17 +08:00
Damon
587d9e4781 Add Flashduty notification (#3475)
* feat: add FlashDuty notification channel

* refactor: #3475 nofify with Up or Down;
refactor code;
add en zh-hk zh-tw lang

* refactor: default select Info

* refactor: add space in word

* refactor the flashduty notification code

* refactor:compatible when Test flashduty nofication

* refactor: add function param description

* refactor: revert zh-hk zh-tw changes of flashduty
2023-08-01 02:13:04 +08:00
Frank Elsinga
ae2867e305 removed input-groups without any visual impact (#3485) 2023-07-31 23:59:12 +08:00
Louis Lam
65ffd77d35 Update dependencies 2023-07-31 18:04:20 +08:00
Louis Lam
9dd652733e Merge pull request #3467 from ngc7331/pushdeer
[reopened] feat: allow the user to configure PushDeer Server URL
2023-07-31 17:57:21 +08:00
Louis Lam
0a59fef7d8 Merge pull request #3490 from chakflying/fix/radius-retry
Fix: Incorrect radius error & retry handling
2023-07-31 17:47:26 +08:00
Louis Lam
27ce47277b Merge pull request #3357 from tarun7singh/status-page-expiry
Status page certificate expiry
2023-07-31 17:46:13 +08:00
Louis Lam
7f68e4a987 Merge remote-tracking branch 'origin/master' into status-page-expiry
# Conflicts:
#	src/lang/en.json
2023-07-31 17:30:49 +08:00
Frank Elsinga
149d08ecbb Chore: make sql monitors eazier to use (#3474)
* Fixed the sql monitor not having the query required

* Apply suggestions from code review

* added `redis` and  `mongodb` to the connectionString as requested by @chakflying
2023-07-31 17:28:39 +08:00
zappityzap
eb6167aaf1 Nostr dm notifications (#3473)
* Add nostr DM notification provider

* require crypto for node 18 compatibility

* remove whitespace

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* move closer to where it is used

* simplify success or failure logic

* don't clobber the non-alert msg

* Update server/notification-providers/nostr.js

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* polyfills required for node <= 18

* resolve linter warnings

* missing comma

* better websocket polyfill, update deprecated function

* add conditional polyfills for node versions

* lint

* use correct npm for package-lock

---------

Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2023-07-31 17:24:45 +08:00
Shaun
db66195f7d Added ability to bulk select, pause & resume (#1886)
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2023-07-31 16:24:00 +08:00
Louis Lam
59245e624d Update workflow's Node.js version to 20 (#3503) 2023-07-30 19:02:36 +08:00
Nelson Chan
c0eb0cb42c Chore: Add test radius dockerfile 2023-07-27 17:43:33 +08:00
Nelson Chan
573f158f7f Fix: incorrect radius error handling 2023-07-27 17:42:22 +08:00
Frank Elsinga
6413d4cbdf added a heltext for the nfty url helptext (#3484) 2023-07-27 00:11:18 +08:00
Adam Stachowicz
cf5a04bc5e Do not translate Android. Addendum to #2812 (#3480) 2023-07-26 19:36:47 +08:00
Louis Lam
a0203372ce Built-in nscd into the docker image (a better dns caching service) (#3472) 2023-07-24 17:04:50 +08:00
Raymond Hackley
5ccf2d23fc Fix: SMTP notification "Ignore TLS Error" option (#2999) (#3465) 2023-07-23 14:45:05 +08:00
小造xu_zh
bf68e0a7bc fix: define pushdeerlink 2023-07-21 14:11:13 +00:00
小造xu_zh
6984596568 Apply suggestions from code review
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2023-07-21 22:01:20 +08:00
小造xu_zh
f3562864ee Apply suggestions from code review
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2023-07-21 13:45:50 +00:00
Louis Lam
9058a829a1 Update install.sh (#3464) 2023-07-21 16:09:35 +08:00
小造xu_zh
0684313ec9 feat: remove blank characters and ending '/' first 2023-07-20 09:33:27 +00:00
小造xu_zh
d7e12dc92d feat: allow the user to configure PushDeer Server URL 2023-07-20 09:24:16 +00:00
SGprooo
1d9a28e9ab feat: Tailscale ping monitor (#3178)
* Add boilerplate for tailscale ping

* tailscale initial commit draft

* Refactor TailscalePing & better error handling

Split check function into two methods and added async/await syntax for readability/modularity
Switched to promise-based error handling (takes into account different types of error such as "Execution error", "Error in output", "no matching peer", and "is local Tailscale IP") and throws them as JavaScript errors.

* Minor update

* minor update (again)

* Update server/monitor-types/tailscale-ping.js

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* Update server/monitor-types/tailscale-ping.js

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* Update server/monitor-types/tailscale-ping.js

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* Update server/monitor-types/tailscale-ping.js

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* timeout revision

* JSDoc

* Removed long explainers

* eslint tailscale-ping.js --fix

* reran eslint

* Fix: Use hostname rather than url

* Fixed NaN on monitor interval

now interval value is correctly passed to runTailscalePing

* Add warning message

---------

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2023-07-19 20:58:21 +08:00
Thomas McWork
ddbf367011 Mattermost: update dead docs link (#3450) 2023-07-19 18:25:58 +08:00
Tarun Singh
50d4091ded Merge branch 'master' of https://github.com/louislam/uptime-kuma into status-page-expiry 2023-07-18 22:57:48 -04:00
Tarun Singh
f6c1b92fc6 Added http type check and tags based design 2023-07-17 02:01:10 -04:00
Tarun Singh
2e75142fe5 Bug fix and unknown days added 2023-07-13 20:50:17 -04:00
Tarun Singh
ad3ffacf45 PR comment fix 2023-07-13 20:37:21 -04:00
Tarun Singh
6f4af30701 Merge branch 'master' of https://github.com/louislam/uptime-kuma into status-page-expiry 2023-07-13 20:02:50 -04:00
Tarun Singh
b1f266ceb1 Added expiry changes to status page and fixes 2023-07-13 20:00:23 -04:00
Tarun Singh
4ea5771f97 Status page certificate expiry 2023-07-04 19:37:45 -04:00
136 changed files with 7357 additions and 2933 deletions

View File

@@ -18,6 +18,7 @@ README.md
.vscode
.eslint*
.stylelint*
/.devcontainer
/.github
yarn.lock
app.json
@@ -33,7 +34,13 @@ tsconfig.json
/ecosystem.config.js
/extra/healthcheck.exe
/extra/healthcheck
extra/exe-builder
/extra/exe-builder
/extra/push-examples
/extra/uptime-kuma-push
# Comment the following line if you want to rebuild the healthcheck binary
/extra/healthcheck-armv7
### .gitignore content (commented rules are duplicated)

View File

@@ -5,11 +5,11 @@ name: Auto Test
on:
push:
branches: [ master ]
branches: [ master, 1.23.X ]
paths-ignore:
- '*.md'
pull_request:
branches: [ master ]
branches: [ master, 1.23.X ]
paths-ignore:
- '*.md'
@@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest, ARM64]
node: [ 14, 18 ]
node: [ 14, 20 ]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
@@ -33,7 +33,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: npm install npm@latest -g
- run: npm install npm@9 -g
- run: npm install
- run: npm run build
- run: npm test
@@ -50,7 +50,7 @@ jobs:
strategy:
matrix:
os: [ ARMv7 ]
node: [ 14.21.3, 18.16.1 ]
node: [ 14, 20 ]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
@@ -61,7 +61,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: npm install npm@latest -g
- run: npm install npm@9 -g
- run: npm ci --production
check-linters:

View File

@@ -1,4 +1,4 @@
name: json-yaml-validate
name: json-yaml-validate
on:
push:
branches:
@@ -6,6 +6,7 @@ on:
pull_request:
branches:
- master
- 2.0.X
workflow_dispatch:
permissions:

View File

@@ -10,6 +10,7 @@
"color-function-notation": "legacy",
"shorthand-property-no-redundant-values": null,
"color-hex-length": null,
"declaration-block-no-redundant-longhand-properties": null
"declaration-block-no-redundant-longhand-properties": null,
"at-rule-no-unknown": null
}
}

View File

@@ -2,13 +2,13 @@
First of all, I want to thank everyone who made pull requests for Uptime Kuma. I never thought the GitHub Community would be so nice! Because of this, I also never thought that other people would actually read and edit my code. It is not very well structured or commented, sorry about that.
The project was created with vite.js (vue3). Then I created a subdirectory called "server" for server part. Both frontend and backend share the same package.json.
The project was created with vite.js (vue3). Then I created a subdirectory called "server" for the server part. Both frontend and backend share the same package.json.
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 builds into "dist" directory. The server (express.js) exposes the "dist" directory as the root of the endpoint. This is how production is working.
## Key Technical Skills
- Node.js (You should know what are promise, async/await and arrow function etc.)
- Node.js (You should know about promise, async/await and arrow function etc.)
- Socket.io
- SCSS
- Vue.js
@@ -30,24 +30,24 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
## Can I create a pull request for Uptime Kuma?
Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**. Especially for a large pull request or you don't know it will be merged or not.
Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**. Especially for a large pull request or you don't know if it will be merged or not.
Here are some references:
✅ Usually Accept:
### ✅ Usually accepted:
- Bug fix
- Security fix
- Adding notification providers
- Adding new language files (You should go to https://weblate.kuma.pet for existing languages)
- Adding new language files (see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md))
- Adding new language keys: `$t("...")`
⚠️ Discussion First
### ⚠️ Discussion required:
- Large pull requests
- New features
❌ Won't Merge
- A dedicated pr for translating existing languages (You can now translate on https://weblate.kuma.pet)
- Do not pass the auto test
### ❌ Won't be merged:
- A dedicated PR for translating existing languages (see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md))
- Do not pass the auto-test
- Any breaking changes
- Duplicated pull requests
- Buggy
@@ -61,9 +61,9 @@ The above cases may not cover all possible situations.
I (@louislam) have the final say. If your pull request does not meet my expectations, I will reject it, no matter how much time you spend on it. Therefore, it is essential to have a discussion beforehand.
I will mark your pull request in the [milestones](https://github.com/louislam/uptime-kuma/milestones), if I am plan to review and merge it.
I will assign your pull request to a [milestone](https://github.com/louislam/uptime-kuma/milestones), if I plan to review and merge it.
Also, please don't rush or ask for ETA, because I have to understand the pull request, make sure it is no breaking changes and stick to my vision of this project, especially for large pull requests.
Also, please don't rush or ask for an ETA, because I have to understand the pull request, make sure it is no breaking changes and stick to my vision of this project, especially for large pull requests.
### Recommended Pull Request Guideline
@@ -83,11 +83,11 @@ Before deep into coding, discussion first is preferred. Creating an empty pull r
## Project Styles
I personally do not like something that requires so many configurations before you can finally start the app. I hope Uptime Kuma installation could be as easy as like installing a mobile app.
I personally do not like something that requires so many configurations before you can finally start the app. I hope Uptime Kuma installation will be as easy as like installing a mobile app.
- Easy to install for non-Docker users, no native build dependency is needed (for x86_64/armv7/arm64), no extra config, no extra effort required to get it running
- Easy to install for non-Docker users, no native build dependency is needed (for x86_64/armv7/arm64), no extra config, and no extra effort required to get it running
- Single container for Docker users, no very complex docker-compose file. Just map the volume and expose the port, then good to go
- Settings should be configurable in the frontend. Environment variable is not encouraged, unless it is related to startup such as `DATA_DIR`
- Settings should be configurable in the frontend. Environment variables are discouraged, unless it is related to startup such as `DATA_DIR`
- Easy to use
- The web UI styling should be consistent and nice
@@ -106,11 +106,11 @@ I personally do not like something that requires so many configurations before y
## Tools
- Node.js >= 14
- NPM >= 8.5
- Git
- IDE that supports ESLint and EditorConfig (I am using IntelliJ IDEA)
- A SQLite GUI tool (SQLite Expert Personal is suggested)
- [`Node.js`](https://nodejs.org/) >= 14
- [`npm`](https://www.npmjs.com/) >= 8.5
- [`git`](https://git-scm.com/)
- IDE that supports [`ESLint`](https://eslint.org/) and EditorConfig (I am using [`IntelliJ IDEA`](https://www.jetbrains.com/idea/))
- A SQLite GUI tool (f.ex. [`SQLite Expert Personal`](https://www.sqliteexpert.com/download.html) or [`DBeaver Community`](https://dbeaver.io/download/))
## Install Dependencies for Development
@@ -130,7 +130,7 @@ Port `3000` and port `3001` will be used.
npm run dev
```
But sometimes, you would like to keep restart the server, but not the frontend, you can run these command in two terminals:
But sometimes, you would like to restart the server, but not the frontend, you can run these commands in two terminals:
```
npm run start-frontend-dev
npm run start-server-dev
@@ -146,13 +146,13 @@ It is mainly a socket.io app + express.js.
express.js is used for:
- entry point such as redirecting to a status page or the dashboard
- serving the frontend built files (index.html, .js and .css etc.)
- serving internal APIs of status page
- serving internal APIs of the status page
### Structure in /server/
- jobs/ (Jobs that are running in another process)
- model/ (Object model, auto mapping to the database table name)
- model/ (Object model, auto-mapping to the database table name)
- modules/ (Modified 3rd-party modules)
- monitor_types (Monitor Types)
- notification-providers/ (individual notification logic)
@@ -163,7 +163,7 @@ express.js is used for:
## Frontend Dev Server
It binds to `0.0.0.0:3000` by default. Frontend dev server is used for development only.
It binds to `0.0.0.0:3000` by default. The frontend dev server is used for development only.
For production, it is not used. It will be compiled to `dist` directory instead.
@@ -181,7 +181,7 @@ Uptime Kuma Frontend is a single page application (SPA). Most paths are handled
The router is in `src/router.js`
As you can see, most data in frontend is stored in root level, even though you changed the current router to any other pages.
As you can see, most data in the frontend is stored at the root level, even though you changed the current router to any other pages.
The data and socket logic are in `src/mixins/socket.js`.
@@ -210,15 +210,25 @@ Both frontend and backend share the same package.json. However, the frontend dep
### Update Dependencies
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 the patch release version only.
Patch release = the third digit ([Semantic Versioning](https://semver.org/))
If for maybe security reasons, a library must be updated. Then you must need to check if there are any breaking changes.
If for security / bug / other reasons, a library must be updated, breaking changes need to be checked by the person proposing the change.
## Translations
Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
Please add **all** the strings which are translatable to `src/lang/en.json` (If translation keys are omitted, they can not be translated).
**Don't include any other languages in your initial Pull-Request** (even if this is your mother tongue), to avoid merge-conflicts between weblate and `master`.
The translations can then (after merging a PR into `master`) be translated by awesome people donating their language skills.
If you want to help by translating Uptime Kuma into your language, please visit the [instructions on how to translate using weblate](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
## Spelling & Grammar
Feel free to correct the grammar in the documentation or code.
My mother language is not English and my grammar is not that great.
## Wiki

View File

@@ -1,16 +1,16 @@
<div align="center" width="100%">
<img src="./public/icon.svg" width="128" alt="" />
</div>
# Uptime Kuma
Uptime Kuma is an easy-to-use self-hosted monitoring tool.
<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>
[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam) <a href="https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/">
<img src="https://weblate.kuma.pet/widgets/uptime-kuma/-/svg-badge.svg" alt="Translation status" />
</a>
<div align="center" width="100%">
<img src="./public/icon.svg" width="128" alt="" />
</div>
Uptime Kuma is an easy-to-use self-hosted monitoring tool.
<img src="https://user-images.githubusercontent.com/1336778/212262296-e6205815-ad62-488c-83ec-a5b0d0689f7c.jpg" width="700" alt="" />
## 🥔 Live Demo
@@ -26,7 +26,7 @@ It is a temporary live demo, all data will be deleted after 10 minutes. Use the
* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / HTTP(s) Json Query / Ping / DNS Record / Push / Steam Game Server / Docker Containers
* Fancy, Reactive, Fast UI/UX
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications)
* 20 second intervals
* 20-second intervals
* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/lang)
* Multiple status pages
* Map status pages to specific domains
@@ -70,7 +70,7 @@ npm run setup
# Option 1. Try it
node server/server.js
# (Recommended) Option 2. Run in background using PM2
# (Recommended) Option 2. Run in the background using PM2
# Install PM2 if you don't have it:
npm install pm2 -g && pm2 install pm2-logrotate
@@ -93,7 +93,7 @@ pm2 save && pm2 startup
### Windows Portable (x64)
https://github.com/louislam/uptime-kuma/files/11886108/uptime-kuma-win64-portable-1.0.1.zip
https://github.com/louislam/uptime-kuma/releases/download/1.23.1/uptime-kuma-windows-x64-portable-1.23.1.zip
### Advanced Installation
@@ -109,7 +109,7 @@ https://github.com/louislam/uptime-kuma/wiki/%F0%9F%86%99-How-to-Update
## 🆕 What's Next?
I will mark requests/issues to the next milestone.
I will assign requests/issues to the next milestone.
https://github.com/louislam/uptime-kuma/milestones
@@ -184,7 +184,10 @@ If you want to report a bug or request a new feature, feel free to open a [new i
### Translations
If you want to translate Uptime Kuma into your language, please visit [Weblate Readme](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
Feel free to correct my grammar in this README, source code, or wiki, as my mother language is not English and my grammar is not that great.
## Spelling & Grammar
Feel free to correct the grammar in the documentation or code.
My mother language is not english and my grammar is not that great.
### Create Pull Requests
If you want to modify Uptime Kuma, please read this guide and follow the rules here: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md

View File

@@ -3,19 +3,19 @@
## Reporting a Vulnerability
1. Please report security issues to https://github.com/louislam/uptime-kuma/security/advisories/new.
1. Please also create a empty security issues for alerting me, as GitHub Advisory do not send a notification, I probably will miss without this. https://github.com/louislam/uptime-kuma/issues/new?assignees=&labels=help&template=security.md
1. Please also create an empty security issue to alert me, as GitHub Advisories do not send a notification, I probably will miss it without this. https://github.com/louislam/uptime-kuma/issues/new?assignees=&labels=help&template=security.md
Do not use the public issue tracker or discuss it in the public as it will cause more damage.
Do not use the public issue tracker or discuss it in public as it will cause more damage.
## Do you accept other 3rd-party bug bounty platforms?
At this moment, I DO NOT accept other bug bounty platforms, because I am not familiar with these platforms and someone have tried to send a phishing link to me by this already. To minimize my own risk, please report through GitHub Advisories only. I will ignore all 3rd-party bug bounty platforms emails.
At this moment, I DO NOT accept other bug bounty platforms, because I am not familiar with these platforms and someone has tried to send a phishing link to me by doing this already. To minimize my own risk, please report through GitHub Advisories only. I will ignore all 3rd-party bug bounty platforms emails.
## Supported Versions
### Uptime Kuma Versions
You should use or upgrade to the latest version of Uptime Kuma. All `1.X.X` versions are upgradable to the lastest version.
You should use or upgrade to the latest version of Uptime Kuma. All `1.X.X` versions are upgradable to the latest version.
### Upgradable Docker Tags

View File

@@ -4,8 +4,4 @@ if (process.env.TEST_FRONTEND) {
config.presets = [ "@babel/preset-env" ];
}
if (process.env.TEST_BACKEND) {
config.plugins = [ "babel-plugin-rewire" ];
}
module.exports = config;

View 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 status_page
ADD show_certificate_expiry BOOLEAN default 0 NOT NULL;
COMMIT;

View 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 monitor
ADD gamedig_given_port_only BOOLEAN default 1 not null;
COMMIT;

View File

@@ -0,0 +1,6 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE monitor
ADD timeout DOUBLE default 0 not null;
COMMIT;

View File

@@ -0,0 +1,34 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
-- Rename COLUMNs to another one (suffixed by `_old`)
ALTER TABLE monitor
RENAME COLUMN kafka_producer_ssl TO kafka_producer_ssl_old;
ALTER TABLE monitor
RENAME COLUMN kafka_producer_allow_auto_topic_creation TO kafka_producer_allow_auto_topic_creation_old;
-- Add correct COLUMNs
ALTER TABLE monitor
ADD COLUMN kafka_producer_ssl BOOLEAN default 0 NOT NULL;
ALTER TABLE monitor
ADD COLUMN kafka_producer_allow_auto_topic_creation BOOLEAN default 0 NOT NULL;
-- These SQL is still not fully safe. See https://github.com/louislam/uptime-kuma/issues/4039.
-- Set bring old values from `_old` COLUMNs to correct ones
-- UPDATE monitor SET kafka_producer_allow_auto_topic_creation = monitor.kafka_producer_allow_auto_topic_creation_old
-- WHERE monitor.kafka_producer_allow_auto_topic_creation_old IS NOT NULL;
-- UPDATE monitor SET kafka_producer_ssl = monitor.kafka_producer_ssl_old
-- WHERE monitor.kafka_producer_ssl_old IS NOT NULL;
-- Remove old COLUMNs
ALTER TABLE monitor
DROP COLUMN kafka_producer_allow_auto_topic_creation_old;
ALTER TABLE monitor
DROP COLUMN kafka_producer_ssl_old;
COMMIT;

View File

@@ -0,0 +1,19 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE monitor
ADD oauth_client_id TEXT default null;
ALTER TABLE monitor
ADD oauth_client_secret TEXT default null;
ALTER TABLE monitor
ADD oauth_token_url TEXT default null;
ALTER TABLE monitor
ADD oauth_scopes TEXT default null;
ALTER TABLE monitor
ADD oauth_auth_method TEXT default null;
COMMIT;

View File

@@ -0,0 +1,10 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
-- SQLite: Change the data type of the column "config" from VARCHAR to TEXT
ALTER TABLE notification RENAME COLUMN config TO config_old;
ALTER TABLE notification ADD COLUMN config TEXT;
UPDATE notification SET config = config_old;
ALTER TABLE notification DROP COLUMN config_old;
COMMIT;

7
db/patch-timeout.sql Normal file
View 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;
UPDATE monitor SET timeout = (interval * 0.8)
WHERE timeout IS NULL OR timeout <= 0;
COMMIT;

View File

@@ -1,17 +1,33 @@
# DON'T UPDATE TO node:14-bullseye-slim, see #372.
# If the image changed, the second stage image should be changed too
FROM node:16-buster-slim
# DON'T UPDATE TO bullseye-slim, see #372.
# There is no 20-buster-slim for armv7 unfortunately, 18-buster-slim is the last one for Uptime Kuma v1.
FROM node:18-buster-slim
ARG TARGETPLATFORM
WORKDIR /app
# Install Curl
# Install Apprise, add sqlite3 cli for debugging in the future, iputils-ping for ping, util-linux for setpriv
# Stupid python3 and python3-pip actually install a lot of useless things into Debian, specify --no-install-recommends to skip them, make the base even smaller than alpine!
# Specify --no-install-recommends to skip unused dependencies, make the base much smaller!
# python3* = apprise's dependencies
# sqlite3 = for debugging
# iputils-ping = for ping
# util-linux = for setpriv (Should be dropped in 2.0.0?)
# dumb-init = avoid zombie processes (#480)
# curl = for debugging
# ca-certificates = keep the cert up-to-date
# sudo = for start service nscd with non-root user
# nscd = for better DNS caching
# (pip) apprise = for notifications
RUN apt-get update && \
apt-get --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
sqlite3 iputils-ping util-linux dumb-init git curl ca-certificates && \
pip3 --no-cache-dir install apprise==1.4.0 && \
apt-get --yes --no-install-recommends install \
python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
sqlite3 \
iputils-ping \
util-linux \
dumb-init \
curl \
ca-certificates \
sudo \
nscd && \
pip3 --no-cache-dir install apprise==1.4.5 && \
rm -rf /var/lib/apt/lists/* && \
apt --yes autoremove
@@ -26,3 +42,7 @@ RUN set -eux && \
rm -rf /var/lib/apt/lists/* && \
apt --yes autoremove
# For nscd
COPY ./docker/etc/nscd.conf /etc/nscd.conf
COPY ./docker/etc/sudoers /etc/sudoers

90
docker/etc/nscd.conf Normal file
View File

@@ -0,0 +1,90 @@
#
# /etc/nscd.conf
#
# An example Name Service Cache config file. This file is needed by nscd.
#
# Legal entries are:
#
# logfile <file>
# debug-level <level>
# threads <initial #threads to use>
# max-threads <maximum #threads to use>
# server-user <user to run server as instead of root>
# server-user is ignored if nscd is started with -S parameters
# stat-user <user who is allowed to request statistics>
# reload-count unlimited|<number>
# paranoia <yes|no>
# restart-interval <time in seconds>
#
# enable-cache <service> <yes|no>
# positive-time-to-live <service> <time in seconds>
# negative-time-to-live <service> <time in seconds>
# suggested-size <service> <prime number>
# check-files <service> <yes|no>
# persistent <service> <yes|no>
# shared <service> <yes|no>
# max-db-size <service> <number bytes>
# auto-propagate <service> <yes|no>
#
# Currently supported cache names (services): passwd, group, hosts, services
#
# logfile /var/log/nscd.log
# threads 4
# max-threads 32
# server-user node
# stat-user somebody
debug-level 0
# reload-count 5
paranoia no
# restart-interval 3600
enable-cache passwd no
positive-time-to-live passwd 600
negative-time-to-live passwd 20
suggested-size passwd 211
check-files passwd yes
persistent passwd yes
shared passwd yes
max-db-size passwd 33554432
auto-propagate passwd yes
enable-cache group no
positive-time-to-live group 3600
negative-time-to-live group 60
suggested-size group 211
check-files group yes
persistent group yes
shared group yes
max-db-size group 33554432
auto-propagate group yes
enable-cache hosts yes
positive-time-to-live hosts 3600
negative-time-to-live hosts 20
suggested-size hosts 211
check-files hosts yes
persistent hosts yes
# Set shared to "no" to display stats in `nscd -g`
# Read more: https://stackoverflow.com/questions/40429245/nscdcentos7curl-0-dns-cache-hit-rate
shared hosts no
max-db-size hosts 33554432
enable-cache services no
positive-time-to-live services 28800
negative-time-to-live services 20
suggested-size services 211
check-files services yes
persistent services yes
shared services yes
max-db-size services 33554432
enable-cache netgroup no
positive-time-to-live netgroup 28800
negative-time-to-live netgroup 20
suggested-size netgroup 211
check-files netgroup yes
persistent netgroup yes
shared netgroup yes
max-db-size netgroup 33554432

31
docker/etc/sudoers Normal file
View File

@@ -0,0 +1,31 @@
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
root ALL=(ALL:ALL) ALL
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
# Allow `node` to control service (mainly for nscd)
node ALL=(root) NOPASSWD: /usr/sbin/nscdservice
node ALL=(root) NOPASSWD: /usr/sbin/service

View File

@@ -5,15 +5,15 @@
// curl -o kuma_install.sh https://raw.githubusercontent.com/louislam/uptime-kuma/master/install.sh && sudo bash kuma_install.sh
println("=====================");
println("Uptime Kuma Installer");
println("Uptime Kuma Install Script");
println("=====================");
println("Supported OS: CentOS 7/8, Ubuntu >= 16.04 and Debian");
println("Supported OS: Ubuntu >= 16.04, Debian and CentOS/RHEL 7/8");
println("---------------------------------------");
println("This script is designed for Linux and basic usage.");
println("For advanced usage, please go to https://github.com/louislam/uptime-kuma/wiki/Installation");
println("---------------------------------------");
println("");
println("Local - Install Uptime Kuma in your current machine with git, Node.js 14 and pm2");
println("Local - Install Uptime Kuma on your current machine with git, Node.js and pm2");
println("Docker - Install Uptime Kuma Docker container");
println("");
@@ -29,14 +29,10 @@ function checkNode() {
bash("nodeVersion=$(node -e 'console.log(process.versions.node.split(`.`)[0])')");
println("Node Version: " ++ nodeVersion);
if (nodeVersion < "12") {
if (nodeVersion <= "12") {
println("Error: Required Node.js 14");
call("exit", "1");
}
if (nodeVersion == "12") {
println("Warning: NodeJS " ++ nodeVersion ++ " is not tested.");
}
}
function deb() {
@@ -60,8 +56,8 @@ function deb() {
bash("apt --yes install curl");
}
println("Installing Node.js 14");
bash("curl -sL https://deb.nodesource.com/setup_14.x | bash - > log.txt");
println("Installing Node.js 16");
bash("curl -sL https://deb.nodesource.com/setup_16.x | bash - > log.txt");
bash("apt --yes install nodejs");
bash("node -v");
@@ -91,6 +87,10 @@ if (type == "local") {
bash("os=$(head -n1 /etc/issue | cut -f 1 -d ' ')");
if (os == "Ubuntu") {
distribution = "ubuntu";
// Get ubuntu version
bash(". /etc/lsb-release");
version = DISTRIB_RELEASE;
}
if (os == "Debian") {
distribution = "debian";
@@ -101,6 +101,7 @@ if (type == "local") {
println("Your OS: " ++ os);
println("Distribution: " ++ distribution);
println("Version: " ++ version);
println("Arch: " ++ arch);
if ("$3" != "") {
@@ -131,15 +132,32 @@ if (type == "local") {
checkNode();
} else {
bash("curlCheck=$(curl --version)");
if (curlCheck == "") {
println("Installing Curl");
bash("yum -y -q install curl");
bash("dnfCheck=$(dnf --version)");
// Use yum
if (dnfCheck == "") {
bash("curlCheck=$(curl --version)");
if (curlCheck == "") {
println("Installing Curl");
bash("yum -y -q install curl");
}
println("Installing Node.js 16");
bash("curl -sL https://rpm.nodesource.com/setup_16.x | bash - > log.txt");
bash("yum install -y -q nodejs");
} else {
bash("curlCheck=$(curl --version)");
if (curlCheck == "") {
println("Installing Curl");
bash("dnf -y install curl");
}
println("Installing Node.js 16");
bash("curl -sL https://rpm.nodesource.com/setup_16.x | bash - > log.txt");
bash("dnf install -y nodejs");
}
println("Installing Node.js 14");
bash("curl -sL https://rpm.nodesource.com/setup_14.x | bash - > log.txt");
bash("yum install -y -q nodejs");
bash("node -v");
bash("nodeCheckAgain=$(node -v)");
@@ -171,13 +189,15 @@ if (type == "local") {
bash("check=$(git --version)");
if (check == "") {
error = 1;
println("Error: git is missing");
println("Error: git is not found!");
println("help: an installation guide is available at https://git-scm.com/book/en/v2/Getting-Started-Installing-Git");
}
bash("check=$(node -v)");
if (check == "") {
error = 1;
println("Error: node is missing");
println("Error: node is not found");
println("help: an installation guide is available at https://nodejs.org/en/download");
}
if (error > 0) {
@@ -193,6 +213,15 @@ if (type == "local") {
bash("pm2 startup");
}
// Check again
bash("check=$(pm2 --version)");
if (check == "") {
println("Error: pm2 is not found!");
println("help: an installation guide is available at https://pm2.keymetrics.io/docs/usage/quick-start/");
bash("exit 1");
}
bash("mkdir -p $installPath");
bash("cd $installPath");
bash("git clone https://github.com/louislam/uptime-kuma.git .");
@@ -206,6 +235,7 @@ if (type == "local") {
bash("check=$(docker -v)");
if (check == "") {
println("Error: docker is not found!");
println("help: an installation guide is available at https://docs.docker.com/desktop/");
bash("exit 1");
}
@@ -213,6 +243,7 @@ if (type == "local") {
bash("if [[ \"$check\" == *\"Is the docker daemon running\"* ]]; then
\"echo\" \"Error: docker is not running\"
\"echo\" \"help: a troubleshooting guide is available at https://docs.docker.com/config/daemon/troubleshoot/\"
\"exit\" \"1\"
fi");

View File

@@ -9,8 +9,24 @@
<meta name="theme-color" id="theme-color" content="" />
<meta name="description" content="Uptime Kuma monitoring tool" />
<title>Uptime Kuma</title>
<style>
.noscript-message {
font-size: 20px;
text-align: center;
padding: 10px;
max-width: 500px;
margin: 0 auto;
}
</style>
</head>
<body>
<noscript>
<div class="noscript-message">
Sorry, you don't seem to have JavaScript enabled or your browser
doesn't support it.<br />This website requires JavaScript to function.
Please enable JavaScript in your browser settings to continue.
</div>
</noscript>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>

View File

@@ -3,15 +3,15 @@
# The command is working on Windows PowerShell and Docker for Windows only.
# curl -o kuma_install.sh https://raw.githubusercontent.com/louislam/uptime-kuma/master/install.sh && sudo bash kuma_install.sh
"echo" "-e" "====================="
"echo" "-e" "Uptime Kuma Installer"
"echo" "-e" "Uptime Kuma Install Script"
"echo" "-e" "====================="
"echo" "-e" "Supported OS: CentOS 7/8, Ubuntu >= 16.04 and Debian"
"echo" "-e" "Supported OS: Ubuntu >= 16.04, Debian and CentOS/RHEL 7/8"
"echo" "-e" "---------------------------------------"
"echo" "-e" "This script is designed for Linux and basic usage."
"echo" "-e" "For advanced usage, please go to https://github.com/louislam/uptime-kuma/wiki/Installation"
"echo" "-e" "---------------------------------------"
"echo" "-e" ""
"echo" "-e" "Local - Install Uptime Kuma in your current machine with git, Node.js 14 and pm2"
"echo" "-e" "Local - Install Uptime Kuma on your current machine with git, Node.js and pm2"
"echo" "-e" "Docker - Install Uptime Kuma Docker container"
"echo" "-e" ""
if [ "$1" != "" ]; then
@@ -25,12 +25,9 @@ function checkNode {
nodeVersion=$(node -e 'console.log(process.versions.node.split(`.`)[0])')
"echo" "-e" "Node Version: ""$nodeVersion"
_0="12"
if [ $(($nodeVersion < $_0)) == 1 ]; then
if [ $(($nodeVersion <= $_0)) == 1 ]; then
"echo" "-e" "Error: Required Node.js 14"
"exit" "1"
fi
if [ "$nodeVersion" == "12" ]; then
"echo" "-e" "Warning: NodeJS ""$nodeVersion"" is not tested."
fi
}
function deb {
@@ -50,8 +47,8 @@ fi
"echo" "-e" "Installing Curl"
apt --yes install curl
fi
"echo" "-e" "Installing Node.js 14"
curl -sL https://deb.nodesource.com/setup_14.x | bash - > log.txt
"echo" "-e" "Installing Node.js 16"
curl -sL https://deb.nodesource.com/setup_16.x | bash - > log.txt
apt --yes install nodejs
node -v
nodeCheckAgain=$(node -v)
@@ -75,7 +72,10 @@ if [ "$type" == "local" ]; then
if [ -e "/etc/issue" ]; then
os=$(head -n1 /etc/issue | cut -f 1 -d ' ')
if [ "$os" == "Ubuntu" ]; then
distribution="ubuntu"
distribution="ubuntu"
# Get ubuntu version
. /etc/lsb-release
version="$DISTRIB_RELEASE"
fi
if [ "$os" == "Debian" ]; then
distribution="debian"
@@ -85,6 +85,7 @@ fi
arch=$(uname -i)
"echo" "-e" "Your OS: ""$os"
"echo" "-e" "Distribution: ""$distribution"
"echo" "-e" "Version: ""$version"
"echo" "-e" "Arch: ""$arch"
if [ "$3" != "" ]; then
port="$3"
@@ -108,14 +109,27 @@ fi
if [ "$nodeCheck" != "" ]; then
"checkNode"
else
curlCheck=$(curl --version)
if [ "$curlCheck" == "" ]; then
"echo" "-e" "Installing Curl"
yum -y -q install curl
dnfCheck=$(dnf --version)
# Use yum
if [ "$dnfCheck" == "" ]; then
curlCheck=$(curl --version)
if [ "$curlCheck" == "" ]; then
"echo" "-e" "Installing Curl"
yum -y -q install curl
fi
"echo" "-e" "Installing Node.js 14"
curl -sL https://rpm.nodesource.com/setup_14.x | bash - > log.txt
yum install -y -q nodejs
"echo" "-e" "Installing Node.js 16"
curl -sL https://rpm.nodesource.com/setup_16.x | bash - > log.txt
yum install -y -q nodejs
else
curlCheck=$(curl --version)
if [ "$curlCheck" == "" ]; then
"echo" "-e" "Installing Curl"
dnf -y install curl
fi
"echo" "-e" "Installing Node.js 16"
curl -sL https://rpm.nodesource.com/setup_16.x | bash - > log.txt
dnf install -y nodejs
fi
node -v
nodeCheckAgain=$(node -v)
if [ "$nodeCheckAgain" == "" ]; then
@@ -142,12 +156,14 @@ fi
check=$(git --version)
if [ "$check" == "" ]; then
error=$((1))
"echo" "-e" "Error: git is missing"
"echo" "-e" "Error: git is not found!"
"echo" "-e" "help: an installation guide is available at https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"
fi
check=$(node -v)
if [ "$check" == "" ]; then
error=$((1))
"echo" "-e" "Error: node is missing"
"echo" "-e" "Error: node is not found"
"echo" "-e" "help: an installation guide is available at https://nodejs.org/en/download"
fi
if [ $(($error > 0)) == 1 ]; then
"echo" "-e" "Please install above missing software"
@@ -161,6 +177,13 @@ fi
"echo" "-e" "Installing PM2"
npm install pm2 -g && pm2 install pm2-logrotate
pm2 startup
fi
# Check again
check=$(pm2 --version)
if [ "$check" == "" ]; then
"echo" "-e" "Error: pm2 is not found!"
"echo" "-e" "help: an installation guide is available at https://pm2.keymetrics.io/docs/usage/quick-start/"
exit 1
fi
mkdir -p $installPath
cd $installPath
@@ -172,11 +195,13 @@ else
check=$(docker -v)
if [ "$check" == "" ]; then
"echo" "-e" "Error: docker is not found!"
"echo" "-e" "help: an installation guide is available at https://docs.docker.com/desktop/"
exit 1
fi
check=$(docker info)
if [[ "$check" == *"Is the docker daemon running"* ]]; then
"echo" "Error: docker is not running"
"echo" "help: a troubleshooting guide is available at https://docs.docker.com/config/daemon/troubleshoot/"
"exit" "1"
fi
if [ "$3" != "" ]; then

5025
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "uptime-kuma",
"version": "1.22.1",
"version": "1.23.5",
"license": "MIT",
"repository": {
"type": "git",
@@ -40,19 +40,25 @@
"build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test --target pr-test . --push",
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
"setup": "git checkout 1.22.1 && npm ci --production && npm run download-dist",
"setup": "git checkout 1.23.5 && npm ci --production && npm run download-dist",
"download-dist": "node extra/download-dist.js",
"mark-as-nightly": "node extra/mark-as-nightly.js",
"reset-password": "node extra/reset-password.js",
"remove-2fa": "node extra/remove-2fa.js",
"compile-install-script": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./extra/compile-install-script.ps1",
"test-install-script-rockylinux": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/rockylinux.dockerfile .",
"test-install-script-centos7": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/centos7.dockerfile .",
"test-install-script-alpine3": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/alpine3.dockerfile .",
"test-install-script-debian": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/debian.dockerfile .",
"test-install-script-debian-buster": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/debian-buster.dockerfile .",
"test-install-script-ubuntu": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/ubuntu.dockerfile .",
"test-install-script-ubuntu1804": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/ubuntu1804.dockerfile .",
"test-install-script-ubuntu1604": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/ubuntu1604.dockerfile .",
"test-nodejs16": "docker build --progress plain -f test/ubuntu-nodejs16.dockerfile .",
"simple-dns-server": "node extra/simple-dns-server.js",
"simple-mqtt-server": "node extra/simple-mqtt-server.js",
"simple-mongo": "docker run --rm -p 27017:27017 mongo",
"simple-postgres": "docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres",
"simple-mariadb": "docker run --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mariadb# mariadb",
"update-language-files": "cd extra/update-language-files && node index.js && cross-env-shell eslint ../../src/languages/$npm_config_language.js --fix",
"ncu-patch": "npm-check-updates -u -t patch",
"release-final": "node ./extra/test-docker.js && node extra/update-version.js && npm run build-docker && node ./extra/press-any-key.js && npm run upload-artifacts && node ./extra/update-wiki-version.js",
@@ -92,11 +98,12 @@
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
"form-data": "~4.0.0",
"gamedig": "~4.0.5",
"gamedig": "~4.1.0",
"http-graceful-shutdown": "~3.1.7",
"http-proxy-agent": "~5.0.0",
"https-proxy-agent": "~5.0.1",
"iconv-lite": "~0.6.3",
"isomorphic-ws": "^5.0.0",
"jsesc": "~3.0.2",
"jsonata": "^2.0.3",
"jsonwebtoken": "~9.0.0",
@@ -104,24 +111,25 @@
"kafkajs": "^2.2.4",
"limiter": "~2.1.0",
"liquidjs": "^10.7.0",
"mongodb": "~4.14.0",
"mongodb": "~4.17.1",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
"mysql2": "~2.3.3",
"mysql2": "~3.6.2",
"nanoid": "~3.3.4",
"node-cloudflared-tunnel": "~1.0.9",
"node-radius-client": "~1.0.0",
"nodemailer": "~6.6.5",
"nostr-tools": "^1.13.1",
"notp": "~2.0.3",
"openid-client": "^5.4.2",
"password-hash": "~1.2.2",
"pg": "~8.8.0",
"pg-connection-string": "~2.5.0",
"pg": "~8.11.3",
"pg-connection-string": "~2.6.2",
"playwright-core": "~1.35.1",
"prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.1",
"protobufjs": "~7.2.4",
"qs": "~6.10.4",
"queue": "~7.0.0",
"redbean-node": "~0.3.0",
"redis": "~4.5.1",
"semver": "~7.5.4",
@@ -130,7 +138,8 @@
"socks-proxy-agent": "6.1.1",
"tar": "~6.1.11",
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2"
"thirty-two": "~1.0.2",
"ws": "^8.13.0"
},
"devDependencies": {
"@actions/github": "~5.0.1",
@@ -147,7 +156,6 @@
"@vue/compiler-sfc": "~3.3.4",
"@vuepic/vue-datepicker": "~3.4.8",
"aedes": "^0.46.3",
"babel-plugin-rewire": "~1.2.0",
"bootstrap": "5.1.3",
"chart.js": "~4.2.1",
"chartjs-adapter-dayjs-4": "~1.0.4",
@@ -155,7 +163,7 @@
"core-js": "~3.26.1",
"cronstrue": "~2.24.0",
"cross-env": "~7.0.3",
"cypress": "^12.17.0",
"cypress": "^13.2.0",
"delay": "^5.0.0",
"dns2": "~2.0.1",
"dompurify": "~2.4.3",

View File

@@ -147,15 +147,18 @@ async function sendAPIKeyList(socket) {
async function sendInfo(socket, hideVersion = false) {
let version;
let latestVersion;
let isContainer;
if (!hideVersion) {
version = checkVersion.version;
latestVersion = checkVersion.latestVersion;
isContainer = (process.env.UPTIME_KUMA_IS_CONTAINER === "1");
}
socket.emit("info", {
version,
latestVersion,
isContainer,
primaryBaseURL: await setting("primaryBaseURL"),
serverTimezone: await server.getTimezone(),
serverTimezoneOffset: server.getTimezoneOffset(),

View File

@@ -3,6 +3,7 @@ const { R } = require("redbean-node");
const { setSetting, setting } = require("./util-server");
const { log, sleep } = require("../src/util");
const knex = require("knex");
const path = require("path");
/**
* Database & App Data Folder
@@ -25,6 +26,8 @@ class Database {
static path;
static dockerTLSDir;
/**
* @type {boolean}
*/
@@ -74,6 +77,13 @@ class Database {
"patch-add-invert-keyword.sql": true,
"patch-added-json-query.sql": true,
"patch-added-kafka-producer.sql": true,
"patch-add-certificate-expiry-status-page.sql": true,
"patch-monitor-oauth-cc.sql": true,
"patch-add-timeout-monitor.sql": true,
"patch-add-gamedig-given-port.sql": true,
"patch-notification-config.sql": true,
"patch-fix-kafka-producer-booleans.sql": true,
"patch-timeout.sql": true,
};
/**
@@ -92,23 +102,28 @@ class Database {
// Data Directory (must be end with "/")
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
Database.path = Database.dataDir + "kuma.db";
Database.path = path.join(Database.dataDir, "kuma.db");
if (! fs.existsSync(Database.dataDir)) {
fs.mkdirSync(Database.dataDir, { recursive: true });
}
Database.uploadDir = Database.dataDir + "upload/";
Database.uploadDir = path.join(Database.dataDir, "upload/");
if (! fs.existsSync(Database.uploadDir)) {
fs.mkdirSync(Database.uploadDir, { recursive: true });
}
// Create screenshot dir
Database.screenshotDir = Database.dataDir + "screenshots/";
Database.screenshotDir = path.join(Database.dataDir, "screenshots/");
if (! fs.existsSync(Database.screenshotDir)) {
fs.mkdirSync(Database.screenshotDir, { recursive: true });
}
Database.dockerTLSDir = path.join(Database.dataDir, "docker-tls/");
if (! fs.existsSync(Database.dockerTLSDir)) {
fs.mkdirSync(Database.dockerTLSDir, { recursive: true });
}
log.info("db", `Data Dir: ${Database.dataDir}`);
}

View File

@@ -2,8 +2,16 @@ const axios = require("axios");
const { R } = require("redbean-node");
const version = require("../package.json").version;
const https = require("https");
const fs = require("fs");
const path = require("path");
const Database = require("./database");
class DockerHost {
static CertificateFileNameCA = "ca.pem";
static CertificateFileNameCert = "cert.pem";
static CertificateFileNameKey = "key.pem";
/**
* Save a docker host
* @param {Object} dockerHost Docker host to save
@@ -66,16 +74,13 @@ class DockerHost {
"Accept": "*/*",
"User-Agent": "Uptime-Kuma/" + version
},
httpsAgent: new https.Agent({
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: false,
}),
};
if (dockerHost.dockerType === "socket") {
options.socketPath = dockerHost.dockerDaemon;
} else if (dockerHost.dockerType === "tcp") {
options.baseURL = DockerHost.patchDockerURL(dockerHost.dockerDaemon);
options.httpsAgent = new https.Agent(DockerHost.getHttpsAgentOptions(dockerHost.dockerType, options.baseURL));
}
let res = await axios.request(options);
@@ -111,6 +116,53 @@ class DockerHost {
}
return url;
}
/**
* Returns HTTPS agent options with client side TLS parameters if certificate files
* for the given host are available under a predefined directory path.
*
* The base path where certificates are looked for can be set with the
* 'DOCKER_TLS_DIR_PATH' environmental variable or defaults to 'data/docker-tls/'.
*
* If a directory in this path exists with a name matching the FQDN of the docker host
* (e.g. the FQDN of 'https://example.com:2376' is 'example.com' so the directory
* 'data/docker-tls/example.com/' would be searched for certificate files),
* then 'ca.pem', 'key.pem' and 'cert.pem' files are included in the agent options.
* File names can also be overridden via 'DOCKER_TLS_FILE_NAME_(CA|KEY|CERT)'.
*
* @param {String} dockerType i.e. "tcp" or "socket"
* @param {String} url The docker host URL rewritten to https://
* @return {Object}
* */
static getHttpsAgentOptions(dockerType, url) {
let baseOptions = {
maxCachedSessions: 0,
rejectUnauthorized: true
};
let certOptions = {};
let dirName = (new URL(url)).hostname;
let caPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameCA);
let certPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameCert);
let keyPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameKey);
if (dockerType === "tcp" && fs.existsSync(caPath) && fs.existsSync(certPath) && fs.existsSync(keyPath)) {
let ca = fs.readFileSync(caPath);
let key = fs.readFileSync(keyPath);
let cert = fs.readFileSync(certPath);
certOptions = {
ca,
key,
cert
};
}
return {
...baseOptions,
...certOptions
};
}
}
module.exports = {

View File

@@ -9,12 +9,12 @@ class Group extends BeanModel {
* @param {boolean} [showTags=false] Should the JSON include monitor tags
* @returns {Object}
*/
async toPublicJSON(showTags = false) {
async toPublicJSON(showTags = false, certExpiry = false) {
let monitorBeanList = await this.getMonitorList();
let monitorList = [];
for (let bean of monitorBeanList) {
monitorList.push(await bean.toPublicJSON(showTags));
monitorList.push(await bean.toPublicJSON(showTags, certExpiry));
}
return {

View File

@@ -3,10 +3,10 @@ const dayjs = require("dayjs");
const axios = require("axios");
const { Prometheus } = require("../prometheus");
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND,
SQL_DATETIME_FORMAT
SQL_DATETIME_FORMAT, isDev, sleep, getRandomInt
} = require("../../src/util");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery,
redisPingAsync, mongodbPing, kafkaProducerAsync
redisPingAsync, mongodbPing, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
} = require("../util-server");
const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model");
@@ -23,6 +23,8 @@ const Gamedig = require("gamedig");
const jsonata = require("jsonata");
const jwt = require("jsonwebtoken");
const rootCertificates = rootCertificatesFingerprints();
/**
* status:
* 0 = DOWN
@@ -37,11 +39,12 @@ class Monitor extends BeanModel {
* Only show necessary data to public
* @returns {Object}
*/
async toPublicJSON(showTags = false) {
async toPublicJSON(showTags = false, certExpiry = false) {
let obj = {
id: this.id,
name: this.name,
sendUrl: this.sendUrl,
type: this.type,
};
if (this.sendUrl) {
@@ -51,6 +54,13 @@ class Monitor extends BeanModel {
if (showTags) {
obj.tags = await this.getTags();
}
if (certExpiry && (this.type === "http" || this.type === "keyword" || this.type === "json-query") && this.getURLProtocol() === "https:") {
const { certExpiryDaysRemaining, validCert } = await this.getCertExpiry(this.id);
obj.certExpiryDaysRemaining = certExpiryDaysRemaining;
obj.validCert = validCert;
}
return obj;
}
@@ -94,6 +104,7 @@ class Monitor extends BeanModel {
active: await this.isActive(),
forceInactive: !await Monitor.isParentActive(this.id),
type: this.type,
timeout: this.timeout,
interval: this.interval,
retryInterval: this.retryInterval,
resendInterval: this.resendInterval,
@@ -126,13 +137,14 @@ class Monitor extends BeanModel {
radiusCalledStationId: this.radiusCalledStationId,
radiusCallingStationId: this.radiusCallingStationId,
game: this.game,
gamedigGivenPortOnly: this.getGameDigGivenPortOnly(),
httpBodyEncoding: this.httpBodyEncoding,
jsonPath: this.jsonPath,
expectedValue: this.expectedValue,
kafkaProducerTopic: this.kafkaProducerTopic,
kafkaProducerBrokers: JSON.parse(this.kafkaProducerBrokers),
kafkaProducerSsl: this.kafkaProducerSsl === "1" && true || false,
kafkaProducerAllowAutoTopicCreation: this.kafkaProducerAllowAutoTopicCreation === "1" && true || false,
kafkaProducerSsl: this.getKafkaProducerSsl(),
kafkaProducerAllowAutoTopicCreation: this.getKafkaProducerAllowAutoTopicCreation(),
kafkaProducerMessage: this.kafkaProducerMessage,
screenshot,
};
@@ -146,6 +158,11 @@ class Monitor extends BeanModel {
grpcMetadata: this.grpcMetadata,
basic_auth_user: this.basic_auth_user,
basic_auth_pass: this.basic_auth_pass,
oauth_client_id: this.oauth_client_id,
oauth_client_secret: this.oauth_client_secret,
oauth_token_url: this.oauth_token_url,
oauth_scopes: this.oauth_scopes,
oauth_auth_method: this.oauth_auth_method,
pushToken: this.pushToken,
databaseConnectionString: this.databaseConnectionString,
radiusUsername: this.radiusUsername,
@@ -184,6 +201,31 @@ class Monitor extends BeanModel {
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ? ORDER BY tag.name", [ this.id ]);
}
/**
* Gets certificate expiry for this monitor
* @param {number} monitorID ID of monitor to send
* @returns {Promise<LooseObject<any>>}
*/
async getCertExpiry(monitorID) {
let tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
monitorID,
]);
let tlsInfo;
if (tlsInfoBean) {
tlsInfo = JSON.parse(tlsInfoBean?.info_json);
if (tlsInfo?.valid && tlsInfo?.certInfo?.daysRemaining) {
return {
certExpiryDaysRemaining: tlsInfo.certInfo.daysRemaining,
validCert: true
};
}
}
return {
certExpiryDaysRemaining: "",
validCert: false
};
}
/**
* Encode user and password to Base64 encoding
* for HTTP "basic" auth, as per RFC-7617
@@ -241,6 +283,26 @@ class Monitor extends BeanModel {
return JSON.parse(this.accepted_statuscodes_json);
}
getGameDigGivenPortOnly() {
return Boolean(this.gamedigGivenPortOnly);
}
/**
* Parse to boolean
* @returns {boolean} Kafka Producer Ssl enabled?
*/
getKafkaProducerSsl() {
return Boolean(this.kafkaProducerSsl);
}
/**
* Parse to boolean
* @returns {boolean} Kafka Producer Allow Auto Topic Creation Enabled?
*/
getKafkaProducerAllowAutoTopicCreation() {
return Boolean(this.kafkaProducerAllowAutoTopicCreation);
}
/**
* Start monitor
* @param {Server} io Socket server instance
@@ -266,6 +328,16 @@ class Monitor extends BeanModel {
}
}
// Evil
if (isDev) {
if (process.env.EVIL_RANDOM_MONITOR_SLEEP === "SURE") {
if (getRandomInt(0, 100) === 0) {
log.debug("evil", `[${this.name}] Evil mode: Random sleep: ` + beatInterval * 10000);
await sleep(beatInterval * 10000);
}
}
}
// Expose here for prometheus update
// undefined if not https
let tlsInfo = undefined;
@@ -295,6 +367,12 @@ class Monitor extends BeanModel {
bean.duration = 0;
}
// Runtime patch timeout if it is 0
// See https://github.com/louislam/uptime-kuma/pull/3961#issuecomment-1804149144
if (!this.timeout || this.timeout <= 0) {
this.timeout = this.interval * 1000 * 0.8;
}
try {
if (await Monitor.isUnderMaintenance(this.id)) {
bean.msg = "Monitor under maintenance";
@@ -313,7 +391,10 @@ class Monitor extends BeanModel {
const lastBeat = await Monitor.getPreviousHeartbeat(child.id);
// Only change state if the monitor is in worse conditions then the ones before
if (bean.status === UP && (lastBeat.status === PENDING || lastBeat.status === DOWN)) {
// lastBeat.status could be null
if (!lastBeat) {
bean.status = PENDING;
} else if (bean.status === UP && (lastBeat.status === PENDING || lastBeat.status === DOWN)) {
bean.status = lastBeat.status;
} else if (bean.status === PENDING && lastBeat.status === DOWN) {
bean.status = lastBeat.status;
@@ -341,9 +422,28 @@ class Monitor extends BeanModel {
};
}
// OIDC: Basic client credential flow.
// Additional grants might be implemented in the future
let oauth2AuthHeader = {};
if (this.auth_method === "oauth2-cc") {
try {
if (this.oauthAccessToken === undefined || new Date(this.oauthAccessToken.expires_at * 1000) <= new Date()) {
log.debug("monitor", `[${this.name}] The oauth access-token undefined or expired. Requesting a new one`);
this.oauthAccessToken = await getOidcTokenClientCredentials(this.oauth_token_url, this.oauth_client_id, this.oauth_client_secret, this.oauth_scopes, this.oauth_auth_method);
log.debug("monitor", `[${this.name}] Obtained oauth access-token. Expires at ${new Date(this.oauthAccessToken.expires_at * 1000)}`);
}
oauth2AuthHeader = {
"Authorization": this.oauthAccessToken.token_type + " " + this.oauthAccessToken.access_token,
};
} catch (e) {
throw new Error("The oauth config is invalid. " + e.message);
}
}
const httpsAgentOptions = {
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: !this.getIgnoreTls(),
secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
};
log.debug("monitor", `[${this.name}] Prepare Options for axios`);
@@ -369,18 +469,20 @@ class Monitor extends BeanModel {
const options = {
url: this.url,
method: (this.method || "get").toLowerCase(),
timeout: this.interval * 1000 * 0.8,
timeout: this.timeout * 1000,
headers: {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"User-Agent": "Uptime-Kuma/" + version,
...(contentType ? { "Content-Type": contentType } : {}),
...(basicAuthHeader),
...(oauth2AuthHeader),
...(this.headers ? JSON.parse(this.headers) : {})
},
maxRedirects: this.maxredirects,
validateStatus: (status) => {
return checkStatusCode(status, this.getAcceptedStatuscodes());
},
signal: axiosAbortSignal(this.timeout * 1000),
};
if (bodyValue) {
@@ -515,13 +617,13 @@ class Monitor extends BeanModel {
let dnsRes = await dnsResolve(this.hostname, this.dns_resolve_server, this.port, this.dns_resolve_type);
bean.ping = dayjs().valueOf() - startTime;
if (this.dns_resolve_type === "A" || this.dns_resolve_type === "AAAA" || this.dns_resolve_type === "TXT") {
if (this.dns_resolve_type === "A" || this.dns_resolve_type === "AAAA" || this.dns_resolve_type === "TXT" || this.dns_resolve_type === "PTR") {
dnsMessage += "Records: ";
dnsMessage += dnsRes.join(" | ");
} else if (this.dns_resolve_type === "CNAME" || this.dns_resolve_type === "PTR") {
dnsMessage = dnsRes[0];
} else if (this.dns_resolve_type === "CNAME") {
dnsMessage += dnsRes[0];
} else if (this.dns_resolve_type === "CAA") {
dnsMessage = dnsRes[0].issue;
dnsMessage += dnsRes[0].issue;
} else if (this.dns_resolve_type === "MX") {
dnsRes.forEach(record => {
dnsMessage += `Hostname: ${record.exchange} - Priority: ${record.priority} | `;
@@ -539,7 +641,7 @@ class Monitor extends BeanModel {
dnsMessage = dnsMessage.slice(0, -2);
}
if (this.dnsLastResult !== dnsMessage) {
if (this.dnsLastResult !== dnsMessage && dnsMessage !== undefined) {
R.exec("UPDATE `monitor` SET dns_last_result = ? WHERE id = ? ", [
dnsMessage,
this.id
@@ -588,7 +690,7 @@ class Monitor extends BeanModel {
}
let res = await axios.get(steamApiUrl, {
timeout: this.interval * 1000 * 0.8,
timeout: this.timeout * 1000,
headers: {
"Accept": "*/*",
"User-Agent": "Uptime-Kuma/" + version,
@@ -596,6 +698,7 @@ class Monitor extends BeanModel {
httpsAgent: CacheableDnsHttpAgent.getHttpsAgent({
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: !this.getIgnoreTls(),
secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
}),
httpAgent: CacheableDnsHttpAgent.getHttpAgent({
maxCachedSessions: 0,
@@ -626,7 +729,7 @@ class Monitor extends BeanModel {
type: this.game,
host: this.hostname,
port: this.port,
givenPortOnly: true,
givenPortOnly: this.getGameDigGivenPortOnly(),
});
bean.msg = state.name;
@@ -638,8 +741,6 @@ class Monitor extends BeanModel {
} else if (this.type === "docker") {
log.debug("monitor", `[${this.name}] Prepare Options for Axios`);
const dockerHost = await R.load("docker_host", this.docker_host);
const options = {
url: `/containers/${this.docker_container}/json`,
timeout: this.interval * 1000 * 0.8,
@@ -650,16 +751,26 @@ class Monitor extends BeanModel {
httpsAgent: CacheableDnsHttpAgent.getHttpsAgent({
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: !this.getIgnoreTls(),
secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
}),
httpAgent: CacheableDnsHttpAgent.getHttpAgent({
maxCachedSessions: 0,
}),
};
const dockerHost = await R.load("docker_host", this.docker_host);
if (!dockerHost) {
throw new Error("Failed to load docker host config");
}
if (dockerHost._dockerType === "socket") {
options.socketPath = dockerHost._dockerDaemon;
} else if (dockerHost._dockerType === "tcp") {
options.baseURL = DockerHost.patchDockerURL(dockerHost._dockerDaemon);
options.httpsAgent = CacheableDnsHttpAgent.getHttpsAgent(
DockerHost.getHttpsAgentOptions(dockerHost._dockerType, options.baseURL)
);
}
log.debug("monitor", `[${this.name}] Axios Request`);
@@ -687,7 +798,7 @@ class Monitor extends BeanModel {
} else if (this.type === "sqlserver") {
let startTime = dayjs().valueOf();
await mssqlQuery(this.databaseConnectionString, this.databaseQuery);
await mssqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1");
bean.msg = "";
bean.status = UP;
@@ -726,7 +837,7 @@ class Monitor extends BeanModel {
} else if (this.type === "postgres") {
let startTime = dayjs().valueOf();
await postgresQuery(this.databaseConnectionString, this.databaseQuery);
await postgresQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1");
bean.msg = "";
bean.status = UP;
@@ -734,7 +845,11 @@ class Monitor extends BeanModel {
} else if (this.type === "mysql") {
let startTime = dayjs().valueOf();
bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery);
// Use `radius_password` as `password` field, since there are too many unnecessary fields
// TODO: rename `radius_password` to `password` later for general use
let mysqlPassword = this.radiusPassword;
bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1", mysqlPassword);
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "mongodb") {
@@ -759,29 +874,19 @@ class Monitor extends BeanModel {
port = this.port;
}
try {
const resp = await radius(
this.hostname,
this.radiusUsername,
this.radiusPassword,
this.radiusCalledStationId,
this.radiusCallingStationId,
this.radiusSecret,
port,
this.interval * 1000 * 0.8,
);
if (resp.code) {
bean.msg = resp.code;
}
bean.status = UP;
} catch (error) {
bean.status = DOWN;
if (error.response?.code) {
bean.msg = error.response.code;
} else {
bean.msg = error.message;
}
}
const resp = await radius(
this.hostname,
this.radiusUsername,
this.radiusPassword,
this.radiusCalledStationId,
this.radiusCallingStationId,
this.radiusSecret,
port,
this.interval * 1000 * 0.4,
);
bean.msg = resp.code;
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "redis") {
let startTime = dayjs().valueOf();
@@ -914,6 +1019,7 @@ class Monitor extends BeanModel {
if (! this.isStop) {
log.debug("monitor", `[${this.name}] SetTimeout for next check.`);
this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000);
this.lastScheduleBeatTime = dayjs();
} else {
log.info("monitor", `[${this.name}] isStop = true, no next check.`);
}
@@ -923,7 +1029,9 @@ class Monitor extends BeanModel {
/** Get a heartbeat and handle errors */
const safeBeat = async () => {
try {
this.lastStartBeatTime = dayjs();
await beat();
this.lastEndBeatTime = dayjs();
} catch (e) {
console.trace(e);
UptimeKumaServer.errorLog(e, false);
@@ -932,6 +1040,9 @@ class Monitor extends BeanModel {
if (! this.isStop) {
log.info("monitor", "Try to restart the monitor");
this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000);
this.lastScheduleBeatTime = dayjs();
} else {
log.info("monitor", "isStop = true, no next check.");
}
}
};
@@ -1016,6 +1127,19 @@ class Monitor extends BeanModel {
}
}
/**
* Example: http: or https:
* @returns {(null|string)}
*/
getURLProtocol() {
const url = this.getUrl();
if (url) {
return this.getUrl().protocol;
} else {
return null;
}
}
/**
* Store TLS info to database
* @param checkCertificateResult
@@ -1352,7 +1476,10 @@ class Monitor extends BeanModel {
let certInfo = tlsInfoObject.certInfo;
while (certInfo) {
let subjectCN = certInfo.subject["CN"];
if (certInfo.daysRemaining > targetDays) {
if (rootCertificates.has(certInfo.fingerprint256)) {
log.debug("monitor", `Known root cert: ${certInfo.certType} certificate "${subjectCN}" (${certInfo.daysRemaining} days valid) on ${targetDays} deadline.`);
break;
} else if (certInfo.daysRemaining > targetDays) {
log.debug("monitor", `No need to send cert notification for ${certInfo.certType} certificate "${subjectCN}" (${certInfo.daysRemaining} days valid) on ${targetDays} deadline.`);
} else {
log.debug("monitor", `call sendCertNotificationByTargetDays for ${targetDays} deadline on certificate ${subjectCN}.`);

View File

@@ -90,6 +90,8 @@ class StatusPage extends BeanModel {
* @param {StatusPage} statusPage
*/
static async getStatusPageData(statusPage) {
const config = await statusPage.toPublicJSON();
// Incident
let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [
statusPage.id,
@@ -110,13 +112,13 @@ class StatusPage extends BeanModel {
]);
for (let groupBean of list) {
let monitorGroup = await groupBean.toPublicJSON(showTags);
let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry);
publicGroupList.push(monitorGroup);
}
// Response
return {
config: await statusPage.toPublicJSON(),
config,
incident,
publicGroupList,
maintenanceList,
@@ -234,6 +236,7 @@ class StatusPage extends BeanModel {
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id,
showCertificateExpiry: !!this.show_certificate_expiry,
};
}
@@ -255,6 +258,7 @@ class StatusPage extends BeanModel {
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id,
showCertificateExpiry: !!this.show_certificate_expiry,
};
}

View File

@@ -1,6 +1,8 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
const passwordHash = require("../password-hash");
const { R } = require("redbean-node");
const jwt = require("jsonwebtoken");
const { shake256, SHAKE256_LENGTH } = require("../util-server");
class User extends BeanModel {
/**
@@ -27,6 +29,19 @@ class User extends BeanModel {
this.password = newPassword;
}
/**
* Create a new JWT for a user
* @param {User} user
* @param {string} jwtSecret
* @return {string}
*/
static createJWT(user, jwtSecret) {
return jwt.sign({
username: user.username,
h: shake256(user.password, SHAKE256_LENGTH),
}, jwtSecret);
}
}
module.exports = User;

View File

@@ -0,0 +1,95 @@
const { MonitorType } = require("./monitor-type");
const { UP, log } = require("../../src/util");
const exec = require("child_process").exec;
/**
* A TailscalePing class extends the MonitorType.
* It runs Tailscale ping to monitor the status of a specific node.
*/
class TailscalePing extends MonitorType {
name = "tailscale-ping";
/**
* Checks the ping status of the URL associated with the monitor.
* It then parses the Tailscale ping command output to update the heatrbeat.
*
* @param {Object} monitor - The monitor object associated with the check.
* @param {Object} heartbeat - The heartbeat object to update.
* @throws Will throw an error if checking Tailscale ping encounters any error
*/
async check(monitor, heartbeat) {
try {
let tailscaleOutput = await this.runTailscalePing(monitor.hostname, monitor.interval);
this.parseTailscaleOutput(tailscaleOutput, heartbeat);
} catch (err) {
log.debug("Tailscale", err);
// trigger log function somewhere to display a notification or alert to the user (but how?)
throw new Error(`Error checking Tailscale ping: ${err}`);
}
}
/**
* Runs the Tailscale ping command to the given URL.
*
* @param {string} hostname - The hostname to ping.
* @returns {Promise<string>} - A Promise that resolves to the output of the Tailscale ping command
* @throws Will throw an error if the command execution encounters any error.
*/
async runTailscalePing(hostname, interval) {
let cmd = `tailscale ping ${hostname}`;
log.debug("Tailscale", cmd);
return new Promise((resolve, reject) => {
let timeout = interval * 1000 * 0.8;
exec(cmd, { timeout: timeout }, (error, stdout, stderr) => {
// we may need to handle more cases if tailscale reports an error that isn't necessarily an error (such as not-logged in or DERP health-related issues)
if (error) {
reject(`Execution error: ${error.message}`);
return;
}
if (stderr) {
reject(`Error in output: ${stderr}`);
return;
}
resolve(stdout);
});
});
}
/**
* Parses the output of the Tailscale ping command to update the heartbeat.
*
* @param {string} tailscaleOutput - The output of the Tailscale ping command.
* @param {Object} heartbeat - The heartbeat object to update.
* @throws Will throw an eror if the output contains any unexpected string.
*/
parseTailscaleOutput(tailscaleOutput, heartbeat) {
let lines = tailscaleOutput.split("\n");
for (let line of lines) {
if (line.includes("pong from")) {
heartbeat.status = UP;
let time = line.split(" in ")[1].split(" ")[0];
heartbeat.ping = parseInt(time);
heartbeat.msg = line;
break;
} else if (line.includes("timed out")) {
throw new Error(`Ping timed out: "${line}"`);
// Immediately throws upon "timed out" message, the server is expected to re-call the check function
} else if (line.includes("no matching peer")) {
throw new Error(`Nonexistant or inaccessible due to ACLs: "${line}"`);
} else if (line.includes("is local Tailscale IP")) {
throw new Error(`Tailscale only works if used on other machines: "${line}"`);
} else if (line !== "") {
throw new Error(`Unexpected output: "${line}"`);
}
}
}
}
module.exports = {
TailscalePing,
};

View File

@@ -18,7 +18,7 @@ class AliyunSMS extends NotificationProvider {
status: this.statusToString(heartbeatJSON["status"]),
msg: heartbeatJSON["msg"],
});
if (this.sendSms(notification, msgBody)) {
if (await this.sendSms(notification, msgBody)) {
return okMsg;
}
} else {
@@ -28,7 +28,7 @@ class AliyunSMS extends NotificationProvider {
status: "",
msg: msg,
});
if (this.sendSms(notification, msgBody)) {
if (await this.sendSms(notification, msgBody)) {
return okMsg;
}
}
@@ -73,7 +73,8 @@ class AliyunSMS extends NotificationProvider {
if (result.data.Message === "OK") {
return true;
}
return false;
throw new Error(result.data.Message);
}
/**

View File

@@ -30,6 +30,7 @@ class Discord extends NotificationProvider {
break;
case "port":
case "dns":
case "gamedig":
case "steam":
address = monitorJSON["hostname"];
if (monitorJSON["port"]) {

View File

@@ -0,0 +1,98 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
const { setting } = require("../util-server");
const successMessage = "Sent Successfully.";
class FlashDuty extends NotificationProvider {
name = "FlashDuty";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
if (heartbeatJSON == null) {
const title = "Uptime Kuma Alert";
const monitor = {
type: "ping",
url: msg,
name: "https://flashcat.cloud"
};
return this.postNotification(notification, title, msg, monitor);
}
if (heartbeatJSON.status === UP) {
const title = "Uptime Kuma Monitor ✅ Up";
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, "Ok");
}
if (heartbeatJSON.status === DOWN) {
const title = "Uptime Kuma Monitor 🔴 Down";
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, notification.flashdutySeverity);
}
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
/**
* Generate a monitor url from the monitors infomation
* @param {Object} monitorInfo Monitor details
* @returns {string|undefined}
*/
genMonitorUrl(monitorInfo) {
if (monitorInfo.type === "port" && monitorInfo.port) {
return monitorInfo.hostname + ":" + monitorInfo.port;
}
if (monitorInfo.hostname != null) {
return monitorInfo.hostname;
}
return monitorInfo.url;
}
/**
* Send the message
* @param {BeanModel} notification Message title
* @param {string} title Message
* @param {string} body Message
* @param {Object} monitorInfo Monitor details
* @param {string} eventStatus Monitor status (Info, Warning, Critical, Ok)
* @returns {string}
*/
async postNotification(notification, title, body, monitorInfo, eventStatus) {
const options = {
method: "POST",
url: "https://api.flashcat.cloud/event/push/alert/standard?integration_key=" + notification.flashdutyIntegrationKey,
headers: { "Content-Type": "application/json" },
data: {
description: `[${title}] [${monitorInfo.name}] ${body}`,
title,
event_status: eventStatus || "Info",
alert_key: String(monitorInfo.id) || Math.random().toString(36).substring(7),
labels: monitorInfo?.tags?.reduce((acc, item) => ({ ...acc,
[item.name]: item.value
}), { resource: this.genMonitorUrl(monitorInfo) }),
}
};
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorInfo) {
options.client = "Uptime Kuma";
options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id);
}
let result = await axios.request(options);
if (result.status == null) {
throw new Error("FlashDuty notification failed with invalid response!");
}
if (result.status < 200 || result.status >= 300) {
throw new Error("FlashDuty notification failed with status code " + result.status);
}
if (result.statusText != null) {
return "FlashDuty notification succeed: " + result.statusText;
}
return successMessage;
}
}
module.exports = FlashDuty;

View File

@@ -0,0 +1,119 @@
const { log } = require("../../src/util");
const NotificationProvider = require("./notification-provider");
const {
relayInit,
getPublicKey,
getEventHash,
getSignature,
nip04,
nip19
} = require("nostr-tools");
// polyfills for node versions
const semver = require("semver");
const nodeVersion = process.version;
if (semver.lt(nodeVersion, "16.0.0")) {
log.warn("monitor", "Node <= 16 is unsupported for nostr, sorry :(");
} else if (semver.lt(nodeVersion, "18.0.0")) {
// polyfills for node 16
global.crypto = require("crypto");
global.WebSocket = require("isomorphic-ws");
if (typeof crypto !== "undefined" && !crypto.subtle && crypto.webcrypto) {
crypto.subtle = crypto.webcrypto.subtle;
}
} else if (semver.lt(nodeVersion, "20.0.0")) {
// polyfills for node 18
global.crypto = require("crypto");
global.WebSocket = require("isomorphic-ws");
} else {
// polyfills for node 20
global.WebSocket = require("isomorphic-ws");
}
class Nostr extends NotificationProvider {
name = "nostr";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
// All DMs should have same timestamp
const createdAt = Math.floor(Date.now() / 1000);
const senderPrivateKey = await this.getPrivateKey(notification.sender);
const senderPublicKey = getPublicKey(senderPrivateKey);
const recipientsPublicKeys = await this.getPublicKeys(notification.recipients);
// Create NIP-04 encrypted direct message event for each recipient
const events = [];
for (const recipientPublicKey of recipientsPublicKeys) {
const ciphertext = await nip04.encrypt(senderPrivateKey, recipientPublicKey, msg);
let event = {
kind: 4,
pubkey: senderPublicKey,
created_at: createdAt,
tags: [[ "p", recipientPublicKey ]],
content: ciphertext,
};
event.id = getEventHash(event);
event.sig = getSignature(event, senderPrivateKey);
events.push(event);
}
// Publish events to each relay
const relays = notification.relays.split("\n");
let successfulRelays = 0;
// Connect to each relay
for (const relayUrl of relays) {
const relay = relayInit(relayUrl);
try {
await relay.connect();
successfulRelays++;
// Publish events
for (const event of events) {
relay.publish(event);
}
} catch (error) {
continue;
} finally {
relay.close();
}
}
// Report success or failure
if (successfulRelays === 0) {
throw Error("Failed to connect to any relays.");
}
return `${successfulRelays}/${relays.length} relays connected.`;
}
async getPrivateKey(sender) {
try {
const senderDecodeResult = await nip19.decode(sender);
const { data } = senderDecodeResult;
return data;
} catch (error) {
throw new Error(`Failed to get private key: ${error.message}`);
}
}
async getPublicKeys(recipients) {
const recipientsList = recipients.split("\n");
const publicKeys = [];
for (const recipient of recipientsList) {
try {
const recipientDecodeResult = await nip19.decode(recipient);
const { type, data } = recipientDecodeResult;
if (type === "npub") {
publicKeys.push(data);
} else {
throw new Error("not an npub");
}
} catch (error) {
throw new Error(`Error decoding recipient: ${error}`);
}
}
return publicKeys;
}
}
module.exports = Nostr;

View File

@@ -20,10 +20,10 @@ class Opsgenie extends NotificationProvider {
try {
switch (notification.opsgenieRegion) {
case "US":
case "us":
opsgenieAlertsUrl = opsgenieAlertsUrlUS;
break;
case "EU":
case "eu":
opsgenieAlertsUrl = opsgenieAlertsUrlEU;
break;
default:

View File

@@ -8,7 +8,9 @@ class PushDeer extends NotificationProvider {
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let pushdeerlink = "https://api2.pushdeer.com/message/push";
let endpoint = "/message/push";
let serverUrl = notification.pushdeerServer || "https://api2.pushdeer.com";
let pushdeerlink = `${serverUrl.trim().replace(/\/*$/, "")}${endpoint}`;
let valid = msg != null && monitorJSON != null && heartbeatJSON != null;

View File

@@ -13,7 +13,7 @@ class SMTP extends NotificationProvider {
port: notification.smtpPort,
secure: notification.smtpSecure,
tls: {
rejectUnauthorized: notification.smtpIgnoreTLSError || false,
rejectUnauthorized: !notification.smtpIgnoreTLSError || false,
}
};

View File

@@ -21,11 +21,13 @@ const LineNotify = require("./notification-providers/linenotify");
const LunaSea = require("./notification-providers/lunasea");
const Matrix = require("./notification-providers/matrix");
const Mattermost = require("./notification-providers/mattermost");
const Nostr = require("./notification-providers/nostr");
const Ntfy = require("./notification-providers/ntfy");
const Octopush = require("./notification-providers/octopush");
const OneBot = require("./notification-providers/onebot");
const Opsgenie = require("./notification-providers/opsgenie");
const PagerDuty = require("./notification-providers/pagerduty");
const FlashDuty = require("./notification-providers/flashduty");
const PagerTree = require("./notification-providers/pagertree");
const PromoSMS = require("./notification-providers/promosms");
const Pushbullet = require("./notification-providers/pushbullet");
@@ -84,11 +86,13 @@ class Notification {
new LunaSea(),
new Matrix(),
new Mattermost(),
new Nostr(),
new Ntfy(),
new Octopush(),
new OneBot(),
new Opsgenie(),
new PagerDuty(),
new FlashDuty(),
new PagerTree(),
new PromoSMS(),
new Pushbullet(),
@@ -115,7 +119,6 @@ class Notification {
new GoAlert(),
new ZohoCliq()
];
for (let item of list) {
if (! item.name) {
throw new Error("Notification provider without name");

View File

@@ -1,5 +1,12 @@
let express = require("express");
const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin, sendHttpError } = require("../util-server");
const {
setting,
allowDevAllOrigin,
allowAllOrigin,
percentageToColor,
filterAndJoin,
sendHttpError,
} = require("../util-server");
const { R } = require("redbean-node");
const apicache = require("../modules/apicache");
const Monitor = require("../model/monitor");
@@ -22,10 +29,14 @@ router.get("/api/entry-page", async (request, response) => {
allowDevAllOrigin(response);
let result = { };
let hostname = request.hostname;
if ((await setting("trustProxy")) && request.headers["x-forwarded-host"]) {
hostname = request.headers["x-forwarded-host"];
}
if (request.hostname in StatusPage.domainMappingList) {
if (hostname in StatusPage.domainMappingList) {
result.type = "statusPageMatchedDomain";
result.statusPageSlug = StatusPage.domainMappingList[request.hostname];
result.statusPageSlug = StatusPage.domainMappingList[hostname];
} else {
result.type = "entryPage";
result.entryPage = server.entryPage;
@@ -38,7 +49,7 @@ router.get("/api/push/:pushToken", async (request, response) => {
let pushToken = request.params.pushToken;
let msg = request.query.msg || "OK";
let ping = parseInt(request.query.ping) || null;
let ping = parseFloat(request.query.ping) || null;
let statusString = request.query.status || "up";
let status = (statusString === "up") ? UP : DOWN;

View File

@@ -49,6 +49,7 @@ if (! process.env.NODE_ENV) {
}
log.info("server", "Node Env: " + process.env.NODE_ENV);
log.info("server", "Inside Container: " + (process.env.UPTIME_KUMA_IS_CONTAINER === "1"));
log.info("server", "Importing Node libraries");
const fs = require("fs");
@@ -82,8 +83,11 @@ const app = server.app;
log.info("server", "Importing this project modules");
log.debug("server", "Importing Monitor");
const Monitor = require("./model/monitor");
const User = require("./model/user");
log.debug("server", "Importing Settings");
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, doubleCheckPassword, startE2eTests } = require("./util-server");
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, doubleCheckPassword, startE2eTests, shake256, SHAKE256_LENGTH
} = require("./util-server");
log.debug("server", "Importing Notification");
const { Notification } = require("./notification");
@@ -296,6 +300,11 @@ let needSetup = false;
]);
if (user) {
// Check if the password changed
if (decoded.h !== shake256(user.password, SHAKE256_LENGTH)) {
throw new Error("The token is invalid due to password change or old token");
}
log.debug("auth", "afterLogin");
afterLogin(socket, user);
log.debug("auth", "afterLogin ok");
@@ -315,9 +324,10 @@ let needSetup = false;
});
}
} catch (error) {
log.error("auth", `Invalid token. IP=${clientIP}`);
if (error.message) {
log.error("auth", error.message, `IP=${clientIP}`);
}
callback({
ok: false,
msg: "Invalid token.",
@@ -356,9 +366,7 @@ let needSetup = false;
callback({
ok: true,
token: jwt.sign({
username: data.username,
}, server.jwtSecret),
token: User.createJWT(user, server.jwtSecret),
});
}
@@ -386,9 +394,7 @@ let needSetup = false;
callback({
ok: true,
token: jwt.sign({
username: data.username,
}, server.jwtSecret),
token: User.createJWT(user, server.jwtSecret),
});
} else {
@@ -640,6 +646,10 @@ let needSetup = false;
let notificationIDList = monitor.notificationIDList;
delete monitor.notificationIDList;
// Ensure status code ranges are strings
if (!monitor.accepted_statuscodes.every((code) => typeof code === "string")) {
throw new Error("Accepted status codes are not all strings");
}
monitor.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes);
delete monitor.accepted_statuscodes;
@@ -656,7 +666,10 @@ let needSetup = false;
await updateMonitorNotification(bean.id, notificationIDList);
await server.sendMonitorList(socket);
await startMonitor(socket.userID, bean.id);
if (monitor.active !== false) {
await startMonitor(socket.userID, bean.id);
}
log.info("monitor", `Added Monitor: ${monitor.id} User ID: ${socket.userID}`);
@@ -702,6 +715,11 @@ let needSetup = false;
removeGroupChildren = true;
}
// Ensure status code ranges are strings
if (!monitor.accepted_statuscodes.every((code) => typeof code === "string")) {
throw new Error("Accepted status codes are not all strings");
}
bean.name = monitor.name;
bean.description = monitor.description;
bean.parent = monitor.parent;
@@ -712,6 +730,12 @@ let needSetup = false;
bean.headers = monitor.headers;
bean.basic_auth_user = monitor.basic_auth_user;
bean.basic_auth_pass = monitor.basic_auth_pass;
bean.timeout = monitor.timeout;
bean.oauth_client_id = monitor.oauth_client_id;
bean.oauth_client_secret = monitor.oauth_client_secret;
bean.oauth_auth_method = monitor.oauth_auth_method;
bean.oauth_token_url = monitor.oauth_token_url;
bean.oauth_scopes = monitor.oauth_scopes;
bean.tlsCa = monitor.tlsCa;
bean.tlsCert = monitor.tlsCert;
bean.tlsKey = monitor.tlsKey;
@@ -765,6 +789,10 @@ let needSetup = false;
bean.kafkaProducerAllowAutoTopicCreation = monitor.kafkaProducerAllowAutoTopicCreation;
bean.kafkaProducerSaslOptions = JSON.stringify(monitor.kafkaProducerSaslOptions);
bean.kafkaProducerMessage = monitor.kafkaProducerMessage;
bean.kafkaProducerSsl = monitor.kafkaProducerSsl;
bean.kafkaProducerAllowAutoTopicCreation =
monitor.kafkaProducerAllowAutoTopicCreation;
bean.gamedigGivenPortOnly = monitor.gamedigGivenPortOnly;
bean.validate();
@@ -776,7 +804,7 @@ let needSetup = false;
await updateMonitorNotification(bean.id, monitor.notificationIDList);
if (bean.isActive()) {
if (await bean.isActive()) {
await restartMonitor(socket.userID, bean.id);
}
@@ -1096,9 +1124,6 @@ let needSetup = false;
value,
]);
// Cleanup unused Tags
await R.exec("delete from tag where ( select count(*) from monitor_tag mt where tag.id = mt.tag_id ) = 0");
callback({
ok: true,
msg: "Deleted Successfully.",
@@ -1177,6 +1202,7 @@ let needSetup = false;
}
const previousChromeExecutable = await Settings.get("chromeExecutable");
const previousNSCDStatus = await Settings.get("nscd");
await setSettings("general", data);
server.entryPage = data.entryPage;
@@ -1194,6 +1220,15 @@ let needSetup = false;
await resetChrome();
}
// Update nscd status
if (previousNSCDStatus !== data.nscd) {
if (data.nscd) {
server.startNSCDServices();
} else {
server.stopNSCDServices();
}
}
callback({
ok: true,
msg: "Saved"
@@ -1363,6 +1398,7 @@ let needSetup = false;
// Define default values
let retryInterval = 0;
let timeout = monitorListData[i].timeout || (monitorListData[i].interval * 0.8); // fallback to old value
/*
Only replace the default value with the backup file data for the specific version, where it appears the first time
@@ -1388,6 +1424,7 @@ let needSetup = false;
basic_auth_pass: monitorListData[i].basic_auth_pass,
authWorkstation: monitorListData[i].authWorkstation,
authDomain: monitorListData[i].authDomain,
timeout,
interval: monitorListData[i].interval,
retryInterval: retryInterval,
resendInterval: monitorListData[i].resendInterval || 0,
@@ -1589,6 +1626,8 @@ let needSetup = false;
await shutdownFunction();
});
server.start();
server.httpServer.listen(port, hostname, () => {
if (hostname) {
log.info("server", `Listening on ${hostname}:${port}`);
@@ -1793,6 +1832,7 @@ async function pauseMonitor(userID, monitorID) {
if (monitorID in server.monitorList) {
server.monitorList[monitorID].stop();
server.monitorList[monitorID].active = 0;
}
}
@@ -1851,8 +1891,10 @@ gracefulShutdown(server.httpServer, {
});
// Catch unexpected errors here
process.addListener("unhandledRejection", (error, promise) => {
let unexpectedErrorHandler = (error, promise) => {
console.trace(error);
UptimeKumaServer.errorLog(error, false);
console.error("If you keep encountering errors, please report to https://github.com/louislam/uptime-kuma/issues");
});
};
process.addListener("unhandledRejection", unexpectedErrorHandler);
process.addListener("uncaughtException", unexpectedErrorHandler);

View File

@@ -162,6 +162,7 @@ module.exports.statusPageSocketHandler = (socket) => {
statusPage.footer_text = config.footerText;
statusPage.custom_css = config.customCSS;
statusPage.show_powered_by = config.showPoweredBy;
statusPage.show_certificate_expiry = config.showCertificateExpiry;
statusPage.modified_date = R.isoDateTime();
statusPage.google_analytics_tag_id = config.googleAnalyticsId;

View File

@@ -10,6 +10,9 @@ const util = require("util");
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
const { Settings } = require("./settings");
const dayjs = require("dayjs");
const childProcess = require("child_process");
const path = require("path");
const axios = require("axios");
// DO NOT IMPORT HERE IF THE MODULES USED `UptimeKumaServer.getInstance()`, put at the bottom of this file instead.
/**
@@ -60,6 +63,8 @@ class UptimeKumaServer {
*/
jwtSecret = null;
checkMonitorsInterval = null;
static getInstance(args) {
if (UptimeKumaServer.instance == null) {
UptimeKumaServer.instance = new UptimeKumaServer(args);
@@ -73,6 +78,9 @@ class UptimeKumaServer {
const sslCert = args["ssl-cert"] || process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined;
const sslKeyPassphrase = args["ssl-key-passphrase"] || process.env.UPTIME_KUMA_SSL_KEY_PASSPHRASE || process.env.SSL_KEY_PASSPHRASE || undefined;
// Set default axios timeout to 5 minutes instead of infinity
axios.defaults.timeout = 300 * 1000;
log.info("server", "Creating express and socket.io instance");
this.app = express();
if (sslKey && sslCert) {
@@ -99,6 +107,7 @@ class UptimeKumaServer {
// Set Monitor Types
UptimeKumaServer.monitorTypeList["real-browser"] = new RealBrowserMonitorType();
UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing();
this.io = new Server(this.httpServer);
}
@@ -212,7 +221,7 @@ class UptimeKumaServer {
* @param {boolean} outputToConsole Should the error also be output to console?
*/
static errorLog(error, outputToConsole = true) {
const errorLogStream = fs.createWriteStream(Database.dataDir + "/error.log", {
const errorLogStream = fs.createWriteStream(path.join(Database.dataDir, "/error.log"), {
flags: "a"
});
@@ -333,9 +342,140 @@ class UptimeKumaServer {
dayjs.tz.setDefault(timezone);
}
/** Stop the server */
async stop() {
/**
* TODO: Listen logic should be moved to here
* @returns {Promise<void>}
*/
async start() {
let enable = await Settings.get("nscd");
if (enable || enable === null) {
this.startNSCDServices();
}
this.checkMonitorsInterval = setInterval(() => {
this.checkMonitors();
}, 60 * 1000);
}
/**
* Stop the server
* @returns {Promise<void>}
*/
async stop() {
let enable = await Settings.get("nscd");
if (enable || enable === null) {
this.stopNSCDServices();
}
clearInterval(this.checkMonitorsInterval);
}
/**
* Start all system services (e.g. nscd)
* For now, only used in Docker
*/
startNSCDServices() {
if (process.env.UPTIME_KUMA_IS_CONTAINER) {
try {
log.info("services", "Starting nscd");
childProcess.execSync("sudo service nscd start", { stdio: "pipe" });
} catch (e) {
log.info("services", "Failed to start nscd");
}
}
}
/**
* Stop all system services
*/
stopNSCDServices() {
if (process.env.UPTIME_KUMA_IS_CONTAINER) {
try {
log.info("services", "Stopping nscd");
childProcess.execSync("sudo service nscd stop");
} catch (e) {
log.info("services", "Failed to stop nscd");
}
}
}
/**
* Start the specified monitor
* @param {number} monitorID ID of monitor to start
* @returns {Promise<void>}
*/
async startMonitor(monitorID) {
log.info("manage", `Resume Monitor: ${monitorID} by server`);
await R.exec("UPDATE monitor SET active = 1 WHERE id = ?", [
monitorID,
]);
let monitor = await R.findOne("monitor", " id = ? ", [
monitorID,
]);
if (monitor.id in this.monitorList) {
this.monitorList[monitor.id].stop();
}
this.monitorList[monitor.id] = monitor;
monitor.start(this.io);
}
/**
* Restart a given monitor
* @param {number} monitorID ID of monitor to start
* @returns {Promise<void>}
*/
async restartMonitor(monitorID) {
return await this.startMonitor(monitorID);
}
/**
* Check if monitors are running properly
*/
async checkMonitors() {
log.debug("monitor_checker", "Checking monitors");
for (let monitorID in this.monitorList) {
let monitor = this.monitorList[monitorID];
// Not for push monitor
if (monitor.type === "push") {
continue;
}
if (!monitor.active) {
continue;
}
// Check the lastStartBeatTime, if it is too long, then restart
if (monitor.lastScheduleBeatTime ) {
let diff = dayjs().diff(monitor.lastStartBeatTime, "second");
if (diff > monitor.interval * 1.5) {
log.error("monitor_checker", `Monitor Interval: ${monitor.interval} Monitor ` + monitorID + " lastStartBeatTime diff: " + diff);
log.error("monitor_checker", "Unexpected error: Monitor " + monitorID + " is struck for unknown reason");
log.error("monitor_checker", "Last start beat time: " + R.isoDateTime(monitor.lastStartBeatTime));
log.error("monitor_checker", "Last end beat time: " + R.isoDateTime(monitor.lastEndBeatTime));
log.error("monitor_checker", "Last ScheduleBeatTime: " + R.isoDateTime(monitor.lastScheduleBeatTime));
// Restart
log.error("monitor_checker", `Restarting monitor ${monitorID} automatically now`);
this.restartMonitor(monitorID);
} else {
//log.debug("monitor_checker", "Monitor " + monitorID + " is running normally");
}
} else {
//log.debug("monitor_checker", "Monitor " + monitorID + " is not started yet, skipp");
}
}
log.debug("monitor_checker", "Checking monitors end");
}
}
@@ -345,3 +485,4 @@ module.exports = {
// Must be at the end to avoid circular dependencies
const { RealBrowserMonitorType } = require("./monitor-types/real-browser-monitor-type");
const { TailscalePing } = require("./monitor-types/tailscale-ping");

View File

@@ -21,6 +21,9 @@ const grpc = require("@grpc/grpc-js");
const protojs = require("protobufjs");
const radiusClient = require("node-radius-client");
const redis = require("redis");
const oidc = require("openid-client");
const tls = require("tls");
const {
dictionaries: {
rfc2865: { file, attributes },
@@ -31,6 +34,7 @@ const dayjs = require("dayjs");
// SASLOptions used in JSDoc
// eslint-disable-next-line no-unused-vars
const { Kafka, SASLOptions } = require("kafkajs");
const crypto = require("crypto");
const isWindows = process.platform === /^win/.test(process.platform);
/**
@@ -52,6 +56,43 @@ exports.initJWTSecret = async () => {
return jwtSecretBean;
};
/**
* Decodes a jwt and returns the payload portion without verifying the jqt.
* @param {string} jwt The input jwt as a string
* @returns {Object} Decoded jwt payload object
*/
exports.decodeJwt = (jwt) => {
return JSON.parse(Buffer.from(jwt.split(".")[1], "base64").toString());
};
/**
* Gets a Access Token form a oidc/oauth2 provider
* @param {string} tokenEndpoint The token URI form the auth service provider
* @param {string} clientId The oidc/oauth application client id
* @param {string} clientSecret The oidc/oauth application client secret
* @param {string} scope The scope the for which the token should be issued for
* @param {string} authMethod The method on how to sent the credentials. Default client_secret_basic
* @returns {Promise<oidc.TokenSet>} TokenSet promise if the token request was successful
*/
exports.getOidcTokenClientCredentials = async (tokenEndpoint, clientId, clientSecret, scope, authMethod = "client_secret_basic") => {
const oauthProvider = new oidc.Issuer({ token_endpoint: tokenEndpoint });
let client = new oauthProvider.Client({
client_id: clientId,
client_secret: clientSecret,
token_endpoint_auth_method: authMethod
});
// Increase default timeout and clock tolerance
client[oidc.custom.http_options] = () => ({ timeout: 10000 });
client[oidc.custom.clock_tolerance] = 5;
let grantParams = { grant_type: "client_credentials" };
if (scope) {
grantParams.scope = scope;
}
return await client.grant(grantParams);
};
/**
* Send TCP request to specified hostname and port
* @param {string} hostname Hostname / address of machine
@@ -247,22 +288,22 @@ exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, sa
producer.connect().then(
() => {
try {
producer.send({
topic: topic,
messages: [{
value: message,
}],
});
connectedToKafka = true;
clearTimeout(timeoutID);
producer.send({
topic: topic,
messages: [{
value: message,
}],
}).then((_) => {
resolve("Message sent successfully");
} catch (e) {
}).catch((e) => {
connectedToKafka = true;
producer.disconnect();
clearTimeout(timeoutID);
reject(new Error("Error sending message: " + e.message));
}
}).finally(() => {
connectedToKafka = true;
clearTimeout(timeoutID);
});
}
).catch(
(e) => {
@@ -274,8 +315,10 @@ exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, sa
);
producer.on("producer.network.request_timeout", (_) => {
clearTimeout(timeoutID);
reject(new Error("producer.network.request_timeout"));
if (!connectedToKafka) {
clearTimeout(timeoutID);
reject(new Error("producer.network.request_timeout"));
}
});
producer.on("producer.disconnect", (_) => {
@@ -353,6 +396,9 @@ exports.mssqlQuery = async function (connectionString, query) {
try {
pool = new mssql.ConnectionPool(connectionString);
await pool.connect();
if (!query) {
query = "SELECT 1";
}
await pool.request().query(query);
pool.close();
} catch (e) {
@@ -373,12 +419,22 @@ exports.postgresQuery = function (connectionString, query) {
return new Promise((resolve, reject) => {
const config = postgresConParse(connectionString);
if (config.password === "") {
// See https://github.com/brianc/node-postgres/issues/1927
return reject(new Error("Password is undefined."));
// Fix #3868, which true/false is not parsed to boolean
if (typeof config.ssl === "string") {
config.ssl = config.ssl === "true";
}
const client = new Client({ connectionString });
if (config.password === "") {
// See https://github.com/brianc/node-postgres/issues/1927
reject(new Error("Password is undefined."));
return;
}
const client = new Client(config);
client.on("error", (error) => {
log.debug("postgres", "Error caught in the error event handler.");
reject(error);
});
client.connect((err) => {
if (err) {
@@ -413,11 +469,15 @@ exports.postgresQuery = function (connectionString, query) {
* Run a query on MySQL/MariaDB
* @param {string} connectionString The database connection string
* @param {string} query The query to validate the database with
* @param {?string} password The password to use
* @returns {Promise<(string)>}
*/
exports.mysqlQuery = function (connectionString, query) {
exports.mysqlQuery = function (connectionString, query, password = undefined) {
return new Promise((resolve, reject) => {
const connection = mysql.createConnection(connectionString);
const connection = mysql.createConnection({
uri: connectionString,
password
});
connection.on("error", (err) => {
reject(err);
@@ -486,6 +546,7 @@ exports.radius = function (
host: hostname,
hostPort: port,
timeout: timeout,
retries: 1,
dictionaries: [ file ],
});
@@ -497,6 +558,12 @@ exports.radius = function (
[ attributes.CALLING_STATION_ID, callingStationId ],
[ attributes.CALLED_STATION_ID, calledStationId ],
],
}).catch((error) => {
if (error.response?.code) {
throw Error(error.response.code);
} else {
throw Error(error.message);
}
});
};
@@ -674,7 +741,6 @@ exports.checkCertificate = function (res) {
* @param {number} status The status code to check
* @param {string[]} acceptedCodes An array of accepted status codes
* @returns {boolean} True if status code within range, false otherwise
* @throws {Error} Will throw an error if the provided status code is not a valid range string or code string
*/
exports.checkStatusCode = function (status, acceptedCodes) {
if (acceptedCodes == null || acceptedCodes.length === 0) {
@@ -682,6 +748,11 @@ exports.checkStatusCode = function (status, acceptedCodes) {
}
for (const codeRange of acceptedCodes) {
if (typeof codeRange !== "string") {
log.error("monitor", `Accepted status code not a string. ${codeRange} is of type ${typeof codeRange}`);
continue;
}
const codeRangeSplit = codeRange.split("-").map(string => parseInt(string));
if (codeRangeSplit.length === 1) {
if (status === codeRangeSplit[0]) {
@@ -692,7 +763,8 @@ exports.checkStatusCode = function (status, acceptedCodes) {
return true;
}
} else {
throw new Error("Invalid status code range");
log.error("monitor", `${codeRange} is not a valid status code range`);
continue;
}
}
@@ -1001,3 +1073,81 @@ module.exports.grpcQuery = async (options) => {
});
};
/**
* Returns an array of SHA256 fingerprints for all known root certificates.
* @returns {Set} A set of SHA256 fingerprints.
*/
module.exports.rootCertificatesFingerprints = () => {
let fingerprints = tls.rootCertificates.map(cert => {
let certLines = cert.split("\n");
certLines.shift();
certLines.pop();
let certBody = certLines.join("");
let buf = Buffer.from(certBody, "base64");
const shasum = crypto.createHash("sha256");
shasum.update(buf);
return shasum.digest("hex").toUpperCase().replace(/(.{2})(?!$)/g, "$1:");
});
fingerprints.push("6D:99:FB:26:5E:B1:C5:B3:74:47:65:FC:BC:64:8F:3C:D8:E1:BF:FA:FD:C4:C2:F9:9B:9D:47:CF:7F:F1:C2:4F"); // ISRG X1 cross-signed with DST X3
fingerprints.push("8B:05:B6:8C:C6:59:E5:ED:0F:CB:38:F2:C9:42:FB:FD:20:0E:6F:2F:F9:F8:5D:63:C6:99:4E:F5:E0:B0:27:01"); // ISRG X2 cross-signed with ISRG X1
return new Set(fingerprints);
};
module.exports.SHAKE256_LENGTH = 16;
/**
*
* @param {string} data
* @param {number} len
* @return {string}
*/
module.exports.shake256 = (data, len) => {
if (!data) {
return "";
}
return crypto.createHash("shake256", { outputLength: len })
.update(data)
.digest("hex");
};
// For unit test, export functions
if (process.env.TEST_BACKEND) {
module.exports.__test = {
parseCertificateInfo,
};
module.exports.__getPrivateFunction = (functionName) => {
return module.exports.__test[functionName];
};
}
/**
* Generates an abort signal with the specified timeout.
* @param {number} timeoutMs - The timeout in milliseconds.
* @returns {AbortSignal | null} - The generated abort signal, or null if not supported.
*/
module.exports.axiosAbortSignal = (timeoutMs) => {
try {
// Just in case, as 0 timeout here will cause the request to be aborted immediately
if (!timeoutMs || timeoutMs <= 0) {
timeoutMs = 5000;
}
return AbortSignal.timeout(timeoutMs);
} catch (_) {
// v16-: AbortSignal.timeout is not supported
try {
const abortController = new AbortController();
setTimeout(() => abortController.abort(), timeoutMs);
return abortController.signal;
} catch (_) {
// v15-: AbortController is not supported
return null;
}
}
};

View File

@@ -111,6 +111,10 @@ optgroup {
padding-right: 20px;
}
.btn-sm {
border-radius: 25px;
}
.btn-primary {
color: white;
@@ -158,6 +162,26 @@ optgroup {
background-color: #161B22;
}
.btn-outline-normal {
padding: 4px 10px;
border: 1px solid #ced4da;
border-radius: 25px;
background-color: transparent;
.dark & {
color: $dark-font-color;
border: 1px solid $dark-font-color2;
}
&.active {
background-color: $highlight-white;
.dark & {
background-color: $dark-font-color2;
}
}
}
@media (max-width: 550px) {
.table-shadow-box {
padding: 10px !important;
@@ -436,7 +460,6 @@ optgroup {
.monitor-list {
&.scrollbar {
overflow-y: auto;
height: calc(100% - 107px);
}
@media (max-width: 770px) {

View File

@@ -0,0 +1,86 @@
<template>
<div class="input-group mb-3">
<select ref="select" v-model="model" class="form-select" :disabled="disabled" :required="required">
<option v-for="option in options" :key="option" :value="option.value" :disabled="option.disabled">{{ option.label }}</option>
</select>
<a class="btn btn-outline-primary" :class="{ disabled: actionDisabled }" @click="action()">
<font-awesome-icon :icon="icon" />
</a>
</div>
</template>
<script>
/**
* Generic select field with a customizable action on the right.
* Action is passed in as a function.
*/
export default {
props: {
options: {
type: Array,
default: () => [],
},
/**
* The value of the select field.
*/
modelValue: {
type: Number,
default: null,
},
/**
* Whether the select field is enabled / disabled.
*/
disabled: {
type: Boolean,
default: false
},
/**
* The icon displayed in the right button of the select field.
* Accepts a Font Awesome icon string identifier.
* @example "plus"
*/
icon: {
type: String,
required: true,
},
/**
* The action to be performed when the button is clicked.
* Action is passed in as a function.
*/
action: {
type: Function,
default: () => {},
},
/**
* Whether the action button is disabled.
* @example true
*/
actionDisabled: {
type: Boolean,
default: false
},
/**
* Whether the select field is required.
* @example true
*/
required: {
type: Boolean,
default: false,
}
},
emits: [ "update:modelValue" ],
computed: {
/**
* Send value update to parent on change.
*/
model: {
get() {
return this.modelValue;
},
set(value) {
this.$emit("update:modelValue", value);
}
}
},
};
</script>

View File

@@ -0,0 +1,56 @@
<template>
<div ref="modal" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
{{ $t("New Group") }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
</div>
<div class="modal-body">
<form @submit.prevent="confirm">
<div>
<label for="draftGroupName" class="form-label">{{ $t("Group Name") }}</label>
<input id="draftGroupName" v-model="groupName" type="text" class="form-control">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
{{ $t("Cancel") }}
</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" :disabled="groupName == '' || groupName == null" @click="confirm">
{{ $t("Confirm") }}
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { Modal } from "bootstrap";
export default {
props: {},
emits: [ "added" ],
data: () => ({
modal: null,
groupName: null,
}),
mounted() {
this.modal = new Modal(this.$refs.modal);
},
methods: {
/** Show the confirm dialog */
show() {
this.modal.show();
},
confirm() {
this.$emit("added", this.groupName);
this.modal.hide();
},
},
};
</script>

View File

@@ -70,7 +70,7 @@ export default {
Confirm,
},
props: {},
emits: [ "added" ],
emits: [ "added", "deleted" ],
data() {
return {
modal: null,
@@ -167,6 +167,7 @@ export default {
this.processing = false;
if (res.ok) {
this.$emit("deleted", this.id);
this.modal.hide();
}
});

View File

@@ -5,15 +5,24 @@
v-for="(beat, index) in shortBeatList"
:key="index"
class="beat"
:class="{ 'empty' : (beat === 0), 'down' : (beat.status === 0), 'pending' : (beat.status === 2), 'maintenance' : (beat.status === 3) }"
:class="{ 'empty': (beat === 0), 'down': (beat.status === 0), 'pending': (beat.status === 2), 'maintenance': (beat.status === 3) }"
:style="beatStyle"
:title="getBeatTitle(beat)"
/>
</div>
<div
v-if="!$root.isMobile && size !== 'small' && beatList.length > 4 && $root.styleElapsedTime !== 'none'"
class="d-flex justify-content-between align-items-center word" :style="timeStyle"
>
<div>{{ timeSinceFirstBeat }} ago</div>
<div v-if="$root.styleElapsedTime === 'with-line'" class="connecting-line"></div>
<div>{{ timeSinceLastBeat }}</div>
</div>
</div>
</template>
<script>
import dayjs from "dayjs";
export default {
props: {
@@ -56,8 +65,30 @@ export default {
}
},
/**
* Calculates the amount of beats of padding needed to fill the length of shortBeatList.
*
* @return {number} The amount of beats of padding needed to fill the length of shortBeatList.
*/
numPadding() {
if (!this.beatList) {
return 0;
}
let num = this.beatList.length - this.maxBeat;
if (this.move) {
num = num - 1;
}
if (num > 0) {
return 0;
}
return -1 * num;
},
shortBeatList() {
if (! this.beatList) {
if (!this.beatList) {
return [];
}
@@ -115,6 +146,53 @@ export default {
};
},
/**
* Returns the style object for positioning the time element.
* @return {Object} The style object containing the CSS properties for positioning the time element.
*/
timeStyle() {
return {
"margin-left": this.numPadding * (this.beatWidth + this.beatMargin * 2) + "px",
};
},
/**
* Calculates the time elapsed since the first valid beat.
*
* @return {string} The time elapsed in minutes or hours.
*/
timeSinceFirstBeat() {
const firstValidBeat = this.shortBeatList.at(this.numPadding);
const minutes = dayjs().diff(dayjs.utc(firstValidBeat?.time), "minutes");
if (minutes > 60) {
return (minutes / 60).toFixed(0) + "h";
} else {
return minutes + "m";
}
},
/**
* Calculates the elapsed time since the last valid beat was registered.
*
* @return {string} The elapsed time in a minutes, hours or "now".
*/
timeSinceLastBeat() {
const lastValidBeat = this.shortBeatList.at(-1);
const seconds = dayjs().diff(dayjs.utc(lastValidBeat?.time), "seconds");
let tolerance = 60 * 2; // default for when monitorList not available
if (this.$root.monitorList[this.monitorId] != null) {
tolerance = this.$root.monitorList[this.monitorId].interval * 2;
}
if (seconds < tolerance) {
return "now";
} else if (seconds < 60 * 60) {
return (seconds / 60).toFixed(0) + "m ago";
} else {
return (seconds / 60 / 60).toFixed(0) + "h ago";
}
}
},
watch: {
beatList: {
@@ -133,14 +211,14 @@ export default {
},
beforeMount() {
if (this.heartbeatList === null) {
if (! (this.monitorId in this.$root.heartbeatList)) {
if (!(this.monitorId in this.$root.heartbeatList)) {
this.$root.heartbeatList[this.monitorId] = [];
}
}
},
mounted() {
if (this.size === "small") {
if (this.size !== "big") {
this.beatWidth = 5;
this.beatHeight = 16;
this.beatMargin = 2;
@@ -151,11 +229,11 @@ export default {
const actualWidth = this.beatWidth * window.devicePixelRatio;
const actualMargin = this.beatMargin * window.devicePixelRatio;
if (! Number.isInteger(actualWidth)) {
if (!Number.isInteger(actualWidth)) {
this.beatWidth = Math.round(actualWidth) / window.devicePixelRatio;
}
if (! Number.isInteger(actualMargin)) {
if (!Number.isInteger(actualMargin)) {
this.beatMargin = Math.round(actualMargin) / window.devicePixelRatio;
}
@@ -229,4 +307,21 @@ export default {
}
}
.word {
color: #aaa;
font-size: 12px;
}
.connecting-line {
flex-grow: 1;
height: 1px;
background-color: #ededed;
margin-left: 10px;
margin-right: 10px;
margin-top: 2px;
.dark & {
background-color: #333;
}
}
</style>

View File

@@ -5,18 +5,18 @@
<h1 class="h3 mb-3 fw-normal" />
<div v-if="!tokenRequired" class="form-floating">
<input id="floatingInput" v-model="username" type="text" class="form-control" placeholder="Username">
<input id="floatingInput" v-model="username" type="text" class="form-control" placeholder="Username" autocomplete="username" required>
<label for="floatingInput">{{ $t("Username") }}</label>
</div>
<div v-if="!tokenRequired" class="form-floating mt-3">
<input id="floatingPassword" v-model="password" type="password" class="form-control" placeholder="Password">
<input id="floatingPassword" v-model="password" type="password" class="form-control" placeholder="Password" autocomplete="current-password" required>
<label for="floatingPassword">{{ $t("Password") }}</label>
</div>
<div v-if="tokenRequired">
<div class="form-floating mt-3">
<input id="otp" v-model="token" type="text" maxlength="6" class="form-control" placeholder="123456">
<input id="otp" v-model="token" type="text" maxlength="6" class="form-control" placeholder="123456" autocomplete="one-time-code" required>
<label for="otp">{{ $t("Token") }}</label>
</div>
</div>

View File

@@ -2,6 +2,10 @@
<div class="shadow-box mb-3" :style="boxStyle">
<div class="list-header">
<div class="header-top">
<button class="btn btn-outline-normal ms-2" :class="{ 'active': selectMode }" type="button" @click="selectMode = !selectMode">
{{ $t("Select") }}
</button>
<div class="placeholder"></div>
<div class="search-wrapper">
<a v-if="searchText == ''" class="search-icon">
@@ -21,27 +25,55 @@
<div class="header-filter">
<MonitorListFilter :filterState="filterState" @update-filter="updateFilter" />
</div>
<!-- Selection Controls -->
<div v-if="selectMode" class="selection-controls px-2 pt-2">
<input
v-model="selectAll"
class="form-check-input select-input"
type="checkbox"
/>
<button class="btn-outline-normal" @click="pauseDialog"><font-awesome-icon icon="pause" size="sm" /> {{ $t("Pause") }}</button>
<button class="btn-outline-normal" @click="resumeSelected"><font-awesome-icon icon="play" size="sm" /> {{ $t("Resume") }}</button>
<span v-if="selectedMonitorCount > 0">
{{ $t("selectedMonitorCount", [ selectedMonitorCount ]) }}
</span>
</div>
</div>
<div class="monitor-list" :class="{ scrollbar: scrollbar }">
<div ref="monitorList" class="monitor-list" :class="{ scrollbar: scrollbar }" :style="monitorListStyle">
<div v-if="Object.keys($root.monitorList).length === 0" class="text-center mt-3">
{{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link>
</div>
<MonitorListItem
v-for="(item, index) in sortedMonitorList" :key="index" :monitor="item"
:isSearch="searchText !== ''"
v-for="(item, index) in sortedMonitorList"
:key="index"
:monitor="item"
:showPathName="filtersActive"
:isSelectMode="selectMode"
:isSelected="isSelected"
:select="select"
:deselect="deselect"
/>
</div>
</div>
<Confirm ref="confirmPause" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="pauseSelected">
{{ $t("pauseMonitorMsg") }}
</Confirm>
</template>
<script>
import Confirm from "../components/Confirm.vue";
import MonitorListItem from "../components/MonitorListItem.vue";
import MonitorListFilter from "./MonitorListFilter.vue";
import { getMonitorRelativeURL } from "../util.ts";
export default {
components: {
Confirm,
MonitorListItem,
MonitorListFilter,
},
@@ -54,6 +86,10 @@ export default {
data() {
return {
searchText: "",
selectMode: false,
selectAll: false,
disableSelectAllWatcher: false,
selectedMonitors: {},
windowTop: 0,
filterState: {
status: null,
@@ -81,31 +117,68 @@ export default {
},
/**
* Returns a sorted list of monitors based on the applied filters and search text.
*
* @return {Array} The sorted list of monitors.
*/
sortedMonitorList() {
let result = Object.values(this.$root.monitorList);
// Simple filter by search text
// finds monitor name, tag name or tag value
if (this.searchText !== "") {
const loweredSearchText = this.searchText.toLowerCase();
result = result.filter(monitor => {
return monitor.name.toLowerCase().includes(loweredSearchText)
result = result.filter(monitor => {
// filter by search text
// finds monitor name, tag name or tag value
let searchTextMatch = true;
if (this.searchText !== "") {
const loweredSearchText = this.searchText.toLowerCase();
searchTextMatch =
monitor.name.toLowerCase().includes(loweredSearchText)
|| monitor.tags.find(tag => tag.name.toLowerCase().includes(loweredSearchText)
|| tag.value?.toLowerCase().includes(loweredSearchText));
});
} else {
result = result.filter(monitor => monitor.parent === null);
}
}
// filter by status
let statusMatch = true;
if (this.filterState.status != null && this.filterState.status.length > 0) {
if (monitor.id in this.$root.lastHeartbeatList && this.$root.lastHeartbeatList[monitor.id]) {
monitor.status = this.$root.lastHeartbeatList[monitor.id].status;
}
statusMatch = this.filterState.status.includes(monitor.status);
}
// filter by active
let activeMatch = true;
if (this.filterState.active != null && this.filterState.active.length > 0) {
activeMatch = this.filterState.active.includes(monitor.active);
}
// filter by tags
let tagsMatch = true;
if (this.filterState.tags != null && this.filterState.tags.length > 0) {
tagsMatch = monitor.tags.map(tag => tag.tag_id) // convert to array of tag IDs
.filter(monitorTagId => this.filterState.tags.includes(monitorTagId)) // perform Array Intersaction between filter and monitor's tags
.length > 0;
}
// Hide children if not filtering
let showChild = true;
if (this.filterState.status == null && this.filterState.active == null && this.filterState.tags == null && this.searchText === "") {
if (monitor.parent !== null) {
showChild = false;
}
}
return searchTextMatch && statusMatch && activeMatch && tagsMatch && showChild;
});
// Filter result by active state, weight and alphabetical
result.sort((m1, m2) => {
if (m1.active !== m2.active) {
if (m1.active === 0) {
if (m1.active === false) {
return 1;
}
if (m2.active === 0) {
if (m2.active === false) {
return -1;
}
}
@@ -123,29 +196,69 @@ export default {
return m1.name.localeCompare(m2.name);
});
if (this.filterState.status != null && this.filterState.status.length > 0) {
result.map(monitor => {
if (monitor.id in this.$root.lastHeartbeatList && this.$root.lastHeartbeatList[monitor.id]) {
monitor.status = this.$root.lastHeartbeatList[monitor.id].status;
}
});
result = result.filter(monitor => this.filterState.status.includes(monitor.status));
}
if (this.filterState.active != null && this.filterState.active.length > 0) {
result = result.filter(monitor => this.filterState.active.includes(monitor.active));
}
if (this.filterState.tags != null && this.filterState.tags.length > 0) {
result = result.filter(monitor => {
return monitor.tags.map(tag => tag.tag_id) // convert to array of tag IDs
.filter(monitorTagId => this.filterState.tags.includes(monitorTagId)) // perform Array Intersaction between filter and monitor's tags
.length > 0;
});
}
return result;
},
isDarkTheme() {
return document.body.classList.contains("dark");
},
monitorListStyle() {
let listHeaderHeight = 107;
if (this.selectMode) {
listHeaderHeight += 42;
}
return {
"height": `calc(100% - ${listHeaderHeight}px)`
};
},
selectedMonitorCount() {
return Object.keys(this.selectedMonitors).length;
},
/**
* Determines if any filters are active.
*
* @return {boolean} True if any filter is active, false otherwise.
*/
filtersActive() {
return this.filterState.status != null || this.filterState.active != null || this.filterState.tags != null || this.searchText !== "";
}
},
watch: {
searchText() {
for (let monitor of this.sortedMonitorList) {
if (!this.selectedMonitors[monitor.id]) {
if (this.selectAll) {
this.disableSelectAllWatcher = true;
this.selectAll = false;
}
break;
}
}
},
selectAll() {
if (!this.disableSelectAllWatcher) {
this.selectedMonitors = {};
if (this.selectAll) {
this.sortedMonitorList.forEach((item) => {
this.selectedMonitors[item.id] = true;
});
}
} else {
this.disableSelectAllWatcher = false;
}
},
selectMode() {
if (!this.selectMode) {
this.selectAll = false;
this.selectedMonitors = {};
}
},
},
mounted() {
window.addEventListener("scroll", this.onScroll);
@@ -181,6 +294,53 @@ export default {
updateFilter(newFilter) {
this.filterState = newFilter;
},
/**
* Deselect a monitor
* @param {number} id ID of monitor
*/
deselect(id) {
delete this.selectedMonitors[id];
},
/**
* Select a monitor
* @param {number} id ID of monitor
*/
select(id) {
this.selectedMonitors[id] = true;
},
/**
* Determine if monitor is selected
* @param {number} id ID of monitor
* @returns {bool}
*/
isSelected(id) {
return id in this.selectedMonitors;
},
/** Disable select mode and reset selection */
cancelSelectMode() {
this.selectMode = false;
this.selectedMonitors = {};
},
/** Show dialog to confirm pause */
pauseDialog() {
this.$refs.confirmPause.show();
},
/** Pause each selected monitor */
pauseSelected() {
Object.keys(this.selectedMonitors)
.filter(id => this.$root.monitorList[id].active)
.forEach(id => this.$root.getSocket().emit("pauseMonitor", id));
this.cancelSelectMode();
},
/** Resume each selected monitor */
resumeSelected() {
Object.keys(this.selectedMonitors)
.filter(id => !this.$root.monitorList[id].active)
.forEach(id => this.$root.getSocket().emit("resumeMonitor", id));
this.cancelSelectMode();
},
},
};
</script>
@@ -271,4 +431,12 @@ export default {
padding-left: 67px;
margin-top: 5px;
}
.selection-controls {
margin-top: 5px;
display: flex;
align-items: center;
gap: 10px;
}
</style>

View File

@@ -258,6 +258,10 @@ export default {
<style lang="scss" scoped>
@import "../assets/vars.scss";
.dropdown-item {
cursor: pointer;
}
.clear-filters-btn {
font-size: 0.8em;
margin-right: 5px;

View File

@@ -1,5 +1,5 @@
<template>
<div class="dropdown" @focusin="open = true" @focusout="handleFocusOut">
<div tabindex="-1" class="dropdown" @focusin="open = true" @focusout="handleFocusOut">
<button type="button" class="filter-dropdown-status" :class="{ 'active': filterActive }" tabindex="0">
<div class="px-1 d-flex align-items-center">
<slot name="status"></slot>
@@ -44,6 +44,7 @@ export default {
<style lang="scss">
@import "../assets/vars.scss";
@import "../assets/app.scss";
.filter-dropdown-menu {
z-index: 100;
@@ -102,17 +103,22 @@ export default {
}
.filter-dropdown-status {
@extend .btn-outline-normal;
display: flex;
align-items: center;
padding: 4px 10px;
margin-left: 5px;
border: 1px solid #ced4da;
border-radius: 25px;
background-color: transparent;
color: $link-color;
.dark & {
color: $dark-font-color;
border: 1px solid $dark-font-color2;
}
&:focus {
background-color: $highlight-white;
.dark & {
background-color: $dark-font-color2;
}
}
&.active {

View File

@@ -1,34 +1,56 @@
<template>
<div>
<router-link :to="monitorURL(monitor.id)" class="item" :class="{ 'disabled': ! monitor.active }">
<div class="row">
<div class="col-9 col-md-8 small-padding" :class="{ 'monitor-item': $root.userHeartbeatBar == 'bottom' || $root.userHeartbeatBar == 'none' }">
<div class="info" :style="depthMargin">
<Uptime :monitor="monitor" type="24" :pill="true" />
<span v-if="hasChildren" class="collapse-padding" @click.prevent="changeCollapsed">
<font-awesome-icon icon="chevron-down" class="animated" :class="{ collapsed: isCollapsed}" />
</span>
{{ monitorName }}
</div>
<div class="tags">
<Tag v-for="tag in monitor.tags" :key="tag" :item="tag" :size="'sm'" />
</div>
</div>
<div v-show="$root.userHeartbeatBar == 'normal'" :key="$root.userHeartbeatBar" class="col-3 col-md-4">
<HeartbeatBar size="small" :monitor-id="monitor.id" />
</div>
<div :style="depthMargin">
<!-- Checkbox -->
<div v-if="isSelectMode" class="select-input-wrapper">
<input
class="form-check-input select-input"
type="checkbox"
:aria-label="$t('Check/Uncheck')"
:checked="isSelected(monitor.id)"
@click.stop="toggleSelection"
/>
</div>
<div v-if="$root.userHeartbeatBar == 'bottom'" class="row">
<div class="col-12 bottom-style">
<HeartbeatBar size="small" :monitor-id="monitor.id" />
<router-link :to="monitorURL(monitor.id)" class="item" :class="{ 'disabled': ! monitor.active }">
<div class="row">
<div class="col-9 col-md-8 small-padding" :class="{ 'monitor-item': $root.userHeartbeatBar == 'bottom' || $root.userHeartbeatBar == 'none' }">
<div class="info">
<Uptime :monitor="monitor" type="24" :pill="true" />
<span v-if="hasChildren" class="collapse-padding" @click.prevent="changeCollapsed">
<font-awesome-icon icon="chevron-down" class="animated" :class="{ collapsed: isCollapsed}" />
</span>
{{ monitorName }}
</div>
<div v-if="monitor.tags.length > 0" class="tags">
<Tag v-for="tag in monitor.tags" :key="tag" :item="tag" :size="'sm'" />
</div>
</div>
<div v-show="$root.userHeartbeatBar == 'normal'" :key="$root.userHeartbeatBar" class="col-3 col-md-4">
<HeartbeatBar ref="heartbeatBar" size="small" :monitor-id="monitor.id" />
</div>
</div>
</div>
</router-link>
<div v-if="$root.userHeartbeatBar == 'bottom'" class="row">
<div class="col-12 bottom-style">
<HeartbeatBar ref="heartbeatBar" size="small" :monitor-id="monitor.id" />
</div>
</div>
</router-link>
</div>
<transition name="slide-fade-up">
<div v-if="!isCollapsed" class="childs">
<MonitorListItem v-for="(item, index) in sortedChildMonitorList" :key="index" :monitor="item" :isSearch="isSearch" :depth="depth + 1" />
<MonitorListItem
v-for="(item, index) in sortedChildMonitorList"
:key="index" :monitor="item"
:showPathName="showPathName"
:isSelectMode="isSelectMode"
:isSelected="isSelected"
:select="select"
:deselect="deselect"
:depth="depth + 1"
/>
</div>
</transition>
</div>
@@ -53,8 +75,13 @@ export default {
type: Object,
default: null,
},
/** If the user is currently searching */
isSearch: {
/** Should the monitor name show it's parent */
showPathName: {
type: Boolean,
default: false,
},
/** If the user is in select mode */
isSelectMode: {
type: Boolean,
default: false,
},
@@ -63,6 +90,21 @@ export default {
type: Number,
default: 0,
},
/** Callback to determine if monitor is selected */
isSelected: {
type: Function,
default: () => {}
},
/** Callback fired when monitor is selected */
select: {
type: Function,
default: () => {}
},
/** Callback fired when monitor is deselected */
deselect: {
type: Function,
default: () => {}
},
},
data() {
return {
@@ -111,13 +153,19 @@ export default {
};
},
monitorName() {
if (this.isSearch) {
if (this.showPathName) {
return this.monitor.pathName;
} else {
return this.monitor.name;
}
}
},
watch: {
isSelectMode() {
// TODO: Resize the heartbeat bar, but too slow
// this.$refs.heartbeatBar.resize();
}
},
beforeMount() {
// Always unfold if monitor is accessed directly
@@ -164,6 +212,16 @@ export default {
monitorURL(id) {
return getMonitorRelativeURL(id);
},
/**
* Toggle selection of monitor
*/
toggleSelection() {
if (this.isSelected(this.monitor.id)) {
this.deselect(this.monitor.id);
} else {
this.select(this.monitor.id);
}
},
},
};
</script>
@@ -201,4 +259,14 @@ export default {
transition: all 0.2s $easing-in;
}
.select-input-wrapper {
float: left;
margin-top: 15px;
margin-left: 3px;
margin-right: 10px;
padding-left: 4px;
position: relative;
z-index: 15;
}
</style>

View File

@@ -126,6 +126,7 @@ export default {
"lunasea": "LunaSea",
"matrix": "Matrix",
"mattermost": "Mattermost",
"nostr": "Nostr",
"ntfy": "Ntfy",
"octopush": "Octopush",
"OneBot": "OneBot",
@@ -157,6 +158,7 @@ export default {
"AliyunSMS": "AliyunSMS (阿里云短信服务)",
"DingDing": "DingDing (钉钉自定义机器人)",
"Feishu": "Feishu (飞书)",
"FlashDuty": "FlashDuty (快猫星云)",
"FreeMobile": "FreeMobile (mobile.free.fr)",
"PushDeer": "PushDeer",
"promosms": "PromoSMS",

View File

@@ -61,12 +61,17 @@
/>
</span>
</div>
<div v-if="showTags" class="tags">
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
<div class="extra-info">
<div v-if="showCertificateExpiry && monitor.element.certExpiryDaysRemaining">
<Tag :item="{name: $t('Cert Exp.'), value: formattedCertExpiryMessage(monitor), color: certExpiryColor(monitor)}" :size="'sm'" />
</div>
<div v-if="showTags">
<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">
<HeartbeatBar size="small" :monitor-id="monitor.element.id" />
<HeartbeatBar size="mid" :monitor-id="monitor.element.id" />
</div>
</div>
</div>
@@ -103,6 +108,10 @@ export default {
/** Should tags be shown? */
showTags: {
type: Boolean,
},
/** Should expiry be shown? */
showCertificateExpiry: {
type: Boolean,
}
},
data() {
@@ -154,6 +163,33 @@ export default {
}
return monitor.element.sendUrl && monitor.element.url && monitor.element.url !== "https://" && !this.editMode;
},
/**
* Returns formatted certificate expiry or Bad cert message
* @param {Object} monitor Monitor to show expiry for
* @returns {string}
*/
formattedCertExpiryMessage(monitor) {
if (monitor?.element?.validCert && monitor?.element?.certExpiryDaysRemaining) {
return monitor.element.certExpiryDaysRemaining + " " + this.$tc("day", monitor.element.certExpiryDaysRemaining);
} else if (monitor?.element?.validCert === false) {
return this.$t("noOrBadCertificate");
} else {
return this.$t("Unknown") + " " + this.$tc("day", 2);
}
},
/**
* Returns certificate expiry based on days remaining
* @param {Object} monitor Monitor to show expiry for
* @returns {string}
*/
certExpiryColor(monitor) {
if (monitor?.element?.validCert && monitor.element.certExpiryDaysRemaining > 7) {
return "#059669";
}
return "#DC2626";
},
}
};
</script>
@@ -161,6 +197,15 @@ export default {
<style lang="scss" scoped>
@import "../assets/vars";
.extra-info {
display: flex;
margin-bottom: 0.5rem;
}
.extra-info > div > div:first-child {
margin-left: 0 !important;
}
.no-monitor-msg {
position: absolute;
width: 100%;

View File

@@ -28,6 +28,7 @@
v-model="currentPassword"
type="password"
class="form-control"
autocomplete="current-password"
required
/>
</div>
@@ -43,7 +44,7 @@
<div v-if="uri && twoFAStatus == false" class="mt-3">
<label for="basic-url" class="form-label">{{ $t("twoFAVerifyLabel") }}</label>
<div class="input-group">
<input v-model="token" type="text" maxlength="6" class="form-control">
<input v-model="token" type="text" maxlength="6" class="form-control" autocomplete="one-time-code" required>
<button class="btn btn-outline-primary" type="button" @click="verifyToken()">{{ $t("Verify Token") }}</button>
</div>
<p v-show="tokenValid" class="mt-2" style="color: green;">{{ $t("tokenValidSettingsMsg") }}</p>

View File

@@ -0,0 +1,29 @@
<template>
<div class="mb-3">
<label for="flashduty-integration-url" class="form-label">Integration Key</label>
<HiddenInput id="flashduty-integration-url" v-model="$parent.notification.flashdutyIntegrationKey" autocomplete="false"></HiddenInput>
<i18n-t tag="div" keypath="wayToGetFlashDutyKey" class="form-text">
<a href="https://flashcat.cloud/product/flashduty?from=kuma" target="_blank">{{ $t("here") }}</a>
</i18n-t>
</div>
<div class="mb-3">
<label for="flashduty-severity" class="form-label">{{ $t("FlashDuty Severity") }}</label>
<select id="flashduty-severity" v-model="$parent.notification.flashdutySeverity" class="form-select" :required="true">
<option value="Info" selected>Info</option>
<option value="Warning" selected>Warning</option>
<option value="Critical">Critical</option>
</select>
</div>
</template>
<script>
import HiddenInput from "../HiddenInput.vue";
export default {
components: {
HiddenInput,
},
mounted() {
}
};
</script>

View File

@@ -1,9 +1,7 @@
<template>
<div class="mb-3">
<label for="goalert-base-url" class="form-label">{{ $t("Base URL") }}</label>
<div class="input-group mb-3">
<input id="goalert-base-url" v-model="$parent.notification.goAlertBaseURL" type="text" class="form-control" required>
</div>
<input id="goalert-base-url" v-model="$parent.notification.goAlertBaseURL" type="text" class="form-control" required>
<i18n-t tag="div" keypath="goAlertInfo" class="form-text">
<a href="https://goalert.me" target="_blank">https://goalert.me</a>
</i18n-t>

View File

@@ -1,23 +1,19 @@
<template>
<div class="mb-3">
<label for="gorush-device-token" class="form-label">{{ $t("Device Token") }}</label><span style="color: red;"><sup>*</sup></span>
<div class="input-group mb-3">
<input id="gorush-device-token" v-model="$parent.notification.gorushDeviceToken" type="text" class="form-control" required>
</div>
<input id="gorush-device-token" v-model="$parent.notification.gorushDeviceToken" type="text" class="form-control" required>
</div>
<div class="mb-3">
<label for="gorush-server-url" class="form-label">{{ $t("Server URL") }}</label><span style="color: red;"><sup>*</sup></span>
<div class="input-group mb-3">
<input id="gorush-server-url" v-model="$parent.notification.gorushServerURL" type="text" class="form-control" required>
</div>
<input id="gorush-server-url" v-model="$parent.notification.gorushServerURL" type="text" class="form-control" required>
</div>
<div class="mb-3">
<label for="gorush-platform" class="form-label">{{ $t("Platform") }}</label><span style="color: red;"><sup>*</sup></span>
<select id="gorush-platform" v-model="$parent.notification.gorushPlatform" class="form-select">
<option value="ios">iOS</option>
<option value="android">{{ $t("Android") }}</option>
<option value="android">Android</option>
<option value="huawei">{{ $t("Huawei") }}</option>
</select>
</div>

View File

@@ -5,9 +5,7 @@
</div>
<div class="mb-3">
<label for="gotify-server-url" class="form-label">{{ $t("Server URL") }}</label>
<div class="input-group mb-3">
<input id="gotify-server-url" v-model="$parent.notification.gotifyserverurl" type="text" class="form-control" required>
</div>
<input id="gotify-server-url" v-model="$parent.notification.gotifyserverurl" type="text" class="form-control" required>
</div>
<div class="mb-3">

View File

@@ -9,10 +9,7 @@
<div class="mb-3">
<label for="kook-guild-id" class="form-label">{{ $t("Guild ID") }}</label>
<div class="input-group mb-3">
<input id="kook-guild-id" v-model="$parent.notification.kookGuildID" type="text" class="form-control" required>
</div>
<input id="kook-guild-id" v-model="$parent.notification.kookGuildID" type="text" class="form-control" required>
<div class="form-text">
<p style="margin-top: 8px;">

View File

@@ -13,7 +13,7 @@
<div class="form-text">
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
<i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;">
<a href="https://docs.mattermost.com/developer/webhooks-incoming.html" target="_blank">https://docs.mattermost.com/developer/webhooks-incoming.html</a>
<a href="https://developers.mattermost.com/integrate/webhooks/incoming/" target="_blank">https://developers.mattermost.com/integrate/webhooks/incoming/</a>
</i18n-t>
<p style="margin-top: 8px;">
{{ $t("aboutMattermostChannelName") }}

View File

@@ -0,0 +1,26 @@
<template>
<div class="mb-3">
<label for="nostr-relays" class="form-label">{{ $t("nostrRelays") }}<span style="color: red;"><sup>*</sup></span></label>
<textarea id="nostr-relays" v-model="$parent.notification.relays" class="form-control" :required="true" placeholder="wss://127.0.0.1:7777/"></textarea>
<small class="form-text text-muted">{{ $t("nostrRelaysHelp") }}</small>
</div>
<div class="mb-3">
<label for="nostr-sender" class="form-label">{{ $t("nostrSender") }}<span style="color: red;"><sup>*</sup></span></label>
<HiddenInput id="nostr-sender" v-model="$parent.notification.sender" autocomplete="new-password" :required="true"></HiddenInput>
</div>
<div class="mb-3">
<label for="nostr-recipients" class="form-label">{{ $t("nostrRecipients") }}<span style="color: red;"><sup>*</sup></span></label>
<textarea id="nostr-recipients" v-model="$parent.notification.recipients" class="form-control" :required="true" placeholder="npub123...&#10;npub789..."></textarea>
<small class="form-text text-muted">{{ $t("nostrRecipientsHelp") }}</small>
</div>
</template>
<script>
import HiddenInput from "../HiddenInput.vue";
export default {
components: {
HiddenInput,
},
};
</script>

View File

@@ -1,14 +1,13 @@
<template>
<div class="mb-3">
<label for="ntfy-ntfytopic" class="form-label">{{ $t("ntfy Topic") }}</label>
<div class="input-group mb-3">
<input id="ntfy-ntfytopic" v-model="$parent.notification.ntfytopic" type="text" class="form-control" required>
</div>
<input id="ntfy-ntfytopic" v-model="$parent.notification.ntfytopic" type="text" class="form-control" required>
</div>
<div class="mb-3">
<label for="ntfy-server-url" class="form-label">{{ $t("Server URL") }}</label>
<div class="input-group mb-3">
<input id="ntfy-server-url" v-model="$parent.notification.ntfyserverurl" type="text" class="form-control" required>
<input id="ntfy-server-url" v-model="$parent.notification.ntfyserverurl" type="text" class="form-control" required>
<div class="form-text">
{{ $t("Server URL should not contain the nfty topic") }}
</div>
</div>
<div class="mb-3">
@@ -23,21 +22,15 @@
</div>
<div v-if="$parent.notification.ntfyAuthenticationMethod === 'usernamePassword'" class="mb-3">
<label for="ntfy-username" class="form-label">{{ $t("Username") }}</label>
<div class="input-group mb-3">
<input id="ntfy-username" v-model="$parent.notification.ntfyusername" type="text" class="form-control">
</div>
<input id="ntfy-username" v-model="$parent.notification.ntfyusername" type="text" class="form-control">
</div>
<div v-if="$parent.notification.ntfyAuthenticationMethod === 'usernamePassword'" class="mb-3">
<label for="ntfy-password" class="form-label">{{ $t("Password") }}</label>
<div class="input-group mb-3">
<HiddenInput id="ntfy-password" v-model="$parent.notification.ntfypassword" autocomplete="new-password"></HiddenInput>
</div>
<HiddenInput id="ntfy-password" v-model="$parent.notification.ntfypassword" autocomplete="new-password"></HiddenInput>
</div>
<div v-if="$parent.notification.ntfyAuthenticationMethod === 'accessToken'" class="mb-3">
<label for="ntfy-access-token" class="form-label">{{ $t("Access Token") }}</label>
<div class="input-group mb-3">
<HiddenInput id="ntfy-access-token" v-model="$parent.notification.ntfyaccesstoken"></HiddenInput>
</div>
<HiddenInput id="ntfy-access-token" v-model="$parent.notification.ntfyaccesstoken"></HiddenInput>
</div>
<div class="mb-3">
<label for="ntfy-icon" class="form-label">{{ $t("IconUrl") }}</label>

View File

@@ -1,4 +1,9 @@
<template>
<div class="mb-3">
<label for="pushdeer-server" class="form-label">{{ $t("PushDeer Server URL") }}</label>
<input id="pushdeer-server" v-model="$parent.notification.pushdeerServer" type="text" class="form-control" placeholder="https://api2.pushdeer.com">
<div class="form-text">{{ $t("pushDeerServerDescription") }}</div>
</div>
<div class="mb-3">
<label for="pushdeer-key" class="form-label">{{ $t("PushDeer Key") }}</label>
<HiddenInput id="pushdeer-key" v-model="$parent.notification.pushdeerKey" :required="true" autocomplete="new-password" placeholder="PDUxxxx"></HiddenInput>

View File

@@ -6,9 +6,7 @@
<div class="mb-3">
<label for="pushy-user-key" class="form-label">{{ $t("pushyToken") }}</label>
<div class="input-group mb-3">
<HiddenInput id="pushy-user-key" v-model="$parent.notification.pushyToken" :required="true" autocomplete="new-password"></HiddenInput>
</div>
<HiddenInput id="pushy-user-key" v-model="$parent.notification.pushyToken" :required="true" autocomplete="new-password"></HiddenInput>
</div>
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
<a href="https://pushy.me/docs/api/send-notifications" target="_blank">https://pushy.me/docs/api/send-notifications</a>

View File

@@ -19,11 +19,13 @@ import LineNotify from "./LineNotify.vue";
import LunaSea from "./LunaSea.vue";
import Matrix from "./Matrix.vue";
import Mattermost from "./Mattermost.vue";
import Nostr from "./Nostr.vue";
import Ntfy from "./Ntfy.vue";
import Octopush from "./Octopush.vue";
import OneBot from "./OneBot.vue";
import Opsgenie from "./Opsgenie.vue";
import PagerDuty from "./PagerDuty.vue";
import FlashDuty from "./FlashDuty.vue";
import PagerTree from "./PagerTree.vue";
import PromoSMS from "./PromoSMS.vue";
import Pushbullet from "./Pushbullet.vue";
@@ -77,11 +79,13 @@ const NotificationFormList = {
"lunasea": LunaSea,
"matrix": Matrix,
"mattermost": Mattermost,
"nostr": Nostr,
"ntfy": Ntfy,
"octopush": Octopush,
"OneBot": OneBot,
"Opsgenie": Opsgenie,
"PagerDuty": PagerDuty,
"FlashDuty": FlashDuty,
"PagerTree": PagerTree,
"promosms": PromoSMS,
"pushbullet": Pushbullet,

View File

@@ -112,6 +112,53 @@
</div>
</div>
</div>
<!-- Timeline -->
<div class="my-4">
<label class="form-label">{{ $t("styleElapsedTime") }}</label>
<div>
<div class="btn-group" role="group">
<input
id="styleElapsedTimeShowNoLine"
v-model="$root.styleElapsedTime"
type="radio"
class="btn-check"
name="styleElapsedTime"
autocomplete="off"
value="no-line"
/>
<label class="btn btn-outline-primary" for="styleElapsedTimeShowNoLine">
{{ $t("styleElapsedTimeShowNoLine") }}
</label>
<input
id="styleElapsedTimeShowWithLine"
v-model="$root.styleElapsedTime"
type="radio"
class="btn-check"
name="styleElapsedTime"
autocomplete="off"
value="with-line"
/>
<label class="btn btn-outline-primary" for="styleElapsedTimeShowWithLine">
{{ $t("styleElapsedTimeShowWithLine") }}
</label>
<input
id="styleElapsedTimeNone"
v-model="$root.styleElapsedTime"
type="radio"
class="btn-check"
name="styleElapsedTime"
autocomplete="off"
value="none"
/>
<label class="btn btn-outline-primary" for="styleElapsedTimeNone">
{{ $t("None") }}
</label>
</div>
</div>
</div>
</div>
</template>

View File

@@ -150,6 +150,43 @@
</div>
</div>
<!-- DNS Cache (nscd) -->
<div v-if="$root.info.isContainer" class="mb-4">
<label class="form-label">
{{ $t("enableNSCD") }}
</label>
<div class="form-check">
<input
id="nscdEnable"
v-model="settings.nscd"
class="form-check-input"
type="radio"
name="nscd"
:value="true"
required
/>
<label class="form-check-label" for="nscdEnable">
{{ $t("Enable") }}
</label>
</div>
<div class="form-check">
<input
id="nscdDisable"
v-model="settings.nscd"
class="form-check-input"
type="radio"
name="nscd"
:value="false"
required
/>
<label class="form-check-label" for="nscdDisable">
{{ $t("Disable") }}
</label>
</div>
</div>
<!-- DNS Cache -->
<div class="mb-4">
<label class="form-label">

View File

@@ -19,6 +19,7 @@
v-model="password.currentPassword"
type="password"
class="form-control"
autocomplete="current-password"
required
/>
</div>
@@ -32,6 +33,7 @@
v-model="password.newPassword"
type="password"
class="form-control"
autocomplete="new-password"
required
/>
</div>
@@ -46,6 +48,7 @@
type="password"
class="form-control"
:class="{ 'is-invalid': invalidPassword }"
autocomplete="new-password"
required
/>
<div class="invalid-feedback">

View File

@@ -455,8 +455,6 @@
"For safety, must use secret key": "للسلامة يجب استخدام المفتاح السري",
"Device Token": "رمز الجهاز",
"Platform": "منصة",
"iOS": "iOS",
"Android": "ذكري المظهر",
"Huawei": "هواوي",
"High": "عالٍ",
"Retry": "إعادة المحاولة",

View File

@@ -592,7 +592,6 @@
"For safety, must use secret key": "للسلامة يجب استخدام المفتاح السري",
"Device Token": "رمز الجهاز",
"Platform": "منصة",
"Android": "ذكري المظهر",
"Huawei": "هواوي",
"High": "عالٍ",
"Retry": "إعادة المحاولة",
@@ -684,5 +683,6 @@
"languageName": "العربية",
"Game": "الألعاب",
"List": "القائمة",
"statusMaintenance": "الصيانة"
"statusMaintenance": "الصيانة",
"Home": "الرئيسة"
}

View File

@@ -333,7 +333,7 @@
"Post": "Публикувай",
"Please input title and content": "Моля, въведете заглавие и съдържание",
"Created": "Създаден",
"Last Updated": "Последно обновен",
"Last Updated": "Последно обновена",
"Unpin": "Откачи",
"Switch to Light Theme": "Превключи към светла тема",
"Switch to Dark Theme": "Превключи към тъмна тема",
@@ -396,8 +396,6 @@
"For safety, must use secret key": "За сигурност, трябва да се използва таен ключ",
"Device Token": "Токен за устройство",
"Platform": "Платформа",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Висок",
"Retry": "Повтори",
@@ -645,8 +643,8 @@
"smseaglePriority": "Приоритет на съобщението (0-9, по подразбиране = 0)",
"IconUrl": "Икона URL адрес",
"webhookAdditionalHeadersTitle": "Допълнителни хедъри",
"webhookAdditionalHeadersDesc": "Задава допълнителни хедъри, изпратени с уеб куката.",
"Enable DNS Cache": "Активирай DNS кеширане",
"webhookAdditionalHeadersDesc": "Задава допълнителни хедъри, изпратени с уеб куката. Всеки хедър трябва да бъде дефиниран като JSON ключ/стойност.",
"Enable DNS Cache": "Активирай DNS кеширане за HTTP(S) монитори",
"Enable": "Активирай",
"Disable": "Деактивирай",
"dnsCacheDescription": "Възможно е да не работи в IPv6 среда - деактивирайте, ако срещнете проблеми.",
@@ -740,7 +738,7 @@
"lunaseaDeviceID": "ID на устройството",
"lunaseaUserID": "ID на потребител",
"twilioAccountSID": "Профил SID",
"twilioAuthToken": "Удостоверяващ токен",
"twilioAuthToken": "Удостоверяващ токен / Тайна на API ключа",
"twilioFromNumber": "От номер",
"twilioToNumber": "Към номер",
"sameAsServerTimezone": "Kато часовата зона на сървъра",
@@ -749,7 +747,7 @@
"cronSchedule": "График: ",
"invalidCronExpression": "Невалиден \"Cron\" израз: {0}",
"cronExpression": "Израз тип \"Cron\"",
"statusPageRefreshIn": "Обновяване след: {0}",
"statusPageRefreshIn": "Ще се обнови след: {0}",
"ntfyUsernameAndPassword": "Потребителско име и парола",
"ntfyAuthenticationMethod": "Метод за удостоверяване",
"pushoverMessageTtl": "TTL на съобщението (секунди)",
@@ -757,7 +755,7 @@
"Badge Generator": "Генератор на баджове на {0}",
"Badge Type": "Тип бадж",
"Badge Duration": "Продължителност на баджа",
"Badge Prefix": "Префикс на баджа",
"Badge Prefix": "Префикс за стйността на баджа",
"Badge Label Color": "Цвят на етикета на баджа",
"Badge Color": "Цвят на баджа",
"Badge Label Suffix": "Суфикс на етикета на значката",
@@ -771,9 +769,9 @@
"Badge URL": "URL адрес на баджа",
"Monitor Setting": "Настройка на монитор {0}",
"Show Clickable Link": "Покажи връзка, която може да се кликне",
"Show Clickable Link Description": "Ако е отбелязано, всеки който има достъп до тази статус страница, ще може да достъпва URL адреса на монитора.",
"Show Clickable Link Description": "Ако е отбелязано, всеки който има достъп до тази статус страница, ще може да достъпва мониторирания URL адрес.",
"Badge Label": "Етикет на баджа",
"Badge Suffix": "Суфикс на баджа",
"Badge Suffix": "Суфикс за стойността на баджа",
"Badge Label Prefix": "Префикс на етикета на значката",
"Badge Pending Color": "Цвят на баджа за изчакващ",
"Badge Down Days": "Колко дни баджът да не се показва",
@@ -784,5 +782,61 @@
"Edit Maintenance": "Редактиране на поддръжка",
"Home": "Главна страница",
"noGroupMonitorMsg": "Не е налично. Първо създайте групов монитор.",
"Close": "Затвори"
"Close": "Затвори",
"nostrRelays": "Nostr релета",
"nostrRelaysHelp": "Един URL адрес за реле на ред",
"nostrSender": "Частен ключ на изпращача (nsec)",
"nostrRecipients": "Публични ключове на получатели (npub)",
"nostrRecipientsHelp": "npub формат, по един на ред",
"chromeExecutable": "Chrome/Chromium изпълним файл",
"chromeExecutableAutoDetect": "Автоматично откриване",
"chromeExecutableDescription": "За потребителите на Docker, ако Chromium все още не е инсталиран, инсталирането и показването на резултата от теста може да отнеме няколко минути. Заема 1GB дисково пространство.",
"Invert Keyword": "Обърнат режим за ключова дума",
"invertKeywordDescription": "При търсене ключовата дума трябва да отсъства, а не да присъства.",
"webhookBodyPresetOption": "Предварителна настройка - {0}",
"webhookBodyCustomOption": "Персонализирано тяло",
"webhookCustomBodyDesc": "Дефинирайте персонализирано HTTP тяло за заявката. Приемат се шаблонни променливи {msg}, {heartbeat}, {monitor}.",
"Request Body": "Тяло на заявката",
"twilioApiKey": "API ключ (по избор)",
"Expected Value": "Очаквана стойност",
"Json Query": "Заявка тип JSON",
"jsonQueryDescription": "Прави JSON заявка срещу отговора и проверява за очаквана стойност (Върнатата стойност ще бъде преобразувана в низ за сравнение). Разгледайте <a href='https://jsonata.org/'>jsonata.org</a> за документация относно езика на заявката. Имате възможност да тествате <a href='https://try.jsonata.org/'>тук</a>.",
"Badge Duration (in hours)": "Времетраене на баджа (в часове)",
"Badge Preview": "Преглед на баджа",
"Notify Channel": "Канал за известяване",
"aboutNotifyChannel": "Каналът за известяване ще задейства известие на настолен компютър или мобилно устройство за всички членове на канала, независимо дали тяхната наличност е в състояние активен или отсъстващ.",
"filterActive": "Активен",
"filterActivePaused": "На пауза",
"Kafka Brokers": "Kafka брокери",
"Enter the list of brokers": "Въведете списъка с брокери",
"Press Enter to add broker": "Натиснете Enter, за да добавите брокер",
"Kafka Topic Name": "Име на темата за Kafka",
"Enable Kafka SSL": "Активирай Kafka SSL",
"Enable Kafka Producer Auto Topic Creation": "Активирай автоматично създаване на темa в Kafka Producer",
"Kafka Producer Message": "Съобщение на Kafka Producer",
"Kafka SASL Options": "Опции на Kafka SASL",
"Mechanism": "Механизъм",
"Pick a SASL Mechanism...": "Изберете SASL механизъм...",
"Authorization Identity": "Идентичност за оторизиране",
"AccessKey Id": "AccessKey ID",
"Secret AccessKey": "Таен ключ за достъп",
"Session Token": "Токен за сесия",
"tailscalePingWarning": "За да използвате Tailscale Ping монитор, трябва да инсталирате Uptime Kuma без Docker и също така да инсталирате Tailscale клиент на вашия сървър.",
"Server URL should not contain the nfty topic": "URL адресът на сървъра не трябва да съдържа nfty темата",
"FlashDuty Severity": "Степен на тежест",
"showCertificateExpiry": "Показвай изтичащ сертификат",
"noOrBadCertificate": "Няма/лош сертификат",
"Select": "Избери",
"selectedMonitorCount": "Избрано: {0}",
"wayToGetFlashDutyKey": "Можете да отидете на страница 'Channel -> (Select a Channel) -> Integrations -> Add a new integration' и да добавите 'Custom Event', за да получите 'push' адрес и да копирате ключа за интегриране в адреса. За повече информация, моля посетете",
"PushDeer Server": "PushDeer сървър",
"pushDeerServerDescription": "Оставете празно, за да използвате официалния сървър",
"Check/Uncheck": "Постави/Премахни отметка",
"Request Timeout": "Време за изтичане на заявката",
"timeoutAfter": "Времето изтича след {0} секунди",
"styleElapsedTime": "Изминало време под лентата с проверки",
"styleElapsedTimeShowNoLine": "Покажи (без ред)",
"gamedigGuessPort": "Gamedig: Познай порт",
"gamedigGuessPortDescription": "Портът, използван от Valve Server Query Protocol, може да е различен от клиентския порт. Опитайте това, ако мониторът не може да се свърже с вашия сървър.",
"styleElapsedTimeShowWithLine": "Покажи (с ред)"
}

1
src/lang/bn.json Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -18,13 +18,13 @@
"Pick Affected Monitors...": "Vyberte dotčené dohledy…",
"Start of maintenance": "Zahájit údržbu",
"All Status Pages": "Všechny stavové stránky",
"Select status pages...": "Vyberte stavovou stránku…",
"Select status pages...": "Vyberte stavové stránky…",
"recurringIntervalMessage": "Spustit jednou každý den | Spustit jednou každých {0} dní",
"affectedMonitorsDescription": "Vyberte dohledy, které budou ovlivněny touto údržbou",
"affectedStatusPages": "Zobrazit tuto zprávu o údržbě na vybraných stavových stránkách",
"atLeastOneMonitor": "Vyberte alespoň jeden dotčený dohled",
"passwordNotMatchMsg": "Hesla se neshodují.",
"notificationDescription": "Aby byla upozornění fungovalo, je nutné ho přiřadit k dohledu.",
"notificationDescription": "Aby oznámení fungovala, je nutné jej přiřadit k dohledu.",
"keywordDescription": "Vyhledat klíčové slovo v prosté odpovědi HTML nebo JSON. Při hledání se rozlišuje velikost písmen.",
"pauseDashboardHome": "Pauza",
"deleteMonitorMsg": "Opravdu chcete odstranit tento dohled?",
@@ -208,7 +208,7 @@
"Status Page": "Stavová stránka",
"Status Pages": "Stavová stránka",
"defaultNotificationName": "Moje {notification} upozornění ({číslo})",
"here": "sem",
"here": "klikněte sem",
"Required": "Vyžadováno",
"telegram": "Telegram",
"ZohoCliq": "ZohoCliq",
@@ -225,7 +225,7 @@
"webhookJsonDesc": "{0} je vhodný pro všechny moderní servery HTTP, jako je Express.js",
"webhookFormDataDesc": "{multipart} je vhodné pro PHP. JSON bude nutné analyzovat prostřednictvím {decodeFunction}",
"webhookAdditionalHeadersTitle": "Dodatečné hlavičky",
"webhookAdditionalHeadersDesc": "Nastavte dodatečné hlavičky, které se odešlou společně s webhookem.",
"webhookAdditionalHeadersDesc": "Nastavte dodatečné hlavičky, které se odešlou společně s webhookem. Každá hlavička by měla být definována jako klíč/hodnota v JSON.",
"smtp": "E-mail (SMTP)",
"secureOptionNone": "Žádné / STARTTLS (25, 587)",
"secureOptionTLS": "TLS (465)",
@@ -243,8 +243,8 @@
"Hello @everyone is...": "Dobrý den, {'@'}všichni jsou…",
"teams": "Microsoft Teams",
"Webhook URL": "URL adresa webhooku",
"wayToGetTeamsURL": "Informace o tom, jak vytvořit URL adresu webhooku naleznete na {0}.",
"wayToGetZohoCliqURL": "Informace o tom, jak vytvořit URL adresu webhooku naleznete na {0}.",
"wayToGetTeamsURL": "Pro informace o tom, jak vytvořit URL adresu webhooku {0}.",
"wayToGetZohoCliqURL": "Pro informace o tom, jak vytvořit URL adresu webhooku {0}.",
"signal": "Signal",
"Number": "Číslo",
"Recipients": "Příjemci",
@@ -339,7 +339,7 @@
"PasswordsDoNotMatch": "Hesla se neshodují.",
"records": "záznamů",
"One record": "Jeden záznam",
"steamApiKeyDescription": "Pro monitorování Steam Game Serveru je nutné zadat Steam Web-API klíč. Svůj API klíč získáte na následující stránce: ",
"steamApiKeyDescription": "Pro monitorování herního serveru ve službě Steam je nutné zadat Steam Web-API klíč. Svůj API klíč získáte na následující stránce: ",
"Current User": "Aktuálně přihlášený uživatel",
"topic": "Téma",
"topicExplanation": "MQTT téma, které chcete sledovat",
@@ -454,8 +454,6 @@
"For safety, must use secret key": "Z důvodu bezpečnosti použijte secret key",
"Device Token": "Token zařízení",
"Platform": "Platforma",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Vysoký",
"Retry": "Opakovat",
@@ -527,8 +525,8 @@
"RadiusCalledStationIdDescription": "Identifikátor volaného zařízení",
"RadiusCallingStationId": "ID volajícího zařízení",
"RadiusCallingStationIdDescription": "Identifikátor volajícího zařízení",
"Certificate Expiry Notification": "Oznámení na blížící se konec platnosti certifikátu",
"API Username": "Uživatelské jména API",
"Certificate Expiry Notification": "Upozornění na blížící se konec platnosti certifikátu",
"API Username": "Uživatelské jméno API",
"API Key": "API klíč",
"Recipient Number": "Číslo příjemce",
"From Name/Number": "Jméno/číslo odesílatele",
@@ -569,7 +567,7 @@
"Also check beta release": "Kontrolovat také dostupnost beta verzí",
"Using a Reverse Proxy?": "Používáte reverzní proxy?",
"Check how to config it for WebSocket": "Zjistěte, jak ji nakonfigurovat pro WebSockety",
"Steam Game Server": "Steam Game Server",
"Steam Game Server": "Herní server ve službě Steam",
"Most likely causes:": "Nejčastější důvody:",
"The resource is no longer available.": "Zdroj již není k dispozici.",
"There might be a typing error in the address.": "Při zadávání adresy jste udělali chybu.",
@@ -640,7 +638,7 @@
"dayOfWeek": "Den v týdnu",
"dayOfMonth": "Den v měsíci",
"lastDay": "Poslední den",
"lastDay1": "1. poslední den v měsíci",
"lastDay1": "Poslední den v měsíci",
"lastDay2": "2. poslední den v měsíci",
"lastDay3": "3. poslední den v měsíci",
"lastDay4": "4. poslední den v měsíci",
@@ -655,10 +653,10 @@
"Server Timezone": "Časové pásmo serveru",
"statusPageMaintenanceEndDate": "Konec",
"IconUrl": "Adresa URL ikony",
"Enable DNS Cache": "Povolit DNS Cache",
"Enable DNS Cache": "Povolit DNS Cache pro HTTP(s) dohledy",
"Enable": "Povolit",
"Disable": "Zakázat",
"dnsCacheDescription": "V některých IPv6 prostředích nemusí fungovat. Pokud narazíte na nějaké problémy, vypněte jej.",
"dnsCacheDescription": "V některých IPv6 prostředích nemusí fungovat. Pokud narazíte na nějaké problémy, tuto možnost vypněte.",
"Single Maintenance Window": "Konkrétní časové okno pro údržbu",
"Maintenance Time Window of a Day": "Časové okno pro údržbu v daný den",
"Effective Date Range": "Časové období (volitelné)",
@@ -692,7 +690,7 @@
"uninstall": "Odinstalace",
"uninstalling": "Odinstalování",
"Packet Size": "Velikost paketu",
"markdownSupported": "Markdown syntaxe podporována",
"markdownSupported": "Markdown syntaxe je podporována",
"Google Analytics ID": "ID Google Analytics",
"Edit Tag": "Upravit štítek",
"Server Address": "Adresa serveru",
@@ -743,46 +741,102 @@
"twilioAccountSID": "SID účtu",
"twilioFromNumber": "Číslo odesílatele",
"twilioToNumber": "Číslo příjemce",
"twilioAuthToken": "Autorizační token",
"twilioAuthToken": "Autorizační token / Tajemství API klíče",
"sameAsServerTimezone": "Stejné jako časové pásmo serveru",
"cronExpression": "Cron výraz",
"cronSchedule": "Plán: ",
"invalidCronExpression": "Neplatný cron výraz: {0}",
"startDateTime": "Počáteční datum/čas",
"startDateTime": "Datum/čas začátku",
"endDateTime": "Datum/čas konce",
"ntfyAuthenticationMethod": "Způsob ověření",
"ntfyUsernameAndPassword": "Uživatelské jméno a heslo",
"pushoverMessageTtl": "Zpráva TTL (Sekund)",
"Show Clickable Link": "Zobrazit klikatelný odkaz",
"Show Clickable Link Description": "Pokud je zaškrtnuto, všichni, kdo mají přístup k této stavové stránce, mají přístup k adrese URL monitoru.",
"Show Clickable Link Description": "Pokud je zaškrtnuto, všichni, kdo mají přístup k této stavové stránce, mají přístup k adrese URL dohledu.",
"Open Badge Generator": "Otevřít generátor odznaků",
"Badge Type": "Typ odznaku",
"Badge Duration": "Platnost odznaku",
"Badge Label": "Štítek odznaku",
"Badge Prefix": "Prefix odznaku",
"Monitor Setting": "{0}'s Nastavení dohledu",
"Badge Prefix": "Prefix hodnoty odznaku",
"Monitor Setting": "Nastavení dohledu pro {0}",
"Badge Generator": "Generátor odznaků pro {0}",
"Badge Label Color": "Barva štítku odznaku",
"Badge Color": "Barva odznaku",
"Badge Style": "Styl odznaku",
"Badge Label Suffix": "Přípona štítku odznaku",
"Badge URL": "URL odznaku",
"Badge Suffix": "Přípona odznaku",
"Badge Suffix": "Přípona hodnoty odznaku",
"Badge Label Prefix": "Prefix štítku odznaku",
"Badge Up Color": "Barva odznaku při Běží",
"Badge Down Color": "Barva odznaku při Nedostupné",
"Badge Pending Color": "Barva odznaku při Pauze",
"Badge Maintenance Color": "Barva odznaku při Údržbě",
"Badge Warn Color": "Barva odznaku při Upozornění",
"Reconnecting...": "Obnovení spojení...",
"Cannot connect to the socket server": "Nelze se připojit k soketovému serveru",
"Reconnecting...": "Obnovování spojení",
"Cannot connect to the socket server": "Nelze se připojit k socketu serveru",
"Edit Maintenance": "Upravit Údržbu",
"Home": "Hlavní stránka",
"Badge Down Days": "Odznak nedostupných dní",
"Group": "Skupina",
"Monitor Group": "Sledovaná skupina",
"noGroupMonitorMsg": "Není k dispozici. Nejprve vytvořte skupin dohledů.",
"noGroupMonitorMsg": "Není k dispozici. Nejprve vytvořte skupinu dohledů.",
"Close": "Zavřít",
"Badge value (For Testing only.)": "Hodnota odznaku (pouze pro testování)",
"Badge Warn Days": "Odznak dní s upozorněním"
"Badge Warn Days": "Odznak dní s upozorněním",
"nostrSender": "Privátní klíč odesílatele (nsec)",
"nostrRelaysHelp": "Jedno relay URL na řádku",
"nostrRecipients": "Privátní klíče příjemců (npub)",
"nostrRecipientsHelp": "formát npub, jeden na řádku",
"chromeExecutable": "Spustitelný soubor Chrome/Chromium",
"chromeExecutableAutoDetect": "Automatická detekce",
"chromeExecutableDescription": "Pokud uživatelé nástroje Docker ještě nemají nainstalovanou aplikaci Chromium, může instalace a zobrazení výsledku testu trvat několik minut. Zabere 1 GB místa na disku.",
"Invert Keyword": "Inverzní klíčové slovo",
"webhookBodyPresetOption": "Uložená hodnota - {0}",
"webhookBodyCustomOption": "Vlastní tělo",
"invertKeywordDescription": "Hledá se klíčové slovo, které je spíše nepřítomné než přítomné.",
"webhookCustomBodyDesc": "Nastaví vlastní tělo HTTP pro požadavek. Akceptovány jsou proměnné {msg}, {heartbeat}, {monitor}.",
"Request Body": "Tělo požadavku",
"twilioApiKey": "Klíč k API (volitelný)",
"Expected Value": "Očekávaná hodnota",
"Json Query": "Json dotaz",
"Badge Duration (in hours)": "Zobrazení odznaku (v hodinách)",
"Badge Preview": "Náhled odznaku",
"Notify Channel": "Kanál nofitikací",
"aboutNotifyChannel": "Upozornění kanálu spustí upozornění na počítači nebo v mobilu pro všechny členy kanálu, ať už jsou dostupní nebo ne.",
"filterActive": "Aktivní",
"filterActivePaused": "Pozastaveno",
"Enter the list of brokers": "Vytvořte seznam zprostředkovatelů",
"Press Enter to add broker": "Stiskem klávesy Enter přidáte zprostředkovatele",
"Kafka Topic Name": "Název Kafka vlákna",
"Enable Kafka SSL": "Zapnout Kafka SSL",
"Mechanism": "Mechanismus",
"Kafka Brokers": "Kafka zprostředkovatelé",
"Authorization Identity": "Autorizační identita",
"AccessKey Id": "AccessKey Id",
"Session Token": "Token relace",
"Pick a SASL Mechanism...": "Vyberte SASL mechanismus…",
"Secret AccessKey": "Secret AccessKey",
"Server URL should not contain the nfty topic": "URL serveru by neměla obsahovat nfty vlákno",
"Kafka SASL Options": "Možnosti Kafka SASL",
"Enable Kafka Producer Auto Topic Creation": "Povolit Kafka zprostředkovateli automatické vytváření vláken",
"Kafka Producer Message": "Zpráva Kafka zprostředkovatele",
"tailscalePingWarning": "Abyste mohli používat Tailscale Ping monitor, je nutné Uptime Kuma nainstalovat mimo Docker, a dále na váš server nainstalovat Tailscale klienta.",
"jsonQueryDescription": "Proveďte JSON dotaz vůči odpovědi a zkontrolujte očekávaný výstup (za účelem porovnání bude návratová hodnota převedena na řetězec). Dokumentaci k dotazovacímu jazyku naleznete na <a href='https://jsonata.org/'>jsonata.org</a>, a využít můžete též <a href='https://try.jsonata.org/'>playground</a>.",
"Select": "Vybrat",
"selectedMonitorCount": "Vybráno: {0}",
"Check/Uncheck": "Vybrat/Zrušit výběr",
"showCertificateExpiry": "Zobrazit vypršení platnosti certifikátu",
"pushDeerServerDescription": "Chcete-li používat oficiální server, ponechte prázdné",
"noOrBadCertificate": "Žádný/Vadný certifikát",
"nostrRelays": "Relé Nostr",
"FlashDuty Severity": "Závažnost",
"PushDeer Server": "Server PushDeer",
"wayToGetFlashDutyKey": "Můžete přejít na stránku Kanál -> (Vyberte kanál) -> Integrace -> Přidat novou integraci, přidat \"Vlastní událost\" a získat adresu pro odeslání, zkopírovat klíč integrace do adresy. Další informace naleznete na adrese",
"Request Timeout": "Časový limit požadavku",
"timeoutAfter": "Vypršení časového limitu po {0} sekundách",
"styleElapsedTime": "Čas uplynulý pod heartbeat ukazatelem",
"styleElapsedTimeShowWithLine": "Zobrazit (s linkou)",
"gamedigGuessPortDescription": "Port používaný protokolem Valve Server Query Protocol se může lišit od portu klienta. Pokud se monitor nemůže připojit k serveru, zkuste to.",
"styleElapsedTimeShowNoLine": "Zobrazit (bez linky)",
"gamedigGuessPort": "Gamedig: Guess Port"
}

View File

@@ -211,7 +211,7 @@
"supportTelegramChatID": "Support Direct Chat / Group / Channel's Chat ID",
"wayToGetTelegramChatID": "Du kan få dit chat-ID ved at sende en besked til bot'en og gå til denne URL for at se chat_id'et:",
"YOUR BOT TOKEN HERE": "DIT BOT TOKEN HER",
"chatIDNotFound": "Chat-ID blev ikke fundet; send venligst en besked til denne bot først ",
"chatIDNotFound": "Chat-ID blev ikke fundet; send venligst en besked til denne bot først",
"Post URL": "Post URL",
"Content Type": "Indholdstype",
"webhookJsonDesc": "{0} er god til alle moderne HTTP-servere som f.eks Express.js",
@@ -558,7 +558,6 @@
"high": "høj",
"Base URL": "Base URL",
"Platform": "Platform",
"Android": "Android",
"Huawei": "Huawei",
"Retry": "Forsøg igen",
"Topic": "Emne",

View File

@@ -48,7 +48,7 @@
"Port": "Port",
"Heartbeat Interval": "Prüfintervall",
"Retries": "Wiederholungen",
"retriesDescription": "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
"retriesDescription": "Maximale Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird",
"Advanced": "Erweitert",
"ignoreTLSError": "Ignoriere TLS-/SSL-Fehler von Webseiten",
"Upside Down Mode": "Umgekehrter Modus",
@@ -109,10 +109,10 @@
"Last Result": "Letztes Ergebnis",
"pauseMonitorMsg": "Bist du sicher, dass du den Monitor pausieren möchtest?",
"clearEventsMsg": "Bist du sicher, dass du alle Ereignisse für diesen Monitor löschen möchtest?",
"clearHeartbeatsMsg": "Bist du sicher, dass du alle Statistiken für diesen Monitor löschen möchtest?",
"clearHeartbeatsMsg": "Bist du sicher, dass du alle Prüfintervalle für diesen Monitor löschen möchtest?",
"Clear Data": "Lösche Daten",
"Events": "Ereignisse",
"Heartbeats": "Statistiken",
"Heartbeats": "Prüfintervalle",
"confirmClearStatisticsMsg": "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
"Create your admin account": "Erstelle dein Admin-Konto",
"Repeat Password": "Passwort erneut eingeben",
@@ -218,7 +218,7 @@
"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.",
"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",
@@ -380,12 +380,12 @@
"alertaAlertState": "Alarmstatus",
"alertaRecoverState": "Wiederherstellungsstatus",
"deleteStatusPageMsg": "Bist du sicher, dass du diese Status-Seite löschen willst?",
"Proxies": "Proxies",
"Proxies": "Proxys",
"default": "Standard",
"enabled": "Aktiviert",
"setAsDefault": "Als Standard setzen",
"deleteProxyMsg": "Bist du sicher, dass du diesen Proxy für alle Monitore löschen willst?",
"proxyDescription": "Proxies müssen einem Monitor zugewiesen werden, um zu funktionieren.",
"proxyDescription": "Proxys müssen einem Monitor zugewiesen werden, um zu funktionieren.",
"enableProxyDescription": "Dieser Proxy wird keinen Effekt auf Monitor-Anfragen haben, bis er aktiviert ist. Du kannst ihn temporär von allen Monitoren nach Aktivierungsstatus deaktivieren.",
"setAsDefaultProxyDescription": "Dieser Proxy wird standardmässig für alle neuen Monitore aktiviert sein. Du kannst den Proxy immer noch für jeden Monitor einzeln deaktivieren.",
"Certificate Chain": "Zertifikatskette",
@@ -403,8 +403,6 @@
"For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden",
"Device Token": "Gerätetoken",
"Platform": "Platform",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Hoch",
"Retry": "Wiederholungen",
@@ -657,10 +655,10 @@
"telegramSendSilentlyDescription": "Sende die Nachricht stumm. Nutzer bekommen eine Benachrichtigung ohne Ton.",
"markdownSupported": "Markdown-Syntax unterstützt",
"webhookAdditionalHeadersTitle": "Zusätzliche Header",
"webhookAdditionalHeadersDesc": "Legt zusätzliche Kopfzeilen fest, die mit dem Webhook gesendet werden.",
"webhookAdditionalHeadersDesc": "Legt zusätzliche Kopfzeilen fest, die mit dem Webhook gesendet werden. Jede Kopfzeile sollte als JSON Schlüssel/Wert definiert werden.",
"Packet Size": "Paketgrösse",
"IconUrl": "Symbol URL",
"Enable DNS Cache": "DNS Cache aktivieren",
"Enable DNS Cache": "DNS-Cache für HTTP(s)-Monitore aktivieren",
"Help": "Hilfe",
"Game": "Spiel",
"General Monitor Type": "Allgemeiner Monitortyp",
@@ -745,7 +743,7 @@
"twilioAccountSID": "Account SID",
"twilioFromNumber": "Absender",
"twilioToNumber": "Empfänger",
"twilioAuthToken": "Auth Token",
"twilioAuthToken": "Auth Token / Api Key Secret",
"statusPageRefreshIn": "Aktualisierung in: {0}",
"sameAsServerTimezone": "Gleiche Zeitzone wie Server",
"startDateTime": "Start Datum/Uhrzeit",
@@ -758,8 +756,8 @@
"Badge Type": "Badge Typ",
"Badge Duration": "Badge Dauer",
"Badge Label": "Badge Label",
"Badge Prefix": "Badge Präfix",
"Badge Suffix": "Badge Suffix",
"Badge Prefix": "Badge Wert Präfix",
"Badge Suffix": "Badge Wert Suffix",
"Badge Label Color": "Badge Label Farbe",
"Badge Color": "Badge Farbe",
"Badge Label Prefix": "Badge Label Präfix",
@@ -781,5 +779,61 @@
"Group": "Gruppe",
"Monitor Group": "Monitor Gruppe",
"noGroupMonitorMsg": "Nicht verfügbar. Erstelle zunächst einen Gruppenmonitor.",
"Close": "Schliessen"
"Close": "Schliessen",
"chromeExecutableAutoDetect": "Automatische Erkennung",
"chromeExecutableDescription": "Für Docker-Benutzer, die Chromium noch nicht installiert haben, kann es ein paar Minuten dauern, bis es installiert ist und das Testergebnis angezeigt wird. Es benötigt 1 GB Speicherplatz.",
"chromeExecutable": "Chrome/Chromium Ausführbare Datei",
"Invert Keyword": "Schlüsselwort invertieren",
"webhookCustomBodyDesc": "Definiere einen benutzerdefinierten HTTP-Body für die Anfrage. Die Template-Variablen {msg}, {heartbeat} und {monitor} werden akzeptiert.",
"webhookBodyPresetOption": "Voreinstellung - {0}",
"webhookBodyCustomOption": "Benutzerdefinierter Body",
"invertKeywordDescription": "Achte darauf, dass das Schlüsselwort eher fehlt als vorhanden ist.",
"Request Body": "Anforderungstext",
"twilioApiKey": "API-Schlüssel (optional)",
"aboutNotifyChannel": "Notify Kanal löst eine Desktop- oder Mobilbenachrichtigung für alle Mitglieder des Kanals aus, unabhängig davon, ob deine Verfügbarkeit auf aktiv oder abwesend eingestellt ist.",
"Notify Channel": "Notify Kanal",
"Enter the list of brokers": "Gib die Liste der Broker ein",
"Kafka Topic Name": "Kafka Topic Name",
"Kafka Producer Message": "Kafka Producer Nachricht",
"Enable Kafka SSL": "Kafka SSL aktivieren",
"Enable Kafka Producer Auto Topic Creation": "Kafka Producer Auto Topic Creation aktivieren",
"Kafka SASL Options": "Kafka SASL Optionen",
"Mechanism": "Mechanismus",
"Pick a SASL Mechanism...": "Wähle ein SASL Mechanismus...",
"AccessKey Id": "AccessKey Id",
"Secret AccessKey": "Secret AccessKey",
"Session Token": "Sitzungs-Token",
"Kafka Brokers": "Kafka Brokers",
"Press Enter to add broker": "Drücke Enter um den Broker hinzuzufügen",
"Authorization Identity": "Authorization Identity",
"Expected Value": "Erwarteter Wert",
"Json Query": "Json-Abfrage",
"filterActive": "Aktiv",
"filterActivePaused": "Pausiert",
"jsonQueryDescription": "Führe eine JSON-Abfrage gegen die Antwort durch und prüfe den erwarteten Wert (der Rückgabewert wird zum Vergleich in eine Zeichenkette umgewandelt). Auf <a href='https://jsonata.org/'>jsonata.org</a> findest du die Dokumentation zur Abfragesprache. <a href='https://try.jsonata.org/'>Hier</a> kannst du Abfragen üben.",
"Badge Duration (in hours)": "Badge Dauer (in Stunden)",
"Badge Preview": "Badge Vorschau",
"tailscalePingWarning": "Um den Tailscale Ping Monitor nutzen zu können, musst du Uptime Kuma ohne Docker installieren und den Tailscale Client auf dem Server installieren.",
"Server URL should not contain the nfty topic": "Die Server-URL sollte das nfty-Thema nicht enthalten",
"pushDeerServerDescription": "Leer lassen um den offiziellen Server zu verwenden",
"FlashDuty Severity": "Schweregrad",
"nostrSender": "Privater Schlüssel des Absenders (nsec)",
"nostrRecipientsHelp": "npub-Format, eine pro Zeile",
"noOrBadCertificate": "Kein/schlechtes Zertifikat",
"wayToGetFlashDutyKey": "Gehe zu Channel -> (Wähle einen Channel) -> Integrationen -> Neue Integration hinzufügen', füge ein 'Custom Event' hinzu, um eine Push-Adresse zu erhalten, und kopiere den Integrationsschlüssel in die Adresse. Für weitere Informationen besuche bitte",
"nostrRelays": "Nostr relays",
"nostrRelaysHelp": "Eine Relay-URL pro Zeile",
"nostrRecipients": "Öffentliche Schlüssel des Empfängers (npub)",
"gamedigGuessPort": "Gamedig: Guess Port",
"Request Timeout": "Zeitüberschreitung der Anfrage",
"styleElapsedTimeShowNoLine": "Anzeigen (keine Zeile)",
"styleElapsedTimeShowWithLine": "Anzeigen (mit Zeile)",
"Select": "Auswählen",
"selectedMonitorCount": "Ausgewählt: {0}",
"PushDeer Server": "PushDeer Server",
"showCertificateExpiry": "Ablauf des Zertifikats anzeigen",
"gamedigGuessPortDescription": "Der vom Valve Server Query Protocol verwendete Port kann sich vom Port des Clients unterscheiden. Versuche dies, wenn der Monitor keine Verbindung zum Server herstellen kann.",
"timeoutAfter": "Zeitüberschreitung nach {0} Sekunden",
"styleElapsedTime": "Verstrichene Zeit unter der Prüfintervallleiste",
"Check/Uncheck": "Aktivieren/Deaktivieren"
}

View File

@@ -48,7 +48,7 @@
"Port": "Port",
"Heartbeat Interval": "Prüfintervall",
"Retries": "Wiederholungen",
"retriesDescription": "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
"retriesDescription": "Maximale Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird",
"Advanced": "Erweitert",
"ignoreTLSError": "Ignoriere TLS-/SSL-Fehler von Webseiten",
"Upside Down Mode": "Umgekehrter Modus",
@@ -109,10 +109,10 @@
"Last Result": "Letztes Ergebnis",
"pauseMonitorMsg": "Bist du sicher, dass du den Monitor pausieren möchtest?",
"clearEventsMsg": "Bist du sicher, dass du alle Ereignisse für diesen Monitor löschen möchtest?",
"clearHeartbeatsMsg": "Bist du sicher, dass du alle Statistiken für diesen Monitor löschen möchtest?",
"clearHeartbeatsMsg": "Bist du sicher, dass du alle Prüfintervalle für diesen Monitor löschen möchtest?",
"Clear Data": "Lösche Daten",
"Events": "Ereignisse",
"Heartbeats": "Statistiken",
"Heartbeats": "Prüfintervalle",
"confirmClearStatisticsMsg": "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
"Create your admin account": "Erstelle dein Admin-Konto",
"Repeat Password": "Passwort erneut eingeben",
@@ -218,7 +218,7 @@
"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 deine Chat-ID erhalten, indem du eine Nachricht an den Bot sendest und zu dieser URL gehst, um die chat_id: zu sehen.",
"wayToGetTelegramChatID": "Du kannst deine 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",
@@ -380,12 +380,12 @@
"alertaAlertState": "Alarmstatus",
"alertaRecoverState": "Wiederherstellungsstatus",
"deleteStatusPageMsg": "Bist du sicher, dass du diese Status-Seite löschen willst?",
"Proxies": "Proxies",
"Proxies": "Proxys",
"default": "Standard",
"enabled": "Aktiviert",
"setAsDefault": "Als Standard setzen",
"deleteProxyMsg": "Bist du sicher, dass du diesen Proxy für alle Monitore löschen willst?",
"proxyDescription": "Proxies müssen einem Monitor zugewiesen werden, um zu funktionieren.",
"proxyDescription": "Proxys müssen einem Monitor zugewiesen werden, um zu funktionieren.",
"enableProxyDescription": "Dieser Proxy wird keinen Effekt auf Monitor-Anfragen haben, bis er aktiviert ist. Du kannst ihn temporär von allen Monitoren nach Aktivierungsstatus deaktivieren.",
"setAsDefaultProxyDescription": "Dieser Proxy wird standardmäßig für alle neuen Monitore aktiviert sein. Du kannst den Proxy immer noch für jeden Monitor einzeln deaktivieren.",
"Certificate Chain": "Zertifikatskette",
@@ -403,8 +403,6 @@
"For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden",
"Device Token": "Gerätetoken",
"Platform": "Platform",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Hoch",
"Retry": "Wiederholungen",
@@ -646,11 +644,11 @@
"Help": "Hilfe",
"Game": "Spiel",
"Custom": "Benutzerdefiniert",
"Enable DNS Cache": "DNS-Cache aktivieren",
"Enable DNS Cache": "DNS-Cache für HTTP(s)-Monitore aktivieren",
"Enable": "Aktivieren",
"Disable": "Deaktivieren",
"Custom Monitor Type": "Benutzerdefinierter Monitortyp",
"webhookAdditionalHeadersDesc": "Legt zusätzliche Header fest, die mit der Webhook gesendet wurden.",
"webhookAdditionalHeadersDesc": "Legt zusätzliche Kopfzeilen fest, die mit dem Webhook gesendet werden. Jede Kopfzeile sollte als JSON Schlüssel/Wert definiert werden.",
"dnsCacheDescription": "In einigen IPv6-Umgebungen funktioniert es möglicherweise nicht. Deaktiviere es, wenn Probleme auftreten.",
"loadingError": "Die Daten konnten nicht abgerufen werden, bitte später noch einmal versuchen.",
"confirmUninstallPlugin": "Möchtest du dieses Plugin wirklich deinstallieren?",
@@ -702,7 +700,7 @@
"Edit Tag": "bearbeite Tag",
"Server Address": "Server Adresse",
"Learn More": "Erfahre mehr",
"Body Encoding": "Körperkodierung",
"Body Encoding": "Inhaltskodierung",
"Add API Key": "API Schlüssel hinzufügen",
"apiKey-active": "Aktiv",
"apiKey-expired": "Abgelaufen",
@@ -749,7 +747,7 @@
"twilioAccountSID": "Account SID",
"twilioFromNumber": "Absender",
"twilioToNumber": "Empfänger",
"twilioAuthToken": "Auth Token",
"twilioAuthToken": "Auth Token / Api Key Secret",
"statusPageRefreshIn": "Aktualisierung in: {0}",
"sameAsServerTimezone": "Gleiche Zeitzone wie Server",
"startDateTime": "Start Datum/Uhrzeit",
@@ -778,11 +776,67 @@
"Badge Pending Color": "Badge Pending Farbe",
"Badge Down Days": "Badge Down Tage",
"Monitor Setting": "{0}'s Monitor Einstellung",
"Badge Prefix": "Badge Präfix",
"Badge Suffix": "Badge Suffix",
"Badge Prefix": "Badge Wert Präfix",
"Badge Suffix": "Badge Wert Suffix",
"Badge Warn Days": "Badge Warnung Tage",
"Group": "Gruppe",
"Monitor Group": "Monitor Gruppe",
"noGroupMonitorMsg": "Nicht verfügbar. Erstelle zunächst einen Gruppenmonitor.",
"Close": "Schließen"
"Close": "Schließen",
"chromeExecutableAutoDetect": "Automatische Erkennung",
"chromeExecutableDescription": "Für Docker-Benutzer, die Chromium noch nicht installiert haben, kann es ein paar Minuten dauern, bis es installiert ist und das Testergebnis angezeigt wird. Es benötigt 1 GB Speicherplatz.",
"chromeExecutable": "Chrome/Chromium Ausführbare Datei",
"Invert Keyword": "Schlüsselwort invertieren",
"invertKeywordDescription": "Achte darauf, dass das Schlüsselwort eher fehlt als vorhanden ist.",
"webhookCustomBodyDesc": "Definiere einen benutzerdefinierten HTTP-Body für die Anfrage. Die Template-Variablen {msg}, {heartbeat} und {monitor} werden akzeptiert.",
"webhookBodyPresetOption": "Voreinstellung - {0}",
"webhookBodyCustomOption": "Benutzerdefinierter Body",
"Request Body": "Anforderungstext",
"Badge Duration (in hours)": "Badge Dauer (in Stunden)",
"Badge Preview": "Badge Vorschau",
"twilioApiKey": "API-Schlüssel (optional)",
"Notify Channel": "Notify Kanal",
"Enter the list of brokers": "Gib die Liste der Broker ein",
"Kafka Topic Name": "Kafka Topic Name",
"Kafka Producer Message": "Kafka Producer Nachricht",
"Enable Kafka SSL": "Kafka SSL aktivieren",
"Enable Kafka Producer Auto Topic Creation": "Kafka Producer Auto Topic Creation aktivieren",
"Kafka SASL Options": "Kafka SASL Optionen",
"Mechanism": "Mechanismus",
"Pick a SASL Mechanism...": "Wähle ein SASL Mechanismus...",
"Authorization Identity": "Authorization Identity",
"AccessKey Id": "AccessKey Id",
"Secret AccessKey": "Secret AccessKey",
"Session Token": "Sitzungs-Token",
"aboutNotifyChannel": "Notify Kanal löst eine Desktop- oder Mobilbenachrichtigung für alle Mitglieder des Kanals aus, unabhängig davon, ob deine Verfügbarkeit auf aktiv oder abwesend eingestellt ist.",
"Kafka Brokers": "Kafka Brokers",
"Press Enter to add broker": "Drücke Enter um den Broker hinzuzufügen",
"filterActive": "Aktiv",
"filterActivePaused": "Pausiert",
"Expected Value": "Erwarteter Wert",
"Json Query": "Json-Abfrage",
"jsonQueryDescription": "Führe eine JSON-Abfrage gegen die Antwort durch und prüfe den erwarteten Wert (der Rückgabewert wird zum Vergleich in eine Zeichenkette umgewandelt). Auf <a href='https://jsonata.org/'>jsonata.org</a> findest du die Dokumentation zur Abfragesprache. <a href='https://try.jsonata.org/'>Hier</a> kannst du Abfragen üben.",
"tailscalePingWarning": "Um den Tailscale Ping Monitor nutzen zu können, musst du Uptime Kuma ohne Docker installieren und den Tailscale Client auf dem Server installieren.",
"Server URL should not contain the nfty topic": "Die Server-URL sollte das nfty-Thema nicht enthalten",
"pushDeerServerDescription": "Leer lassen um den offiziellen Server zu verwenden",
"FlashDuty Severity": "Schweregrad",
"nostrRelays": "Nostr relays",
"gamedigGuessPort": "Gamedig: Guess Port",
"Request Timeout": "Zeitüberschreitung der Anfrage",
"styleElapsedTimeShowNoLine": "Anzeigen (keine Zeile)",
"Select": "Auswählen",
"selectedMonitorCount": "Ausgewählt: {0}",
"PushDeer Server": "PushDeer Server",
"nostrRelaysHelp": "Eine Relay-URL pro Zeile",
"nostrSender": "Privater Schlüssel des Absenders (nsec)",
"gamedigGuessPortDescription": "Der vom Valve Server Query Protocol verwendete Port kann sich vom Port des Clients unterscheiden. Versuche dies, wenn der Monitor keine Verbindung zum Server herstellen kann.",
"wayToGetFlashDutyKey": "Gehe zu Channel -> (Wähle einen Channel) -> Integrationen -> Neue Integration hinzufügen', füge ein 'Custom Event' hinzu, um eine Push-Adresse zu erhalten, und kopiere den Integrationsschlüssel in die Adresse. Für weitere Informationen besuche bitte",
"timeoutAfter": "Zeitüberschreitung nach {0} Sekunden",
"styleElapsedTimeShowWithLine": "Anzeigen (mit Zeile)",
"styleElapsedTime": "Verstrichene Zeit unter der Prüfintervallleiste",
"Check/Uncheck": "Aktivieren/Deaktivieren",
"nostrRecipients": "Öffentliche Schlüssel des Empfängers (npub)",
"nostrRecipientsHelp": "npub-Format, eine pro Zeile",
"showCertificateExpiry": "Ablauf des Zertifikats anzeigen",
"noOrBadCertificate": "Kein/schlechtes Zertifikat"
}

View File

@@ -420,8 +420,6 @@
"For safety, must use secret key": "Για ασφάλεια, πρέπει να χρησιμοποιήσετε secret key",
"Device Token": "Device Token",
"Platform": "Platform",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "High",
"Retry": "Ξαναδοκιμάσετε",

View File

@@ -59,6 +59,8 @@
"Hostname": "Hostname",
"Port": "Port",
"Heartbeat Interval": "Heartbeat Interval",
"Request Timeout": "Request Timeout",
"timeoutAfter": "Timeout after {0} seconds",
"Retries": "Retries",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Resend Notification if Down X times consecutively": "Resend Notification if Down X times consecutively",
@@ -85,6 +87,9 @@
"Dark": "Dark",
"Auto": "Auto",
"Theme - Heartbeat Bar": "Theme - Heartbeat Bar",
"styleElapsedTime": "Elapsed time under the heartbeat bar",
"styleElapsedTimeShowNoLine": "Show (No Line)",
"styleElapsedTimeShowWithLine": "Show (With Line)",
"Normal": "Normal",
"Bottom": "Bottom",
"None": "None",
@@ -269,6 +274,9 @@
"Services": "Services",
"Discard": "Discard",
"Cancel": "Cancel",
"Select": "Select",
"selectedMonitorCount": "Selected: {0}",
"Check/Uncheck": "Check/Uncheck",
"Powered by": "Powered by",
"shrinkDatabaseDescription": "Trigger database VACUUM for SQLite. If your database is created after 1.10.0, AUTO_VACUUM is already enabled and this action is not needed.",
"Customize": "Customize",
@@ -361,9 +369,12 @@
"Setup Docker Host": "Setup Docker Host",
"Connection Type": "Connection Type",
"Docker Daemon": "Docker Daemon",
"noDockerHostMsg": "Not Available. Setup a Docker Host First.",
"DockerHostRequired": "Please set the Docker Host for this monitor.",
"deleteDockerHostMsg": "Are you sure want to delete this docker host for all monitors?",
"socket": "Socket",
"tcp": "TCP / HTTP",
"tailscalePingWarning": "In order to use the Tailscale Ping monitor, you need to install Uptime Kuma without Docker and also install Tailscale client on your server.",
"Docker Container": "Docker Container",
"Container Name / ID": "Container Name / ID",
"Docker Host": "Docker Host",
@@ -440,9 +451,10 @@
"Server Timezone": "Server Timezone",
"statusPageMaintenanceEndDate": "End",
"IconUrl": "Icon URL",
"Enable DNS Cache": "Enable DNS Cache",
"Enable DNS Cache": "(Deprecated) Enable DNS Cache for HTTP(s) monitors",
"Enable": "Enable",
"Disable": "Disable",
"enableNSCD": "Enable NSCD (Name Service Cache Daemon) for caching all DNS requests",
"chromeExecutable": "Chrome/Chromium Executable",
"chromeExecutableAutoDetect": "Auto Detect",
"chromeExecutableDescription": "For Docker users, if Chromium is not yet installed, it may take a few minutes to install and display the test result. It takes 1GB of disk space.",
@@ -619,7 +631,6 @@
"For safety, must use secret key": "For safety, must use secret key",
"Device Token": "Device Token",
"Platform": "Platform",
"Android": "Android",
"Huawei": "Huawei",
"High": "High",
"Retry": "Retry",
@@ -690,12 +701,15 @@
"Octopush API Version": "Octopush API Version",
"Legacy Octopush-DM": "Legacy Octopush-DM",
"ntfy Topic": "ntfy Topic",
"Server URL should not contain the nfty topic": "Server URL should not contain the nfty topic",
"onebotHttpAddress": "OneBot HTTP Address",
"onebotMessageType": "OneBot Message Type",
"onebotGroupMessage": "Group",
"onebotPrivateMessage": "Private",
"onebotUserOrGroupId": "Group/User ID",
"onebotSafetyTips": "For safety, must set access token",
"PushDeer Server": "PushDeer Server",
"pushDeerServerDescription": "Leave blank to use the official server",
"PushDeer Key": "PushDeer Key",
"wayToGetClickSendSMSToken": "You can get API Username and API Key from {0} .",
"Custom Monitor Type": "Custom Monitor Type",
@@ -784,5 +798,16 @@
"Session Token": "Session Token",
"noGroupMonitorMsg": "Not Available. Create a Group Monitor First.",
"Close": "Close",
"Request Body": "Request Body"
"Request Body": "Request Body",
"wayToGetFlashDutyKey":"You can go to Channel -> (Select a Channel) -> Integrations -> Add a new integration' page, add a 'Custom Event' to get a push address, copy the Integration Key in the address. For more information, please visit",
"FlashDuty Severity":"Severity",
"nostrRelays": "Nostr relays",
"nostrRelaysHelp": "One relay URL per line",
"nostrSender": "Sender Private Key (nsec)",
"nostrRecipients": "Recipients Public Keys (npub)",
"nostrRecipientsHelp": "npub format, one per line",
"showCertificateExpiry": "Show Certificate Expiry",
"noOrBadCertificate": "No/Bad Certificate",
"gamedigGuessPort": "Gamedig: Guess Port",
"gamedigGuessPortDescription": "The port used by Valve Server Query Protocol may be different from the client port. Try this if the monitor cannot connect to your server."
}

View File

@@ -270,7 +270,7 @@
"Display Timezone": "Mostrar Zona Horaria",
"Server Timezone": "Servidor de Zona Horaria",
"statusPageMaintenanceEndDate": "Finaliza",
"Enable DNS Cache": "Habilitar Cache DNS",
"Enable DNS Cache": "Habilitar Cache DNS de monitores HTTP(s)",
"No Maintenance": "Sin Mantenimiento",
"weekdayShortSun": "Dom",
"dayOfWeek": "Día de la Semana",
@@ -389,7 +389,7 @@
"emojiCheatSheet": "Hoja de trucos Emoji: {0}",
"webhookJsonDesc": "{0} es bueno para cualquier servidor HTTP moderno como Express.js",
"webhookFormDataDesc": "{multipart} es bueno para PHP. El JSON deberá analizarse con {decodeFunction}",
"webhookAdditionalHeadersDesc": "Establece encabezados adicionales enviados con el webhook.",
"webhookAdditionalHeadersDesc": "Establece encabezados adicionales enviados con el webhook. Cada cabecera debe definirse como una clave/valor JSON.",
"appriseInstalled": "Apprise está instalado.",
"successMessage": "Mensaje de éxito",
"Pick Accepted Status Codes...": "Seleccione Códigos de Estado Aceptados…",
@@ -497,8 +497,6 @@
"Proto Method": "Método Proto",
"Proto Content": "Contenido Proto",
"Economy": "Económico",
"iOS": "iOS",
"Android": "Android",
"Platform": "Plataforma",
"onebotPrivateMessage": "Privado",
"onebotMessageType": "Tipo de Mensaje OneBot",
@@ -590,8 +588,8 @@
"GoogleChat": "Chat de Google (sólo Google Workspace)",
"Kook": "Kook",
"wayToGetKookBotToken": "Crea aplicación y obtén tu token de bot en {0}",
"wayToGetKookGuildID": "Activa 'Modo Desarrollador' en los ajustes de Kook, y haz click derecho en la unión para obtener su ID",
"Guild ID": "ID de Gremio",
"wayToGetKookGuildID": "Activa 'Modo Desarrollador' en los ajustes de Kook, y haz click derecho en el grupo para obtener su ID",
"Guild ID": "ID de grupo",
"User Key": "Key de Usuario",
"octopushTypePremium": "Premium (Rápido - recomendado para alertas)",
"octopushTypeLowCost": "Bajo Coste (Lento - algunas veces bloqueado por operador)",
@@ -655,7 +653,7 @@
"gorush": "Gorush",
"squadcast": "Squadcast",
"Maintenance Time Window of a Day": "Ventana de tiempo de mantenimiento de un día",
"Effective Date Range": "Rango de Fecha Efectivo",
"Effective Date Range": "Rango de Fecha Efectivo (Opcional)",
"Free Mobile User Identifier": "Identificador de Usuario de Free Mobile",
"Gateway Type": "Tipo de Puerta de Enlace",
"SMSManager": "SMSManager",
@@ -698,7 +696,7 @@
"High": "Alto",
"alertaApiEndpoint": "Endpoint API",
"Body Encoding": "Codificación del cuerpo",
"Expiry date": "Fecha de expiración",
"Expiry date": "Fecha de vencimiento",
"Expiry": "Expiración",
"API Keys": "Claves API",
"Key Added": "Clave añadida",
@@ -751,7 +749,22 @@
"statusPageRefreshIn": "Reinicio en: {0}",
"twilioAuthToken": "Token de Autentificación",
"ntfyUsernameAndPassword": "Nombre de Usuario y Contraseña",
"ntfyAuthenticationMethod": "Método de Autentificación",
"ntfyAuthenticationMethod": "Método de Autenticación",
"Cannot connect to the socket server": "No se puede conectar al servidor socket",
"Reconnecting...": "Reconectando..."
"Reconnecting...": "Reconectando...",
"Select": "Seleccionar",
"chromeExecutableAutoDetect": "Auto Detectar",
"Edit Maintenance": "Editar mantenimiento",
"pushoverMessageTtl": "Mensaje TTL (segundos)",
"Notify Channel": "Canal de notificación",
"Show Clickable Link Description": "Si está marcado, todos los que tienen acceso a esta página de estado pueden tener acceso a la URL del monitor.",
"webhookBodyCustomOption": "Cuerpo Personalizado",
"selectedMonitorCount": "Seleccionado: {0}",
"Check/Uncheck": "Marcar/Desmarcar",
"Invert Keyword": "Invertir palabra clave",
"filterActive": "Activo",
"filterActivePaused": "Pausado",
"Home": "Inicio",
"Expected Value": "Valor esperado",
"Json Query": "Consulta Json"
}

View File

@@ -415,8 +415,6 @@
"For safety, must use secret key": "For safety, must use secret key",
"Device Token": "Gailu tokena",
"Platform": "Plataforma",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Altua",
"Retry": "Errepikatu",
@@ -571,5 +569,18 @@
"dayOfMonth": "Hilabeteko eguna",
"lastDay": "Azken eguna",
"lastDay1": "Hilabeteko azken eguna",
"Resend Notification if Down X times consecutively": "Bidali jakinarazpena X aldiz jarraian erortzen bada"
"Resend Notification if Down X times consecutively": "Bidali jakinarazpena X aldiz jarraian erortzen bada",
"Add New Tag": "Gehitu etiketa berria",
"Schedule maintenance": "Programatu mantenua",
"Start of maintenance": "Mantenuaren hasiera",
"All Status Pages": "Egoera orrialde guztiak",
"Custom": "Pertsonalizatua",
"showCertificateExpiry": "Erakutsi ziurtagiriaren iraungitzea",
"Close": "Itxi",
"Request Body": "Eskaera gorputza",
"Mechanism": "Mekanismoa",
"Home": "Hasiera",
"filterActive": "Aktibo",
"filterActivePaused": "Geldituta",
"Expected Value": "Esperotako balioa"
}

View File

@@ -36,7 +36,7 @@
"Version": "نسخه",
"Check Update On GitHub": "بررسی بروزرسانی بر روی گیت‌هاب",
"List": "لیست",
"Add": "اضافه",
"Add": "اضافه کردن",
"Add New Monitor": "اضافه کردن مانیتور جدید",
"Quick Stats": "خلاصه وضعیت",
"Up": "فعال",
@@ -241,7 +241,7 @@
"apiKeyAddedMsg": "کلید API شما اضافه شده است. لطفاً آن را یادداشت کنید زیرا دیگر نمایش داده نخواهد شد.",
"deleteAPIKeyMsg": "آیا مطمئن هستید که می خواهید این کلید API را غیرفعال کنید؟",
"twilioAccountSID": "SID حساب",
"twilioAuthToken": "توکن اعتبارسنجی",
"twilioAuthToken": "توکن اعتبارسنجی / کلید مخفی API",
"appriseNotInstalled": "Apprise نصب نشده است. {0}",
"trustProxyDescription": "به هدرهای «X-Forwarded-*» اعتماد کن. اگر می‌خواهید IP مشتری صحیح را دریافت کنید و آپ‌تایم کومای شما پشت پروکسی مانند Nginx یا Apache قرار دارد، باید این گزینه را فعال کنید.",
"matrixDesc2": "اکیداً توصیه می‌شود که یک کاربر جدید ایجاد کنید و از رمز دسترسی کاربر Matrix خود استفاده نکنید زیرا امکان دسترسی کامل به حساب شما و تمام اتاق‌هایی را که به آنها ملحق شده‌اید می‌دهد. در عوض، یک کاربر جدید ایجاد کنید و فقط او را به اتاقی دعوت کنید که می‌خواهید اعلان را دریافت کنید. می‌توانید با اجرای {0} توکن دسترسی را دریافت کنید",
@@ -568,7 +568,6 @@
"SendKey": "کلید ارسال (SendKey)",
"SecretAccessKey": "کلید دسترسی مخفی (AccessKey Secret)",
"SignName": "نام امضا (SignName)",
"Android": "اندروید",
"Huawei": "هواوی",
"WeCom Bot Key": "کلید ربات WeCom",
"Setup Proxy": "تنظیم پروکسی",
@@ -643,7 +642,7 @@
"Schedule maintenance": "زمانبندی نگهداری (غیرفعال سازی دستی)",
"webhookFormDataDesc": "{multipart} برای PHP مناسب است. آرایه JSON نیاز است تا به این شکل باز شود {decodeFunction}",
"webhookAdditionalHeadersTitle": "هدر اضافی",
"webhookAdditionalHeadersDesc": "تنظیم هدر های اضافی که نیاز است با وب هوک ارسال شود.",
"webhookAdditionalHeadersDesc": "تنظیم هدر های اضافی که نیاز است با وب هوک ارسال شود. هر هدر باید به کیلد/مقدار JSON تعریف شده باشد.",
"Webhook URL": "آدرس وب هوک",
"Application Token": "توکن اپلیکیشن",
"Style": "حالت ها",
@@ -673,7 +672,7 @@
"Server Timezone": "منطقه زمانی در سرور",
"statusPageMaintenanceEndDate": "پایان",
"IconUrl": "URL آیکون",
"Enable DNS Cache": "فعال سازی کش DNS",
"Enable DNS Cache": "فعال سازی کش DNS برای مانیتور های HTTP",
"Access Token": "توکن دسترسی",
"smtp": "ایمیل (SMTP)",
"Device": "دستگاه",
@@ -728,8 +727,8 @@
"Badge Type": "نوع نشان",
"Badge Duration": "مدت نشان",
"Badge Label": "برچسب نشان",
"Badge Prefix": "پیشوند نشان",
"Badge Suffix": "پسوند نشان",
"Badge Prefix": "مقدار پیشوند نشان",
"Badge Suffix": "مقدار پسوند نشان",
"Badge Label Color": "رنگ برچسب نشان",
"Badge Color": "رنگ نشان",
"Badge Label Prefix": "پیشوند برچسب نشان",
@@ -753,5 +752,61 @@
"Reconnecting...": "ارتباط مجدد...",
"Monitor Group": "گروه مانیتور",
"Group": "گروه",
"Close": "بستن"
"Close": "بستن",
"Request Timeout": "زمان تایم اوت ریکوئست",
"filterActive": "فعال",
"webhookCustomBodyDesc": "یک بدنه HTTP سفارشی برای ریکوئست تعریف کنید. متغیر های قابل استفاده: {msg}, {heartbeat}, {monitor}.",
"tailscalePingWarning": "برای استفاده از Tailscale Ping monitor، شما باید آپتایم کوما را بدون استفاده از داکر و همچنین Tailscale client را نیز بر روی سرور خود نصب داشته باشید.",
"jsonQueryDescription": "یک کوئری json در برابر پاسخ انجام دهید و مقدار مورد انتظار را (مقدار برگشتی برای مقایسه به رشته تبدیل می شود). برای مستندات درباره زبان کوئری، <a href='https://jsonata.org/'>jsonata.org</a> مشاهده کنید. همچنین محیط تست را میتوانید در <a href='https://try.jsonata.org/'>اینجا</a> پیدا کنید.",
"Enter the list of brokers": "لیست بروکر هارا وارد کنید",
"Enable Kafka Producer Auto Topic Creation": "فعال سازی ایجاپ موضوع اتوماتیک تهیه کننده",
"Secret AccessKey": "کلید محرمانه AccessKey",
"wayToGetFlashDutyKey": "می توانید به کانال -> (انتخاب یک کانال) -> یکپارچه سازی -> صفحه یکپارچه سازی جدید بروید، یک \"رویداد سفارشی\" را برای دریافت یک آدرس فشار اضافه کنید، کلید یکپارچه سازی را در آدرس کپی کنید. برای اطلاعات بیشتر لطفا مراجعه کنید به",
"showCertificateExpiry": "نمایش زمان به پایان رسیدن اعتبار سرتیفیکیت",
"gamedigGuessPortDescription": "پورت مورد استفاده توسط پروتکل Query Valve Server ممکن است با پورت مشتری متفاوت باشد. اگر مانیتور نمی تواند به سرور شما متصل شود، این را امتحان کنید.",
"invertKeywordDescription": "دنبال کلمات کلیدی ناموجود باشید تا آنهایی که موجود است.",
"Notify Channel": "آگاه کردن کانال",
"timeoutAfter": "تایم اوت بعد از {0} ثانیه",
"FlashDuty Severity": "شدت",
"nostrRelays": "ریلی Nostr",
"nostrRelaysHelp": "یک آدرس ریلی به ازای هر خط",
"nostrSender": "کلید محرمانه فرسته (nsec)",
"gamedigGuessPort": "Gamedig: پورت پرسش",
"styleElapsedTime": "زمان سپری شده زیر heartbeat bar",
"styleElapsedTimeShowNoLine": "نمایش (بدون خط)",
"styleElapsedTimeShowWithLine": "نمایش (با خط)",
"filterActivePaused": "متوقف شده",
"webhookBodyPresetOption": "از پیش تعیین شده - {0}",
"webhookBodyCustomOption": "بدنه سفارشی",
"selectedMonitorCount": "انتخاب شده: {0}",
"Check/Uncheck": "انتخاب/ عدم انتخاب",
"chromeExecutable": "فایل اجرایی کروم/کرومیوم",
"chromeExecutableAutoDetect": "تشخیص خودکار",
"chromeExecutableDescription": "برای کاربران داکر، اگر کرومیوم را هنوز نصب نکردید، ممکن است چند دقیقه زمان ببرد تا کرومیوم نصب و نتایج نشان داده شود. همچنین ممکن است تا 1 گیگابایت فضا بر روی سرور نیاز باشد.",
"Select": "انتخاب",
"aboutNotifyChannel": "آگاه کردن کانال یک نوتیفیکیشن دسکتاپ یا تلفن همراه را برای همه اعضای کانال راه‌اندازی می‌کند، خواه در دسترس بودن آنها فعال باشد یا غیرفعال.",
"Server URL should not contain the nfty topic": "URL سرور نباید حاوی موضوع nfty باشد",
"PushDeer Server": "سرور PushDeer",
"pushDeerServerDescription": "برای استفاده از سرور رسمی خالی بگذارید",
"twilioApiKey": "کلید API (اختیاری)",
"Badge Duration (in hours)": "مدت نشان (در ساعت)",
"Badge Preview": "پیش نمایش نشان",
"Kafka Brokers": "بروکر Kafka",
"Press Enter to add broker": "Enter را برای افزودن بروکر جدید فشار دهید",
"Kafka Topic Name": "عنوان موضوع",
"Kafka Producer Message": "پیام تهیه کننده",
"Enable Kafka SSL": "فعال سازی SSL",
"Kafka SASL Options": "گزینه های SASL",
"Mechanism": "مکانیزم",
"Pick a SASL Mechanism...": "یک مکانیزم SASL انتخاب کنید...",
"Authorization Identity": "اطلاعات اعتبارسنجی",
"AccessKey Id": "آیدی AccessKey",
"Session Token": "توکن سشن",
"Request Body": "بدنه پیام",
"nostrRecipients": "کلید عمومی گیرنده (npub)",
"nostrRecipientsHelp": "فرمت npub، یکی به ازای هر خط",
"noOrBadCertificate": "بدون سرتیفیکت یا بد",
"Invert Keyword": "کلمه کلیدی معکوس",
"Expected Value": "مقدار مورد انتظار",
"Json Query": "کوئری جیسون"
}

View File

@@ -547,7 +547,6 @@
"For safety, must use secret key": "Turvallisuuden vuoksi on käytettävä salaista avainta",
"Device Token": "Laitteen tunnus",
"Platform": "Alusta",
"iOS": "iOS",
"Bark Endpoint": "Bark päätepiste",
"Huawei": "Huawei",
"High": "Korkea",
@@ -564,7 +563,6 @@
"promosmsAllowLongSMS": "Salli pitkät tekstiviestit",
"Feishu WebHookUrl": "Feishu WebHookURL-osoite",
"Internal Room Id": "Huoneen sisäinen tunnus",
"Android": "Android",
"Channel Name": "Kanavan nimi",
"Uptime Kuma URL": "Uptime Kuma URL-osoite",
"Icon Emoji": "Ikoni Emoji",

View File

@@ -223,7 +223,7 @@
"webhookJsonDesc": "{0} est bien pour tous les serveurs HTTP modernes comme Express.js",
"webhookFormDataDesc": "{multipart} est bien pour du PHP. Le JSON aura besoin d'être parsé avec {decodeFunction}",
"webhookAdditionalHeadersTitle": "En-têtes supplémentaires",
"webhookAdditionalHeadersDesc": "Définit des en-têtes supplémentaires envoyés avec le webhook.",
"webhookAdditionalHeadersDesc": "Définit des en-têtes supplémentaires envoyés avec le webhook. Chaque en-tête doit être défini comme une clé/valeur JSON.",
"smtp": "Courriel (SMTP)",
"secureOptionNone": "Aucun / STARTTLS (25, 587)",
"secureOptionTLS": "TLS (465)",
@@ -451,8 +451,6 @@
"For safety, must use secret key": "Par sécurité, utilisation obligatoire de la clé secrète",
"Device Token": "Jeton d'appareil",
"Platform": "Plateforme",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Haute",
"Retry": "Recommencez",
@@ -465,7 +463,7 @@
"User": "Utilisateur",
"Installed": "Installé",
"Not installed": "Non installé",
"Running": "Fonctionne",
"Running": "En cours",
"Not running": "Ne fonctionne pas",
"Remove Token": "Supprimer le jeton",
"Start": "Démarrer",
@@ -652,7 +650,7 @@
"Server Timezone": "Fuseau horaire du serveur",
"statusPageMaintenanceEndDate": "Fin",
"IconUrl": "URL vers l'icône",
"Enable DNS Cache": "Activer le cache DNS",
"Enable DNS Cache": "Activer le cache DNS pour les sondes HTTP(s)",
"Enable": "Activer",
"Disable": "Désactiver",
"dnsCacheDescription": "Il peut ne pas fonctionner dans certains environnements IPv6, désactivez-le si vous rencontrez des problèmes.",
@@ -743,7 +741,7 @@
"twilioFromNumber": "Du Nombre",
"twilioToNumber": "Au Nombre",
"twilioAccountSID": "ID du compte",
"twilioAuthToken": "Jeton d'authentification",
"twilioAuthToken": "Jeton d'authentification / Clé secrète de l'API",
"sameAsServerTimezone": "Identique au fuseau horaire du serveur",
"startDateTime": "Date/heure de début",
"endDateTime": "Date/heure de fin",
@@ -758,8 +756,8 @@
"Open Badge Generator": "Ouvrir le générateur de badges",
"Badge Type": "Type de badge",
"Badge Duration": "Durée du badge",
"Badge Prefix": "Préfixe de badge",
"Badge Suffix": "Suffixe de badge",
"Badge Prefix": "Préfixe de la valeur du badge",
"Badge Suffix": "Suffixe de la valeur du badge",
"Badge Label Color": "Couleur de l'étiquette du badge",
"Badge Color": "Couleur du badge",
"Badge Label Prefix": "Préfixe d'étiquette de badge",
@@ -784,5 +782,61 @@
"Group": "Groupe",
"Home": "Accueil",
"noGroupMonitorMsg": "Pas disponible. Créez d'abord une sonde de groupe.",
"Close": "Fermer"
"Close": "Fermer",
"chromeExecutableDescription": "Pour les utilisateurs sous Docker, si Chromium n'est pas encore installé, quelques minutes seront nécessaires pour installer et afficher le résultat du test. Cela peut prendre 1 Go d'espace disque.",
"chromeExecutableAutoDetect": "Auto-détecter",
"chromeExecutable": "Exécutable Chrome/Chromium",
"Invert Keyword": "Inverser le mot-clé",
"invertKeywordDescription": "Recherchez le mot-clé absent plutôt que présent.",
"webhookCustomBodyDesc": "Définissez un corps HTTP personnalisé pour la requête. Les variables de modèle {msg}, {heartbeat}, {monitor} sont acceptées.",
"webhookBodyCustomOption": "Corps personnalisé",
"webhookBodyPresetOption": "Préréglages - {0}",
"Request Body": "Corps de la requête",
"twilioApiKey": "Clé API (facultatif)",
"Expected Value": "Valeur attendue",
"Json Query": "Requête Json",
"jsonQueryDescription": "Faites une requête json contre la réponse et vérifiez la valeur attendue (la valeur de retour sera convertie en chaîne pour comparaison). Consultez <a href='https://jsonata.org/'>jsonata.org</a> pour la documentation sur le langage de requête. Une aire de jeux peut être trouvée <a href='https://try.jsonata.org/'>ici</a>.",
"Badge Duration (in hours)": "Durée du badge (en heures)",
"Badge Preview": "Aperçu du badge",
"aboutNotifyChannel": "Notifier le canal déclenchera une notification de bureau ou mobile pour tous les membres du canal, que leur disponibilité soit active ou absente.",
"Notify Channel": "Notifier le canal",
"filterActive": "Actif",
"filterActivePaused": "En pause",
"Enter the list of brokers": "Entrez la liste des courtiers",
"Press Enter to add broker": "Appuyez sur Entrée pour ajouter un courtier",
"Kafka Topic Name": "Nom du sujet Kafka",
"Enable Kafka SSL": "Activer Kafka SSL",
"Kafka SASL Options": "Options de Kafka SAS",
"Mechanism": "Mécanisme",
"Pick a SASL Mechanism...": "Choisissez un mécanisme SASL...",
"Authorization Identity": "Identité d'autorisation",
"AccessKey Id": "ID de la clé d'accès",
"Secret AccessKey": "Clé d'accès secrète",
"Session Token": "Jeton de session",
"Kafka Brokers": "Courtiers Kafka",
"Kafka Producer Message": "Message du producteur Kafka",
"Enable Kafka Producer Auto Topic Creation": "Activer la création automatique de rubrique Kafka",
"tailscalePingWarning": "Afin d'utiliser la sonde Tailscale Ping, vous devez installer Uptime Kuma sans Docker et également installer le client Tailscale sur votre serveur.",
"Server URL should not contain the nfty topic": "L'URL du serveur ne doit pas contenir le sujet nfty",
"Select": "Sélectionner",
"selectedMonitorCount": "Sélectionné : {0}",
"Check/Uncheck": "Cocher/décocher",
"nostrRelaysHelp": "Une URL relais par ligne",
"nostrRecipients": "Clés publiques des bénéficiaires (npub)",
"nostrSender": "Émetteur clé privée (nsec)",
"nostrRecipientsHelp": "Format npub, un par ligne",
"nostrRelays": "Relais Nostr",
"PushDeer Server": "PushDeer Server",
"showCertificateExpiry": "Afficher l'expiration du certificat",
"noOrBadCertificate": "Pas/Mauvais certificat",
"pushDeerServerDescription": "Laissez le champ vide pour utiliser le serveur officiel",
"FlashDuty Severity": "Gravité",
"wayToGetFlashDutyKey": "Vous pouvez aller dans Canal -> (Sélectionner un canal) -> Intégrations -> Ajouter une nouvelle page d'intégration, ajouter un \"événement personnalisé\" pour obtenir une adresse push, copier la clé d'intégration dans l'adresse. Pour plus d'informations, veuillez visiter",
"Request Timeout": "Délai d'expiration de la demande",
"timeoutAfter": "Délai dépassé après {0} secondes",
"gamedigGuessPort": "Gamedig: Devinez le port",
"gamedigGuessPortDescription": "Le port utilisé par Valve Server Query Protocol peut être différent du port client. Essayez ceci si la sonde ne peut pas se connecter à votre serveur.",
"styleElapsedTimeShowNoLine": "Afficher (pas de ligne)",
"styleElapsedTimeShowWithLine": "Afficher (avec ligne)",
"styleElapsedTime": "Temps écoulé sous la barre d'état"
}

View File

@@ -445,8 +445,6 @@
"For safety, must use secret key": "לבטיחות, חייב להשתמש במפתח סודיy",
"Device Token": "אסימון מכשיר",
"Platform": "פּלַטפוֹרמָה",
"iOS": "iOS",
"Android": "דְמוּי אָדָם",
"Huawei": "huawei",
"High": "High",
"Retry": "נסה שוב",
@@ -741,5 +739,6 @@
"pagertreeHigh": "גבוהה",
"pagertreeCritical": "קריטי",
"pagertreeResolve": "הגדרה אוטומטית",
"ntfyUsernameAndPassword": "שם משתמש וסיסמא"
"ntfyUsernameAndPassword": "שם משתמש וסיסמא",
"Cannot connect to the socket server": "לא ניתן להתחבר לשקע השרת"
}

View File

@@ -39,5 +39,6 @@
"Reconnecting...": "पुनः कनेक्ट किया जा रहा है...",
"Down": "बंद",
"Passive Monitor Type": "निष्क्रिय मॉनिटर प्रकार",
"Status": "स्थिति"
"Status": "स्थिति",
"showCertificateExpiry": "प्रमाणपत्र समाप्ति दिखाएँ"
}

View File

@@ -113,7 +113,7 @@
"Password": "Lozinka",
"Remember me": "Zapamti me",
"Login": "Prijava",
"No Monitors, please": "Nema monitora, ",
"No Monitors, please": "Nema monitora,",
"add one": "dodaj jedan",
"Notification Type": "Tip obavijesti",
"Email": "E-pošta",
@@ -420,8 +420,6 @@
"For safety, must use secret key": "Korištenje tajnog ključa je obavezno",
"Device Token": "Token uređaja",
"Platform": "Platforma",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Visoko",
"Retry": "Ponovnih pokušaja",

View File

@@ -11,13 +11,13 @@
"acceptedStatusCodesDescription": "Pilih kode status yang dianggap sebagai tanggapan yang berhasil.",
"passwordNotMatchMsg": "Kata 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",
"keywordDescription": "Kata kunci pencarian dalam HTML biasa atau respons JSON. Pencarian bersifat peka terhadap huruf besar/kecil.",
"pauseDashboardHome": "Jeda",
"deleteMonitorMsg": "Apakah Anda mau menghapus monitor ini?",
"deleteNotificationMsg": "Apakah Anda mau menghapus notifikasi untuk semua monitor?",
"dnsPortDescription": "Port server DNS. Bawaan menggunakan 53. Anda dapat mengubah port kapan saja.",
"resolverserverDescription": "Cloudflare adalah server bawaan, Anda dapat mengubah server resolver kapan saja.",
"rrtypeDescription": "Pilih RR-Type yang mau Anda monitor",
"rrtypeDescription": "Pilih RR Type yang mau Anda monitor",
"pauseMonitorMsg": "Apakah Anda yakin mau menjeda?",
"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?",
@@ -25,13 +25,13 @@
"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",
"twoFAVerifyLabel": "Masukkan token Anda untuk memverifikasi 2FA:",
"tokenValidSettingsMsg": "Token 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",
"New Update": "Update terbaru",
"Language": "Bahasa",
"Appearance": "Tampilan",
"Theme": "Tema",
@@ -58,7 +58,7 @@
"Delete": "Hapus",
"Current": "Saat ini",
"Uptime": "Waktu aktif",
"Cert Exp.": "Batas kedaluwarsa SSL",
"Cert Exp.": "Sertifikat Kedaluwarsa.",
"day": "hari | hari-hari",
"-day": "-hari",
"hour": "Jam",
@@ -69,9 +69,9 @@
"Keyword": "Kata Kunci",
"Friendly Name": "Nama yang Ramah",
"URL": "URL",
"Hostname": "Hostname",
"Hostname": "Nama host",
"Port": "Port",
"Heartbeat Interval": "Jarak Waktu Heartbeat",
"Heartbeat Interval": "Rentang Waktu Heartbeat",
"Retries": "Coba lagi",
"Heartbeat Retry Interval": "Jeda Pengulangan Heartbeat",
"Resend Notification if Down X times consecutively": "Kirim Ulang Notifikasi jika Tidak Aktif X kali",
@@ -106,7 +106,7 @@
"Enable Auth": "Aktifkan Autentikasi",
"disableauth.message1": "Apakah Anda yakin ingin <strong>menonaktifkan autentikasi</strong>?",
"disableauth.message2": "Ini untuk <strong>mereka yang memiliki autentikasi pihak ketiga</strong> diletakkan di depan Uptime Kuma, misalnya akses Cloudflare.",
"Please use this option carefully!": "Gunakan dengan hati-hati.",
"Please use this option carefully!": "Silahkan gunakan opsi ini dengan hati-hati!",
"Logout": "Keluar",
"Leave": "Pergi",
"I understand, please disable": "Saya mengerti, silakan dinonaktifkan",
@@ -117,14 +117,14 @@
"Password": "Sandi",
"Remember me": "Ingat saya",
"Login": "Masuk",
"No Monitors, please": "Tidak ada monitor, silakan",
"No Monitors, please": "Tolong, jangan ada Monitor",
"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",
"Resource Record Type": "Jenis Rekam Sumber Daya",
"Last Result": "Hasil Terakhir",
"Create your admin account": "Buat akun admin Anda",
"Repeat Password": "Ulangi Sandi",
@@ -162,7 +162,7 @@
"Token": "Token",
"Show URI": "Lihat URI",
"Tags": "Tanda",
"Add New below or Select...": "Tambahkan Baru di bawah atau Pilih...",
"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",
@@ -175,7 +175,7 @@
"Indigo": "Biru Tua",
"Purple": "Ungu",
"Pink": "Merah Muda",
"Search...": "Cari...",
"Search...": "Cari",
"Avg. Ping": "Rata-rata Ping",
"Avg. Response": "Rata-rata Tanggapan",
"Entry Page": "Halaman Masuk",
@@ -194,7 +194,7 @@
"here": "di sini",
"Required": "Wajib",
"telegram": "Telegram",
"Bot Token": "Bot Token",
"Bot Token": "Token Bot",
"wayToGetTelegramToken": "Anda dapat mendapatkan token dari {0}.",
"Chat ID": "Chat ID",
"supportTelegramChatID": "Mendukung Obrolan Langsung / Grup / Channel Chat ID",
@@ -216,13 +216,13 @@
"smtpCC": "CC",
"smtpBCC": "BCC",
"discord": "Discord",
"Discord Webhook URL": "Discord Webhook URL",
"wayToGetDiscordURL": "Anda bisa mendapatkan ini dengan pergi ke Server Pengaturan -> Integrasi -> Buat Webhook",
"Discord Webhook URL": "URL Webhook Discord",
"wayToGetDiscordURL": "Anda bisa mendapatkan ini dengan pergi ke Server Pengaturan -> Integrasi -> Lihat Webhooks -> Buat Webhook",
"Bot Display Name": "Nama Bot",
"Prefix Custom Message": "Awalan Pesan",
"Hello @everyone is...": "Halo {'@'}everyone is...",
"Hello @everyone is...": "Halo {'@'}everyone is",
"teams": "Microsoft Teams",
"Webhook URL": "Webhook URL",
"Webhook URL": "URL Webhook",
"wayToGetTeamsURL": "Anda dapat mempelajari cara membuat url webhook {0}.",
"signal": "Sinyal",
"Number": "Nomer",
@@ -285,7 +285,7 @@
"lineDevConsoleTo": "Konsol Pengembang Line - {0}",
"Basic Settings": "Pengaturan Dasar",
"User ID": "ID User",
"Messaging API": "Messaging API",
"Messaging API": "API Messaging",
"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.",
@@ -293,7 +293,7 @@
"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.",
"promosmsTypeFull": "SMS FULL - Tingkat Premium SMS, Anda dapat menggunakan Nama Pengirim Anda (Nama Anda harus didaftarkan 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",
@@ -302,7 +302,7 @@
"Internal Room Id": "Internal Room ID",
"matrixDesc1": "Kamu dapat menemukan Internal Room ID dengan melihat di bagian konfigurasi ruang di Matrix. Seharusnya berbentuk seperti !QMdRCpUIfLwsfjxye6:home.server.",
"matrixDesc2": "Sangat direkomendasikan kepada Anda untuk membuat akun baru dan jangan menggunakan token atas akun terkini yang memiliki token akses secara penuh terhadap akun dan seluruh ruang yang terdaftar. Alih - alih, buat akun baru dan undang akun tsb ke ruang tempat anda ingin menerima notifikasi. Untuk mendapatkan token akses anda dapat menjalankan {0}",
"Method": "Method",
"Method": "Metode",
"Body": "Body",
"Headers": "Headers",
"PushUrl": "Push URL",
@@ -315,18 +315,18 @@
"One record": "Satu catatan",
"steamApiKeyDescription": "Untuk monitoring Steam Game Server Anda membutuhkan kunci Steam Web-API. Anda dapat mendaftarkan Kunci API Anda melalui: ",
"Current User": "Pengguna Saat Ini",
"topic": "Topic",
"topicExplanation": "MQTT topic untuk dimonitor",
"topic": "topik",
"topicExplanation": "MQTT topik untuk dimonitor",
"successMessage": "Pesan Berhasil",
"successMessageExplanation": "Pesan MQTT yang akan dianggap berhasil",
"recent": "Baru saja",
"Done": "Selesai",
"Info": "Info",
"Security": "Keamanan",
"Steam API Key": "Steam API Key",
"Shrink Database": "Shrink Database",
"Pick a RR-Type...": "Pilih RR-Type...",
"Pick Accepted Status Codes...": "Pilih Kode Status yang Diterima...",
"Steam API Key": "Kunci API Steam",
"Shrink Database": "Kecilkan Database",
"Pick a RR-Type...": "Pilih RR-Type",
"Pick Accepted Status Codes...": "Pilih Kode Status yang Diterima",
"Default": "Default",
"HTTP Options": "Opsi HTTP",
"Create Incident": "Buat Incident",
@@ -373,8 +373,8 @@
"smtpDkimDesc": "Silakan merujuk ke Nodemailer DKIM {0} untuk penggunaan.",
"documentation": "dokumentasi",
"smtpDkimDomain": "Nama Domain",
"smtpDkimKeySelector": "Key Selector",
"smtpDkimPrivateKey": "Private Key",
"smtpDkimKeySelector": "Selektor Kunci",
"smtpDkimPrivateKey": "Kunci Pribadi",
"smtpDkimHashAlgo": "Algoritma Hash (Opsional)",
"smtpDkimheaderFieldNames": "Header Keys untuk ditambahkan (Optional)",
"smtpDkimskipFields": "Header Keys not untuk ditambahkan (Optional)",
@@ -401,8 +401,8 @@
"proxyDescription": "Proxy harus ditambahkan ke monitor agar berfungsi.",
"enableProxyDescription": "Proxy berikut tidak akan berdampak ke monitor hingga diaktifkan. Anda dapat mengontrol menonaktifkan sementara proxy dari semua monitor dengan status aktivasi.",
"setAsDefaultProxyDescription": "Proxy berikut akan diaktifkan sebagai bawaan untuk monitor baru. Anda masih dapat menonaktifkan proxy secara terpisah untuk setiap monitor.",
"Certificate Chain": "Certificate Chain",
"Valid": "Valid",
"Certificate Chain": "Rangkaian Sertifikat",
"Valid": "Berlaku",
"Invalid": "Tidak Valid",
"AccessKeyId": "AccessKey ID",
"SecretAccessKey": "AccessKey Secret",
@@ -418,8 +418,6 @@
"For safety, must use secret key": "Untuk keamaan Anda harus menggunakan kunci rahasia",
"Device Token": "Token Perangkat",
"Platform": "Platform",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Tinggi",
"Retry": "Ulang",
@@ -447,7 +445,7 @@
"The slug is already taken. Please choose another slug.": "Slug telah digunakan. Silakan pilih slug lain.",
"No Proxy": "Tidak ada Proxy",
"Authentication": "Autentikasi",
"HTTP Basic Auth": "HTTP Basic Auth",
"HTTP Basic Auth": "Autentikasi Dasar HTTP",
"New Status Page": "Halaman Status Baru",
"Page Not Found": "Halaman Tidak Ditemukan",
"Reverse Proxy": "Proxy Terbalik",
@@ -458,7 +456,7 @@
"Message:": "Pesan:",
"Don't know how to get the token? Please read the guide:": "Tidak tahu cara mendapatkan token? Silakan baca panduannya:",
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Koneksi saat ini mungkin hilang jika Anda saat ini terhubung melalui Cloudflare Tunel. Apakah Anda yakin ingin menghentikannya? Ketik kata sandi Anda saat ini untuk mengonfirmasinya.",
"HTTP Headers": "HTTP Headers",
"HTTP Headers": "Header HTTP",
"Trust Proxy": "Proxy Terpercaya",
"Other Software": "Perangkat Lunak lainnya",
"For example: nginx, Apache and Traefik.": "Sebagai contoh: nginx, Apache and Traefik.",
@@ -512,12 +510,12 @@
"pushoversounds cosmic": "Cosmic",
"pushoversounds falling": "Falling",
"pushoversounds gamelan": "Gamelan",
"pushoversounds incoming": "Incoming",
"pushoversounds intermission": "Intermission",
"pushoversounds incoming": "Masuk",
"pushoversounds intermission": "Jeda",
"pushoversounds magic": "Magic",
"pushoversounds mechanical": "Mechanical",
"pushoversounds mechanical": "Mekanik",
"pushoversounds pianobar": "Piano Bar",
"pushoversounds siren": "Siren",
"pushoversounds siren": "Sirene",
"pushoversounds spacealarm": "Space Alarm",
"pushoversounds tugboat": "Tug Boat",
"pushoversounds alien": "Alien Alarm (long)",
@@ -553,17 +551,17 @@
"socket": "Socket",
"tcp": "TCP / HTTP",
"Docker Container": "Docker Container",
"Container Name / ID": "Container Name / ID",
"Docker Host": "Docker Host",
"Docker Hosts": "Docker Hosts",
"Container Name / ID": "Nama / ID Container",
"Docker Host": "Host Docker",
"Docker Hosts": "Hosts Docker",
"ntfy Topic": "ntfy Topic",
"Domain": "Domain",
"Workstation": "Workstation",
"disableCloudflaredNoAuthMsg": "Anda berada dalam mode Tanpa Otentikasi, kata sandi tidak diperlukan.",
"trustProxyDescription": "Trust 'X-Forwarded-*' headers. Jika Anda ingin mendapatkan IP klien yang benar dan Uptime Kuma Anda dibalik layanan seperti Nginxor Apache, Anda harus mengaktifkan ini.",
"trustProxyDescription": "Trust 'X-Forwarded-*' headers. Jika Anda ingin mendapatkan IP klien yang benar dan Uptime Kuma Anda dibalik proxy seperti Nginx or Apache, Anda harus mengaktifkan ini.",
"wayToGetLineNotifyToken": "Anda bisa mendapatkan token akses dari {0}",
"Examples": "Contoh",
"Home Assistant URL": "Home Assistant URL",
"Home Assistant URL": "URL Home Asisten",
"Long-Lived Access Token": "Token Akses Berumur Panjang",
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Token Akses Berumur Panjang dapat dibuat dengan mengklik nama profil Anda (kiri bawah) dan menggulir ke bawah lalu klik Buat Token. ",
"Notification Service": "Layanan Pemberitahuan",
@@ -580,15 +578,215 @@
"goAlertInfo": "GoAlert adalah aplikasi open source untuk penjadwalan panggilan, eskalasi otomatis dan pemberitahuan (seperti SMS atau panggilan suara). Secara otomatis melibatkan orang yang tepat, dengan cara yang benar, dan pada waktu yang tepat! {0}",
"goAlertIntegrationKeyInfo": "Dapatkan kunci integrasi API generik untuk layanan dalam format ini \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" biasanya nilai parameter token dari URL yang disalin.",
"goAlert": "GoAlert",
"backupOutdatedWarning": "Tidak digunakan lagi: Karena banyak fitur ditambahkan dan fitur cadangan ini agak tidak terawat, itu tidak dapat menghasilkan atau memulihkan cadangan lengkap.",
"backupRecommend": "Harap cadangkan volume atau folder data (./data/) secara langsung.",
"backupOutdatedWarning": "Tidak digunakan lagi: Karena banyak fitur ditambahkan dan fitur pencadangan ini agak tidak terpelihara, fitur ini tidak dapat menghasilkan atau memulihkan cadangan lengkap.",
"backupRecommend": "Silahkan backup volume atau folder (./data/) secara langsung.",
"Help": "Bantuan",
"Game": "Gim/Permainan",
"Game": "Permainan",
"markdownSupported": "Dukungan sintaks markdown",
"statusMaintenance": "Pemeliharaan",
"Maintenance": "Pemeliharaan",
"General Monitor Type": "Tipe Monitor Umum",
"Passive Monitor Type": "Tipe Monitor Pasif",
"Specific Monitor Type": "Tipe Monitor Spesifik",
"Monitor": "Monitor"
"Monitor": "Monitor",
"Guild ID": "ID Guild",
"twilioAccountSID": "SID akun",
"twilioAuthToken": "Token Autentikasi",
"ntfyAuthenticationMethod": "Metode Autentikasi",
"ntfyUsernameAndPassword": "Nama pengguna dan kata sandi",
"Add Another": "Tambah Lainnya",
"Key Added": "Kunci Ditambahkan",
"Google Analytics ID": "ID Google Analytics",
"pagertreeIntegrationUrl": "URL integrasi",
"pagertreeUrgency": "Darurat",
"Home": "Beranda",
"startDateTime": "Tanggal/Waktu Mulai",
"Recurring": "Berulang",
"strategyManual": "Aktif/TidakAktif Secara Manual",
"infiniteRetention": "Setel ke 0 untuk retensi tak terbatas.",
"enableGRPCTls": "Izinkan untuk mengirim permintaan gRPC dengan koneksi TLS",
"grpcMethodDescription": "Nama metode dikonversi ke format cammelCase seperti sayHello, check, dll.",
"deleteMaintenanceMsg": "Apakah Anda yakin ingin menghapus pemeliharaan ini?",
"Free Mobile API Key": "Kunci API Seluler Gratis",
"Enable TLS": "Aktifkan TLS",
"Proto Method": "Metode Proto",
"Proto Content": "Konten Proto",
"Economy": "Ekonomi",
"Free Mobile User Identifier": "Pengidentifikasi Pengguna Seluler",
"Proto Service Name": "Nama Layanan Proto",
"SMSManager API Docs": "Dokumen API SMSManager ",
"Expiry date": "Tanggal kadaluarsa",
"No API Keys": "Tidak ada Kunci API",
"Expires": "Berakhir",
"pagertreeCritical": "Penting",
"pagertreeResolve": "Penyelesaian Otomatis",
"lunaseaDeviceID": "ID perangkat",
"lunaseaUserID": "ID Pengguna",
"twilioFromNumber": "Dari Nomor",
"twilioToNumber": "Ke Nomor",
"Badge Generator": "Pembuat Lencana {0}",
"Badge Duration": "Durasi Lencana",
"Badge Label": "Label Lencana",
"Badge Prefix": "Prefiks Lencana",
"Badge Suffix": "Suffix Lencana",
"Badge Label Color": "Warna Label Lencana",
"Badge Color": "Warna Lencana",
"Badge Label Prefix": "Prefiks Label Lencana",
"telegramSendSilently": "Kirim Secara Senyap",
"Invert Keyword": "Balikkan Kata Kunci",
"Pick Affected Monitors...": "Pilih Monitor yang Terkena Dampak…",
"Badge Label Suffix": "Suffix Label Lencana",
"statusPageMaintenanceEndDate": "berakhir",
"Add API Key": "Tambahkan Kunci API",
"apiKey-expired": "Kedaluwarsa",
"apiKey-active": "Aktif",
"apiKey-inactive": "Tidak aktif",
"Monitor Setting": "Pengaturan Pemantauan {0}",
"Show Clickable Link": "Tampilkan Tautan yang Dapat Diklik",
"Badge Type": "Tipe lencana",
"confirmDeleteTagMsg": "Yakin ingin menghapus tag ini? Monitor yang terkait dengan tag ini tidak akan dihapus.",
"Gateway Type": "tipe Gateway",
"Don't expire": "Jangan sampai kadaluarsa",
"apiKeyAddedMsg": "Kunci API Anda telah ditambahkan. Mohon dicatat karena tidak akan ditampilkan lagi.",
"disableAPIKeyMsg": "Yakin ingin menonaktifkan kunci API ini?",
"pagertreeSilent": "Bisu",
"pagertreeLow": "Rendah",
"pagertreeDoNothing": "Jangan Lakukan Apa-apa",
"wayToGetPagerTreeIntegrationURL": "Setelah membuat integrasi Uptime Kuma di PagerTree, salin Endpoint. Lihat detail lengkap {0}",
"lunaseaTarget": "Sasaran",
"Show Clickable Link Description": "Jika dicentang, setiap orang yang memiliki akses ke halaman status ini dapat memiliki akses ke URL monitor.",
"Open Badge Generator": "Buka Pembuat Lencana",
"Cannot connect to the socket server": "Tidak dapat terhubung ke server soket",
"Reconnecting...": "Menghubungkan ulang...",
"deleteAPIKeyMsg": "Apakah Anda yakin ingin menghapus kunci API ini?",
"Generate": "Hasilkan",
"pagertreeMedium": "Sedang",
"pagertreeHigh": "Tinggi",
"Group": "Grup",
"Body Encoding": "Body Encoding",
"Add New Tag": "Tambahkan Tag Baru",
"chromeExecutableDescription": "Untuk pengguna Docker, jika Chromium belum diinstal, mungkin perlu waktu beberapa menit untuk menginstal dan menampilkan hasil pengujian. Dibutuhkan 1GB ruang penyimpanan.",
"recurringIntervalMessage": "Jalankan sekali setiap hari | Jalankan sekali setiap {0} hari",
"wayToGetKookBotToken": "Buat aplikasi dan dapatkan token bot Anda di {0}",
"Custom Monitor Type": "Tipe Monitor Khusus",
"API Keys": "Kunci API",
"Expiry": "Kadaluarsa",
"noGroupMonitorMsg": "Tidak tersedia. Buat Monitor Grup Terlebih Dahulu.",
"Close": "Tutup",
"telegramMessageThreadID": "(Opsional) ID Pesan",
"Date and Time": "Tanggal dan waktu",
"Single Maintenance Window": "Jendela Pemeliharaan Tunggal",
"wayToGetZohoCliqURL": "Anda dapat mempelajari cara membuat URL webhook {0}.",
"dayOfWeek": "Hari dalam seminggu",
"dayOfMonth": "Hari dalam Bulan",
"lastDay": "Hari terakhir",
"Clone Monitor": "Klon Monitor",
"Clone": "Klon",
"Server Address": "Alamat server",
"Edit Tag": "Sunting Tag",
"smseagleTo": "Nomor telepon",
"maintenanceStatus-under-maintenance": "Dalam perbaikan",
"webhookAdditionalHeadersDesc": "Menetapkan header tambahan yang dikirim dengan webhook. Setiap header harus didefinisikan sebagai kunci/nilai JSON.",
"webhookCustomBodyDesc": "Tentukan Body HTTP khusus untuk permintaan tersebut. Variabel template {msg}, {heartbeat}, {monitor} yang diterima.",
"webhookBodyPresetOption": "Prasetel - {0}",
"webhookBodyCustomOption": "Body Kustom",
"Packet Size": "Ukuran Paket",
"telegramMessageThreadIDDescription": "Pengidentifikasi unik Opsional untuk pesan target (topik) forum; untuk forum supergrup saja",
"telegramProtectContent": "Lindungi Forwarding/Saving",
"or": "atau",
"sameAsServerTimezone": "Sama seperti Zona Waktu Server",
"endDateTime": "Tanggal/Waktu Berakhir",
"cronExpression": "Ekspresi Cron",
"cronSchedule": "Jadwal: ",
"invalidCronExpression": "Ekspresi Cron Tidak Valid: {0}",
"recurringInterval": "Selang waktu",
"warningTimezone": "Itu menggunakan zona waktu server",
"weekdayShortMon": "Senin",
"weekdayShortTue": "Selasa",
"weekdayShortWed": "Rabu",
"weekdayShortThu": "Kamis",
"weekdayShortFri": "Jum'at",
"weekdayShortSat": "Sabtu",
"weekdayShortSun": "Minggu",
"lastDay1": "Hari Terakhir dalam Sebulan",
"lastDay2": "2 Hari Terakhir Bulan Ini",
"lastDay3": "3 Hari Terakhir Bulan Ini",
"lastDay4": "4 Hari Terakhir Bulan Ini",
"No Maintenance": "Tidak Ada Pemeliharaan",
"pauseMaintenanceMsg": "Anda yakin ingin menjeda?",
"maintenanceStatus-inactive": "Tidak aktif",
"Display Timezone": "Tampilkan Zona Waktu",
"IconUrl": "URL ikon",
"Enable DNS Cache": "Aktifkan Cache DNS",
"Enable": "Aktifkan",
"Disable": "Nonaktifkan",
"affectedStatusPages": "Tampilkan pesan pemeliharaan ini pada halaman status yang dipilih",
"invertKeywordDescription": "Carilah kata kunci untuk menjadi tidak ada daripada hadir.",
"wayToGetKookGuildID": "Aktifkan 'Mode Pengembang' di pengaturan Kook, dan klik kanan guild untuk mendapatkan ID-nya",
"Strategy": "Strategi",
"high": "tinggi",
"SendKey": "SendKey",
"Lowcost": "rendah",
"smseagleContact": "nama kontak buku telepon",
"smseagleRecipient": "Penerima (jika banyak harus dipisahkan dengan koma)",
"smseagleEncoding": "Kirim sebagai Unicode",
"smseaglePriority": "Prioritas pesan (0-9, default = 0)",
"Learn More": "Pelajari lebih lanjut",
"Badge Up Color": "Warna atas Lencana",
"Badge Maintenance Color": "Warna Lencana Pemeliharaan",
"Badge Warn Color": "Warna Lencana Peringatan",
"Request Body": "Permintaan Body",
"uninstalling": "Menghapus instalan",
"notificationRegional": "Daerah",
"atLeastOneMonitor": "Pilih setidaknya satu monitor yang terpengaruh",
"pushoverMessageTtl": "TTL pesan (Detik)",
"smseagleGroup": "Nama grup buku telepon",
"smseagleRecipientType": "Tipe Penerima",
"smseagleToken": "Token Akses API",
"smseagleUrl": "URL perangkat SMSEagle Anda",
"Schedule maintenance": "Jadwalkan pemeliharaan",
"Affected Monitors": "Monitor yang Terpengaruh",
"Start of maintenance": "Mulai pemeliharaan",
"All Status Pages": "Semua Halaman Status",
"Select status pages...": "Pilih halaman status…",
"Custom": "Khusus",
"Optional": "Opsional",
"dnsCacheDescription": "Ini mungkin tidak berfungsi di beberapa lingkungan IPv6, nonaktifkan jika Anda mengalami masalah.",
"Maintenance Time Window of a Day": "Jendela Waktu Perawatan dalam Sehari",
"Effective Date Range": "Rentang Tanggal Efektif (Opsional)",
"Schedule Maintenance": "Jadwal Pemeliharaan",
"Badge Down Color": "Warna bawah Lencana",
"Badge Warn Days": "Hari Lencana Peringatan",
"statusPageRefreshIn": "Muat ulang dalam: {0}",
"webhookAdditionalHeadersTitle": "Header Tambahan",
"maintenanceStatus-unknown": "Tidak dikenal",
"Server Timezone": "Zona Waktu Server",
"maintenanceStatus-scheduled": "Dijadwalkan",
"maintenanceStatus-ended": "Berakhir",
"dataRetentionTimeError": "Periode retensi harus 0 atau lebih besar",
"chromeExecutable": "Chrome/Chromium Dapat Dijalankan",
"chromeExecutableAutoDetect": "Deteksi otomatis",
"Edit Maintenance": "Sunting Pemeliharaan",
"DateTime Range": "Rentang Tanggal dan Waktu",
"loadingError": "Tidak dapat mengambil data, harap coba lagi nanti.",
"installing": "Memasang",
"uninstall": "Copot pemasangan",
"confirmUninstallPlugin": "Anda yakin ingin mencopot pemasangan plugin ini?",
"cloneOf": "Klon dari {0}",
"affectedMonitorsDescription": "Pilih monitor yang terpengaruh oleh pemeliharaan saat ini",
"You can divide numbers with": "Anda dapat membagi angka dengan",
"Continue": "Lanjutkan",
"Badge Style": "Gaya Lencana",
"Badge value (For Testing only.)": "Nilai lencana (Hanya untuk Pengujian.)",
"Badge URL": "URL lencana",
"Badge Down Days": "Hari Penghentian Lencana",
"telegramSendSilentlyDescription": "Mengirim pesan secara senyap. Pengguna akan menerima notifikasi tanpa suara.",
"telegramProtectContentDescription": "Jika diaktifkan, pesan bot di Telegram akan dilindungi dari forwarding dan saving.",
"plugin": "Pengaya | Plugin",
"install": "Pasang",
"promosmsAllowLongSMS": "Izinkan SMS panjang",
"Badge Pending Color": "Warna Lencana Tertunda",
"Monitor Group": "Monitor Grup",
"Expected Value": "Value yang diharapkan",
"Json Query": "Json Query"
}

View File

@@ -159,7 +159,7 @@
"Show URI": "Mostra URI",
"Tags": "Etichette",
"Add New below or Select...": "Aggiungi oppure scegli…",
"Tag with this name already exist.": "Un'etichetta con questo nome già esiste.",
"Tag with this name already exist.": "Un'etichetta con questo nome esiste già.",
"Tag with this value already exist.": "Un'etichetta con questo valore già esiste.",
"color": "colore",
"value (optional)": "descrizione (opzionale)",
@@ -177,7 +177,7 @@
"Entry Page": "Pagina Principale",
"statusPageNothing": "Non c'è nulla qui, aggiungi un gruppo oppure un monitor.",
"No Services": "Nessun servizio",
"All Systems Operational": "Tutti i sistemi sono funzionali",
"All Systems Operational": "Tutti i sistemi sono funzionanti",
"Partially Degraded Service": "Servizio parzialmente degradato",
"Degraded Service": "Servizio degradato",
"Add Group": "Aggiungi gruppo",
@@ -213,7 +213,7 @@
"smtpBCC": "CCn",
"discord": "Discord",
"Discord Webhook URL": "URL Webhook di Discord",
"wayToGetDiscordURL": "È possibile recuperarlo da Impostazioni server -> Integrazioni -> Creare Webhook",
"wayToGetDiscordURL": "Puoi ottenerlo andando su Impostazioni server -> Integrazioni -> Visualizza webhook -> Nuovo webhook",
"Bot Display Name": "Nome del Bot",
"Prefix Custom Message": "Prefisso per il messaggio personalizzato",
"Hello @everyone is...": "Ciao a {'@'}everyone …",
@@ -384,7 +384,7 @@
"resendDisabled": "Reinvio disabilitato",
"Resend Notification if Down X times consequently": "Reinvia la notifica se Down X volte di seguito",
"Add New Status Page": "Aggiungi nuova pagina di stato",
"webhookAdditionalHeadersDesc": "Imposta gli header aggiuntivi inviati nel webhook.",
"webhookAdditionalHeadersDesc": "Imposta intestazioni aggiuntive inviate con il webhook. Ogni intestazione deve essere definita come chiave/valore JSON.",
"topicExplanation": "MQTT topic da controllare",
"successMessage": "Messaggio con successo",
"successMessageExplanation": "Messaggio MQTT considerato come successo",
@@ -417,5 +417,198 @@
"Affected Monitors": "Monitoraggi interessati",
"Pick Affected Monitors...": "Seleziona i monitoraggi interessati…",
"Valid": "Valido",
"Certificate Expiry Notification": "Notifica scadenza certificato"
"Certificate Expiry Notification": "Notifica scadenza certificato",
"styleElapsedTimeShowWithLine": "Mostra (con linea)",
"webhookBodyPresetOption": "Predefinito - {0}",
"webhookBodyCustomOption": "Corpo personalizzato",
"topic": "Topic",
"selectedMonitorCount": "Selezionato: {0}",
"Check/Uncheck": "Seleziona/Deseleziona",
"Proxies": "Proxy",
"Stop": "Fermare",
"startOrEndWithOnly": "Inizia o termina solo con {0}",
"No consecutive dashes": "Nessun trattino consecutivo",
"HTTP Basic Auth": "Autenticazione di base HTTP",
"Reverse Proxy": "Proxy inverso",
"Backup": "Backup",
"About": "Di",
"wayToGetCloudflaredURL": "(Scarica cloudflared da {0})",
"cloudflareWebsite": "Sito web di Cloudflare",
"Message:": "Messaggio:",
"Don't know how to get the token? Please read the guide:": "Non sai come ottenere il token? Si prega di leggere la guida:",
"Trust Proxy": "Proxy di fiducia",
"Other Software": "Altro Software",
"For example: nginx, Apache and Traefik.": "Ad esempio: nginx, Apache e Traefik.",
"Please read": "Si prega di leggere",
"Subject:": "Soggetto:",
"Valid To:": "Valido per:",
"Days Remaining:": "Giorni rimanenti:",
"Issuer:": "Emittente",
"Fingerprint:": "Impronta digitale:",
"No status pages": "Nessuna pagina di stato",
"Domain Name Expiry Notification": "Notifica di scadenza del nome di dominio",
"Date Created": "Data di creazione",
"Slug": "Slug",
"Show Powered By": "Mostra Alimentato da",
"Domain Names": "Nomi di dominio",
"signedInDispDisabled": "Autenticazione disabilitata.",
"RadiusSecret": "Radius Segreto",
"RadiusCalledStationId": "Identificativo della stazione chiamata",
"RadiusCallingStationId": "Id stazione chiamante",
"RadiusCallingStationIdDescription": "Identificativo del dispositivo chiamante",
"API Username": "Nome utente dell'API",
"API Key": "Chiave dell'API",
"Show update if available": "Mostra aggiornamento se disponibile",
"RadiusSecretDescription": "Segreto condiviso tra client e server",
"Also check beta release": "Controlla anche la versione beta",
"Check how to config it for WebSocket": "Controlla come configurarlo per WebSocket",
"Steam Game Server": "Server di gioco Steam",
"Most likely causes:": "Cause più probabili:",
"The resource is no longer available.": "La risorsa non è più disponibile.",
"What you can try:": "Cosa puoi provare:",
"Retype the address.": "Ridigita l'indirizzo.",
"Go back to the previous page.": "Torna alla pagina precedente.",
"Coming Soon": "Prossimamente",
"Connection String": "Stringa di connessione",
"Query": "Richiesta",
"settingsCertificateExpiry": "Scadenza certificato TLS",
"deleteDockerHostMsg": "Sei sicuro di voler eliminare questo host docker per tutti i monitor?",
"tcp": "TCP / HTTP",
"Docker Container": "Contenitore Docker",
"Container Name / ID": "Nome/ID contenitore",
"Docker Host": "Host Docker",
"Docker Hosts": "Host Docker",
"Domain": "Dominio",
"Workstation": "Postazione di lavoro",
"Packet Size": "Dimensione del pacchetto",
"Setup Docker Host": "Configurare l'host Docker",
"telegramSendSilently": "Invia silenziosamente",
"telegramSendSilentlyDescription": "Invia il messaggio in silenzio. Gli utenti riceveranno una notifica senza audio.",
"telegramProtectContent": "Proteggi inoltro/salvataggio",
"disableCloudflaredNoAuthMsg": "Sei in modalità No Auth, non è richiesta una password.",
"wayToGetLineNotifyToken": "Puoi ottenere un token di accesso da {0}",
"Examples": "Esempi",
"Long-Lived Access Token": "Token di accesso di lunga durata",
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Il token di accesso di lunga durata può essere creato facendo clic sul nome del tuo profilo (in basso a sinistra) e scorrendo verso il basso, quindi fai clic su Crea token. ",
"Notification Service": "Servizio di notifica",
"default: notify all devices": "default: notifica a tutti i dispositivi",
"Automations can optionally be triggered in Home Assistant:": "Le automazioni possono essere facoltativamente attivate in Home Assistant:",
"Trigger type:": "Tipo di attivazione:",
"Event type:": "Tipo di evento:",
"Event data:": "Dati dell'evento:",
"Then choose an action, for example switch the scene to where an RGB light is red.": "Quindi scegli un'azione, ad esempio cambia la scena in cui una luce RGB è rossa.",
"Frontend Version": "Versione front-end",
"Frontend Version do not match backend version!": "La versione del frontend non corrisponde alla versione del backend!",
"backupOutdatedWarning": "Deprecato: poiché sono state aggiunte molte funzionalità e questa funzionalità di backup è un po' trascurata, non può generare o ripristinare un backup completo.",
"backupRecommend": "Eseguire invece il backup diretto del volume o della cartella dei dati (./data/).",
"Optional": "Opzionale",
"sameAsServerTimezone": "Uguale al fuso orario del server",
"startDateTime": "Data/ora di inizio",
"endDateTime": "Data/ora di fine",
"cronExpression": "Espressione Cron",
"cronSchedule": "Programma: ",
"recurringInterval": "Intervallo",
"Recurring": "Ricorrente",
"strategyManual": "Attivo/Inattivo manualmente",
"warningTimezone": "Sta usando il fuso orario del server",
"weekdayShortMon": "Lun",
"weekdayShortTue": "Mar",
"weekdayShortWed": "Mer",
"weekdayShortThu": "Gio",
"weekdayShortSat": "Sab",
"weekdayShortSun": "Dom",
"dayOfWeek": "Giorno della settimana",
"dayOfMonth": "Giorno del mese",
"lastDay": "Ultimo giorno",
"lastDay1": "Ultimo giorno del mese",
"lastDay3": "3° ultimo giorno del mese",
"lastDay4": "4° ultimo giorno del mese",
"No Maintenance": "Nessuna manutenzione",
"pauseMaintenanceMsg": "Sei sicuro di voler mettere in pausa?",
"maintenanceStatus-inactive": "Inattivo",
"maintenanceStatus-scheduled": "Programmato",
"maintenanceStatus-ended": "Conclusa",
"maintenanceStatus-unknown": "Sconosciuto",
"Display Timezone": "Mostra fuso orario",
"Server Timezone": "Fuso orario del server",
"statusPageMaintenanceEndDate": "Fine",
"IconUrl": "URL dell'icona",
"Enable DNS Cache": "Abilita la cache DNS per i monitor HTTP(s).",
"Enable": "Abilitare",
"Disable": "Disattivare",
"chromeExecutableAutoDetect": "Trovato automaticamente",
"dnsCacheDescription": "Potrebbe non funzionare in alcuni ambienti IPv6, disabilitalo in caso di problemi.",
"Single Maintenance Window": "Singola finestra di manutenzione",
"Maintenance Time Window of a Day": "Finestra temporale di manutenzione di un giorno",
"Effective Date Range": "Intervallo di date effettivo (facoltativo)",
"Schedule Maintenance": "Pianificare la manutenzione",
"Edit Maintenance": "Modifica Manutenzione",
"Date and Time": "Data e ora",
"DateTime Range": "Intervallo DataOra",
"loadingError": "Impossibile recuperare i dati, riprova più tardi.",
"plugin": "Plug-in | Plugin",
"install": "Installare",
"installing": "Installazione",
"uninstall": "Disinstalla",
"confirmUninstallPlugin": "Sei sicuro di voler disinstallare questo plugin?",
"notificationRegional": "Regionale",
"Clone": "Clone",
"cloneOf": "Clone di {0}",
"wayToGetZohoCliqURL": "Puoi scoprire come creare un URL webhook {0}.",
"dataRetentionTimeError": "Il periodo di conservazione deve essere pari o superiore a 0",
"infiniteRetention": "Impostare su 0 per la conservazione infinita.",
"enableGRPCTls": "Consenti l'invio di richieste gRPC con connessione TLS",
"grpcMethodDescription": "Il nome del metodo viene convertito nel formato cammelCase come sayHello, check, ecc.",
"styleElapsedTimeShowNoLine": "Mostra (nessuna riga)",
"Add New Tag": "Aggiungi nuova etichetta",
"webhookCustomBodyDesc": "Definire un corpo HTTP personalizzato per la richiesta. Le variabili modello {msg}, {heartbeat}, {monitor} sono accettate.",
"Select": "Selezionare",
"Accept characters:": "Accetta caratteri:",
"The slug is already taken. Please choose another slug.": "La lumaca è già slug. Scegli un'altra slug.",
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "La connessione corrente potrebbe andare persa se ti stai connettendo tramite Cloudflare Tunnel. Sei sicuro di volerlo fermare? Digita la tua password attuale per confermarla.",
"Footer Text": "Testo piè di pagina",
"signedInDisp": "Accesso eseguito come {0}",
"RadiusCalledStationIdDescription": "Identificativo del dispositivo chiamato",
"Clone Monitor": "Monitoraggio clonazione",
"styleElapsedTime": "Tempo trascorso sotto la barra del battito cardiaco",
"enableProxyDescription": "Questo proxy non avrà effetto sulle richieste di monitoraggio fino a quando non viene attivato. È possibile controllare la disabilitazione temporanea del proxy da tutti i monitor in base allo stato di attivazione.",
"Using a Reverse Proxy?": "Utilizzo di un proxy inverso?",
"There might be a typing error in the address.": "Potrebbe esserci un errore di battitura nell'indirizzo.",
"certificationExpiryDescription": "HTTPS monitora la notifica di attivazione quando il certificato TLS scade tra:",
"tailscalePingWarning": "Per utilizzare il monitor Tailscale Ping, è necessario installare Uptime Kuma senza Docker e installare anche il client Tailscale sul server.",
"telegramMessageThreadID": "(Facoltativo) ID thread messaggio",
"telegramMessageThreadIDDescription": "Facoltativo Identificatore univoco per il thread del messaggio di destinazione (argomento) del forum; solo per i supergruppi del forum",
"telegramProtectContentDescription": "Se abilitato, i messaggi del bot in Telegram saranno protetti dall'inoltro e dal salvataggio.",
"trustProxyDescription": "Fidati delle intestazioni 'X-Forwarded-*'. Se vuoi ottenere l'IP client corretto e il tuo Uptime Kuma è dietro un proxy come Nginx o Apache, dovresti abilitarlo.",
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Un elenco di servizi di notifica è disponibile in Home Assistant in \"Strumenti per sviluppatori> Servizi\" cerca \"notifica\" per trovare il nome del tuo dispositivo/telefono.",
"invalidCronExpression": "Espressione Cron non valida: {0}",
"lastDay2": "2° ultimo giorno del mese",
"maintenanceStatus-under-maintenance": "In manutenzione",
"chromeExecutable": "Cromo/cromo eseguibile",
"chromeExecutableDescription": "Per gli utenti Docker, se Chromium non è ancora installato, potrebbero essere necessari alcuni minuti per l'installazione e la visualizzazione del risultato del test. Richiede 1 GB di spazio su disco.",
"uninstalling": "Disinstallazione",
"confirmDeleteTagMsg": "Sei sicuro di voler eliminare questo tag? I monitor associati a questo tag non verranno eliminati.",
"Request Timeout": "Richiedi timeout",
"timeoutAfter": "Timeout dopo {0} secondi",
"Resend Notification if Down X times consecutively": "Invia di nuovo la notifica se giù X volte consecutivamente",
"Proxy": "Proxy",
"or": "o",
"statusPageRefreshIn": "Aggiorna tra: {0}",
"HTTP Headers": "Intestazioni HTTP",
"Custom": "Personalizzato",
"Connection Type": "Tipo di connessione",
"Docker Daemon": "Deamon Docker",
"socket": "Socket",
"Home Assistant URL": "URL dell'assistente domestico",
"weekdayShortFri": "Ven",
"Home": "Accoglienza",
"Invert Keyword": "Inverti parola chiave",
"filterActive": "Attiva",
"filterActivePaused": "In pausa",
"Cannot connect to the socket server": "Impossibile connettersi al server socket",
"Reconnecting...": "Riconnessione...",
"Expected Value": "Valore atteso",
"Json Query": "Query Json",
"deleteMaintenanceMsg": "Sei sicuro di voler cancellare questa attività di manutenzione?",
"dnsPortDescription": "Porta server DNS. Default 53. Puoi cambiare questa porta in ogni momento."
}

View File

@@ -507,7 +507,6 @@
"lineDevConsoleTo": "Line Developers Console - {0}",
"Basic Settings": "基本設定",
"User ID": "User ID",
"Android": "Android",
"Huawei": "Huawei",
"Device Token": "デバイストークン",
"recurringIntervalMessage": "毎日1回実行する{0} 日に1回実行する",
@@ -516,5 +515,42 @@
"Body Encoding": "ボディエンコード",
"Learn More": "さらに詳しく",
"infiniteRetention": "保持期間を無制限にしたい場合は、0に設定してください。",
"Display Timezone": "表示タイムゾーン"
"Display Timezone": "表示タイムゾーン",
"startDateTime": "開始日時",
"User Key": "ユーザーキー",
"SecretKey": "シークレットキー",
"Home": "ホーム",
"webhookBodyCustomOption": "カスタムbody",
"octopushPhoneNumber": "電話番号 (初期フォーマット, 例: +33612345678) ",
"Topic": "トピック",
"pushoverMessageTtl": "メッセージTTL(秒)",
"apiCredentials": "API認証情報",
"Economy": "エコノミー",
"statusPageRefreshIn": "{0}後に再読み込みします",
"filterActivePaused": "停止中",
"filterActive": "有効",
"Example:": "例: {0}",
"Read more:": "さらに: {0}",
"Status:": "ステータス: {0}",
"Enable TLS": "TLS 有効",
"AccessKeyId": "アクセスキーID",
"SecretAccessKey": "アクセスキーシークレット",
"PhoneNumbers": "携帯電話番号",
"Date and Time": "日時",
"chromeExecutableAutoDetect": "自動検出",
"More info on:": "詳細はこちら: {0}",
"Cannot connect to the socket server": "ソケットサーバーに接続できません",
"Reconnecting...": "再接続中...",
"endDateTime": "終了日時",
"cronSchedule": "スケジュール ",
"Edit Maintenance": "メンテナンスの編集",
"WebHookUrl": "ウェブフックUrl",
"Notification Service": "通知サービス",
"atLeastOneMonitor": "最低一つは影響を受けるモニターを選択してください",
"Json Query": "Jsonクエリ",
"octopushSMSSender": "SMS送信者名311文字の英数字とスペースazAz09",
"Lowcost": "低コスト",
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "通知サービスの一覧からデバイス名を見つけるには、Home Assistantの「開発者ツール > サービス」から通知で検索してください。",
"Notify Channel": "通知チャンネル",
"Icon Emoji": "絵文字アイコン"
}

View File

@@ -413,8 +413,6 @@
"For safety, must use secret key": "안전을 위해 꼭 Secret Key를 사용하세요.",
"Device Token": "기기 Token",
"Platform": "플랫폼",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "High",
"Retry": "재시도",
@@ -591,6 +589,8 @@
"RadiusCalledStationIdDescription": "접속 스테이션의 식별자",
"RadiusCallingStationId": "접속 요청 스테이션의 Id",
"RadiusCallingStationIdDescription": "접속 요청 스테이션의 식별자",
"timeoutAfter": "{0}초 후 타임아웃",
"Request Timeout": "요청 타임아웃",
"Query": "쿼리",
"settingsCertificateExpiry": "TLS 인증서 만료",
"certificationExpiryDescription": "HTTPS 모니터링 TLS 인증서가 만료되면 알림을 활성화해요:",

93
src/lang/my.json Normal file
View File

@@ -0,0 +1,93 @@
{
"languageName": "အင်္ဂလိပ်ဘာသာ",
"Settings": "ပြင်ဆင်ချက်များ",
"Help": "အကူအညီ",
"New Update": "အသစ်ထွက်ရှိခြင်း",
"Language": "ဘာသာစကား",
"Appearance": "သွင်ပြင်လက္ခဏာ",
"Theme": "သဏ္ဍာန်",
"General": "အထွေထွေ",
"Primary Base URL": "ဦးစားပေးအင်တာနက်လိပ်စာ",
"Version": "စနစ်အဆင့်",
"List": "စာရင်း",
"Home": "ပင်မစာမျက်နှာ",
"Dashboard": "ခြုံငုံသုံးသပ်ချက်စာမျက်နှာ",
"Add": "အသစ်ပေါင်းထည့်မည်",
"Quick Stats": "စာရင်းအားခြုံငုံကြည့်ရှုခြင်း",
"Up": "ချိတ်ဆက်မှုအောင်မြင်နေသည်",
"Maintenance": "ပြုပြင်နေသည်",
"Unknown": "အမည်မသိအကြောင်းအရာ",
"Reconnecting...": "ပြန်လည်ချိတ်ဆက်နေပါသည်...",
"General Monitor Type": "အထွေထွေစောင့်ကြည့်မှုပုံစံ",
"markdownSupported": "Markdown syntax အားထောက်ပံ့သည်",
"pauseDashboardHome": "ခေတ္တရပ်တန့်မည်",
"Pause": "ခေတ္တရပ်တန့်မည်",
"Name": "အမ်",
"Status": "အခြေအနေများ",
"DateTime": "နေ့ရက်နှင့်အချိန်",
"Message": "စာတို",
"No important events": "အရေးမကြီးသောဖြစ်ရပ်များ",
"Game": "ဂိမ်း",
"Check Update On GitHub": "အသစ်ထွက်ရှိမှုအား GitHub တွင် စစ်ဆေးရန်",
"Add New Monitor": "စောင့်ကြည့်မှုအသစ်ပေါင်းထည့်မည်",
"Down": "ကွန်ရက်ပြတ်တောက်နေသည်",
"Pending": "ဆိုင်းငံ့ဆဲ",
"statusMaintenance": "ပြုပြင်ထိန်းသိမ်းခြင်း",
"Cannot connect to the socket server": "Socket Server အားချိတ်ဆက်မှုမအောင်မြင်ပါ",
"Passive Monitor Type": "Passive စောင့်ကြည့်မှုပုံစံ",
"Specific Monitor Type": "သီးခြားစောင့်ကြည့်မှုပုံစံ",
"Resume": "ဆက်သွားမည်",
"Edit": "ပြောင်းလဲမည်",
"Delete": "ဖျက်သိမ်းမည်",
"Current": "ယခုလက်ရှိ",
"Uptime": "ကွန်ယက်ချိတ်ဆက်မှုကြာချိန်",
"Cert Exp.": "ဆာတီဖီကိတ်ကုန်ဆုံးချိန်",
"Monitor": "စောင့်ကြည့်မှု | စောင့်ကြည့်မှုများ",
"day": "နေ့ရက် | ရက်များ",
"-day": "-နေ့ရက်",
"hour": "နာရီ",
"-hour": "-နာရီ",
"Response": "တုံ့ပြန်မှု",
"Monitor Type": "စောင့်ကြည့်မှုပုံစံ",
"Keyword": "စာသား",
"Invert Keyword": "စာသားပြောင်းပြန်",
"Friendly Name": "မှတ်သားရန်လွယ်ကူသည့်အမည်",
"URL": "အင်တာနက်လိပ်စာ",
"Hostname": "စောင့်ကြည့်မှုအမည်",
"Port": "အပေါက်",
"Advanced": "အဆင့်မြင့်ပြင်ဆင်မှုများ",
"checkEverySecond": "{0} စက္ကန့်တိုင်း‌စောင့်ကြည့်မည်",
"retryCheckEverySecond": "{0} စက္ကန့်တိုင်း‌ထပ်မံကြိုးစားမည်",
"resendEveryXTimes": "{0} စက္ကန့်တိုင်း‌ထပ်မံပေးပို့မည်",
"resendDisabled": "ပိတ်ဆို့ထားခြင်းအားပေးပို့မ်",
"ignoreTLSError": "HTTPS ဝက်ဘ်ဆိုဒ်များအတွက် TLS/SSL အပြစ်အား‌လျစ်လျှူရှုမည်",
"Save": "သိမ်းဆည်းမည်",
"Notifications": "သတိပေးချက်များ",
"Not available, please setup.": "လတ်တလောမရရှိနိုင်ပါ၊ ကျေးဇူးပြု၍ပြင်ဆင်ပါ",
"Setup Notification": "ပြင်ဆင်ခြင်းသတိပေးချက်",
"Light": "အလင်း",
"Dark": "အမှောင်",
"Auto": "အလိုအလျောက်",
"Theme - Heartbeat Bar": "သဏ္ဍာန်-ကွန်ယက်တိုင်းတာနှုန်းပေတံ",
"Normal": "ပုံမှန်",
"Bottom": "အောက်ဆုံး",
"None": "ဘာမှမရှိပါ",
"Timezone": "အချိန်ဇုန်",
"Allow indexing": "အစီအစဉ်ချခြင်းကိုခွင့်ပြုရန်",
"Change Password": "စကားဝှက်ပြောင်းမည်",
"Current Password": "လက်ရှိစကားဝှက်",
"New Password": "စကားဝှက်အသစ်",
"Repeat New Password": "စကားဝှက်အသစ်အားထပ်မံရိုက်ထည့်ပါ",
"Update Password": "စကားဝှက်အားပြင်ဆင်မည်",
"Disable Auth": "ဝင်ရောက်မှုထပ်မံစစ်ဆေးခြင်းအားဖျက်သိမ်းမည်",
"Enable Auth": "ဝင်ရောက်မှုထပ်မံစစ်ဆေးခြင်းအားအတည်ပြုမည်",
"disableauth.message1": "</strong>ဝင်ရောက်မှုထပ်မံစစ်ဆေးခြင်းကိုဖျက်သိမ်းရန်</strong>သေချာပါသလား?",
"Ping": "ချိတ်ဆက်မှုတိုင်းတာခြင်း",
"Expected Value": "မျှော်လင့်ထားသည့်တန်ဖိုး",
"Heartbeat Interval": "ကွန်ယက်ချိတ်ဆက်နိုင်မှုတိုင်းတာခြင်း အချိန်ကွာဟချက်",
"Retries": "ထပ်မံကြိုးစားမှုများ",
"Heartbeat Retry Interval": "ကွန်ယက်ချိတ်ဆက်နိုင်မှုတိုင်းတာခြင်း ထပ်မံကြိုးစားခြင်း အချိန်ကွာဟချက်",
"Resend Notification if Down X times consecutively": "ကွန်ယက်ချိတ်ဆက်မှု X အကြိမ်ထိ ဆက်တိုက်ကျနေပါက သတိပေးချက်ထပ်မံပေးပို့ရန်",
"retriesDescription": "ဝန်ဆောင်မှုကွန်ယက်ပြတ်တောက်နေ၍ သတိပေးချက်ပေးပို့ပြီး အများဆုံးထပ်မံကြိုးစားနိုင်မှု",
"Search Engine Visibility": "ရှာဖွေမှုအင်ဂျင်များ၏မြင်နိုင်စွမ်း"
}

View File

@@ -404,8 +404,6 @@
"For safety, must use secret key": "Voor de veiligheid moet je de secret key gebruiken",
"Device Token": "Apparaat Token",
"Platform": "Platform",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Hoog",
"Retry": "Opnieuw",
@@ -586,7 +584,7 @@
"Enable": "Inschakelen",
"Disable": "Uitschakelen",
"Single Maintenance Window": "Enkel onderhoudsperiode",
"Effective Date Range": "Effectieve periode",
"Effective Date Range": "Effectieve periode (Optioneel)",
"Schedule Maintenance": "Onderhoud inplannen",
"Date and Time": "Datum en tijd",
"DateTime Range": "Datum en tijd periode",
@@ -620,7 +618,7 @@
"Lowcost": "Lowcost",
"Economy": "Economy",
"webhookAdditionalHeadersTitle": "Extra Headers",
"webhookAdditionalHeadersDesc": "Voegt extra headers toe die meegestuurd worden met de webhook.",
"webhookAdditionalHeadersDesc": "Voegt extra headers toe die meegestuurd worden met de webhook. Elke header moet worden gedefinieerd als een JSON key/value.",
"Help": "Hulp",
"Game": "Game",
"statusMaintenance": "Onderhoud",
@@ -703,5 +701,106 @@
"pagertreeHigh": "Hoog",
"Clone": "Dupliceer",
"cloneOf": "Duplicaat van {0}",
"Add New Tag": "Voeg nieuw label toe"
"Add New Tag": "Voeg nieuw label toe",
"Body Encoding": "Body Encoding",
"twilioAuthToken": "Auth Token / Api Sleutel Secret",
"twilioAccountSID": "Account SID",
"Badge Preview": "Badge voorbeeld",
"ntfyAuthenticationMethod": "Authenticatiemethode",
"ntfyUsernameAndPassword": "Gebruikersnaam en Wachtwoord",
"twilioApiKey": "Api Sleutel (optioneel)",
"Badge Label Prefix": "Badge Label Voorvoegsel",
"Badge Label Suffix": "Badge label achtervoegsel",
"API Keys": "API Sleutels",
"Expiry": "Verval",
"noGroupMonitorMsg": "Niet beschikbaar. Creëer eerst een Groep Monitor.",
"Notify Channel": "Notify Channel",
"Expiry date": "Vervaldatum",
"Key Added": "Sleutel toegevoegd",
"Badge value (For Testing only.)": "Badgewaarde (Alleen voor testen)",
"aboutNotifyChannel": "Notify channel activeert een melding op bureaublad of mobiel voor alle leden van de channel, ongeacht of hun beschikbaarheid is ingesteld op actief of afwezig.",
"apiKey-inactive": "Inactief",
"disableAPIKeyMsg": "Weet je zeker dat je deze API-sleutel wilt uitschakelen?",
"Show Clickable Link Description": "Als deze optie is aangevinkt, heeft iedereen die toegang heeft tot deze statuspagina toegang tot de monitor URL.",
"Badge Duration (in hours)": "Duur badge (in uren)",
"Badge Maintenance Color": "Badge Onderhoud Kleur",
"Badge URL": "Badge URL",
"Close": "Sluit",
"Request Body": "Request Body",
"pagertreeIntegrationUrl": "Integratie URL",
"pagertreeUrgency": "Urgentie",
"pagertreeSilent": "Stil",
"telegramMessageThreadID": "(Optioneel) Message Thread ID",
"Clone Monitor": "Kloon Monitor",
"Expires": "Vervalt",
"webhookCustomBodyDesc": "Definieer een aangepaste HTTP Body voor de request. Template variabelen {msg}, {heartbeat}, {monitor} worden geaccepteerd.",
"webhookBodyPresetOption": "Vooraf ingesteld - {0}",
"webhookBodyCustomOption": "Aangepaste Body",
"notificationRegional": "Regionaal",
"No API Keys": "Geen API Sleutels",
"apiKeyAddedMsg": "Je API-sleutel is toegevoegd. Noteer deze, want hij wordt niet meer weergegeven.",
"Add API Key": "Voeg API Sleutel toe",
"telegramSendSilently": "Stil verzenden",
"telegramSendSilentlyDescription": "Stille verzending van het bericht. Gebruikers ontvangen een melding zonder geluid.",
"Home": "Home",
"Don't expire": "Verval nooit",
"Continue": "Ga verder",
"Add Another": "Nog een toevoegen",
"lunaseaTarget": "Doel",
"lunaseaDeviceID": "Apparaat ID",
"lunaseaUserID": "Gebruiker ID",
"Badge Color": "Badge kleur",
"wayToGetPagerTreeIntegrationURL": "Nadat je de Uptime Kuma-integratie in PagerTree hebt gemaakt, kopieert je het eindpunt. Bekijk alle details {0}",
"Badge Warn Color": "Badge Waarschuwing Kleur",
"Invert Keyword": "Trefwoord omkeren",
"filterActive": "Actief",
"filterActivePaused": "Gepauzeerd",
"statusPageRefreshIn": "Vernieuwen in: {0}",
"telegramMessageThreadIDDescription": "Optioneel Unique identifier voor de target message thread (topic) van het forum; alleen voor forum-supergroepen",
"telegramProtectContentDescription": "Als deze optie is ingeschakeld, zijn de botberichten in Telegram beveiligd tegen doorsturen en opslaan.",
"telegramProtectContent": "Beveilig Doorsturen/Opslaan",
"sameAsServerTimezone": "Zelfde als Server Tijdzone",
"startDateTime": "Begindatum/Tijd",
"endDateTime": "Einddatum/Tijd",
"cronExpression": "Cron expressie",
"cronSchedule": "Planning: ",
"invalidCronExpression": "Ongeldige Cron expressie: {0}",
"chromeExecutableDescription": "Voor Docker-gebruikers, als Chromium nog niet is geïnstalleerd, kan het een paar minuten duren om te installeren en het testresultaat weer te geven. Het neemt 1GB schijfruimte in beslag.",
"invertKeywordDescription": "Kijk of het trefwoord afwezig is in plaats van aanwezig.",
"pushoverMessageTtl": "Bericht TTL (seconden)",
"goAlertInfo": "GoAlert is een open source applicatie voor het plannen van aanwezigheidsdiensten, geautomatiseerde escalaties en meldingen (zoals SMS of spraakoproepen). Schakel automatisch de juiste persoon in, op de juiste manier en op het juiste moment! {0}",
"goAlertIntegrationKeyInfo": "Verkrijg generieke API-integratiesleutel voor de service in dit formaat \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\" meestal de waarde van tokenparameter van gekopieerde URL.",
"deleteAPIKeyMsg": "Weet je zeker dat je deze API-sleutel wilt verwijderen?",
"Generate": "Genereer",
"pagertreeMedium": "Medium",
"pagertreeCritical": "Kritisch",
"pagertreeResolve": "Automatisch oplossen",
"pagertreeDoNothing": "Doe niks",
"twilioFromNumber": "Van Nummer",
"twilioToNumber": "Naar Nummer",
"Monitor Setting": "{0}'s Monitor Instelling",
"Show Clickable Link": "Laat klikbare link zien",
"Open Badge Generator": "Open Badge Generator",
"Badge Generator": "{0}'s Badge Generator",
"Badge Type": "Badge type",
"Badge Up Color": "Badge Online Kleur",
"Badge Down Color": "Badge Offline Kleur",
"Badge Warn Days": "Badge Waarschuwing dagen",
"Badge Down Days": "Badge Offline dagen",
"Badge Style": "Badge stijl",
"chromeExecutable": "Chrome/Chromium Executable",
"chromeExecutableAutoDetect": "Automatisch detecteren",
"Edit Maintenance": "Onderhoud bewerken",
"Badge Label": "Badge Label",
"Badge Label Color": "Badge label kleur",
"Badge Prefix": "Badge Waarde Voorvoegsel",
"Badge Pending Color": "Badge In Afwachting Kleur",
"Badge Suffix": "Badge waarde achtervoegsel",
"Group": "Groep",
"Monitor Group": "Monitor Groep",
"Cannot connect to the socket server": "Kan geen verbinding maken met de socket-server",
"Reconnecting...": "Opnieuw verbinden...",
"Expected Value": "Verwachte waarde",
"Json Query": "Json Query",
"jsonQueryDescription": "Voer een JSON-query uit op de respons en controleer de verwachte waarde (De retourwaarde wordt omgezet naar een string voor vergelijking). Bekijk <a href='https://jsonata.org/'>jsonata.org</a> voor de documentatie over de querytaal. Een speelplaats is beschikbaar <a href='https://try.jsonata.org/'>hier</a>."
}

View File

@@ -414,8 +414,6 @@
"For safety, must use secret key": "Ze względów bezpieczeństwa musisz użyć tajnego klucza",
"Device Token": "Token urządzenia",
"Platform": "Platforma",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "Wysoki",
"Retry": "Ponów",
@@ -450,7 +448,7 @@
"Backup": "Backup",
"About": "O skrypcie",
"wayToGetCloudflaredURL": "(Pobierz cloudflared z {0})",
"cloudflareWebsite": "Strona Cloudflare",
"cloudflareWebsite": "strona Cloudflare",
"Message:": "Wiadomość:",
"Don't know how to get the token? Please read the guide:": "Nie wiesz jak uzyksać token? Przeczytaj proszę poradnik:",
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Bieżące połączenie może zostać utracone, jeśli aktualnie łączysz się przez tunel Cloudflare. Czy na pewno chcesz to przerwać? Wpisz swoje aktualne hasło, aby je potwierdzić.",
@@ -615,7 +613,7 @@
"You can divide numbers with": "Możesz dzielić liczby przez",
"or": "lub",
"recurringInterval": "odstęp czasu",
"Recurring": "powtarzający się",
"Recurring": "Powtarzający się",
"strategyManual": "Aktywowany/dezaktywowany ręcznie",
"warningTimezone": "Używa strefy czasowej serwera",
"weekdayShortMon": "pon",
@@ -625,8 +623,8 @@
"weekdayShortFri": "pt",
"weekdayShortSat": "sob",
"weekdayShortSun": "niedz",
"dayOfWeek": "Dzień tygodnia",
"dayOfMonth": "Dzień miesiąca",
"dayOfWeek": "dzień tygodnia",
"dayOfMonth": "dzień miesiąca",
"lastDay": "Ostatni dzień",
"lastDay1": "Ostatni dzień miesiąca",
"lastDay2": "2. ostatni dzień miesiąca",
@@ -648,8 +646,8 @@
"confirmDeleteTagMsg": "Czy na pewno chcesz usunąć ten tag? Monitory powiązane z tym tagiem nie zostaną usunięte.",
"Kook": "Kook",
"Enable TLS": "Włącz TLS",
"webhookAdditionalHeadersDesc": "Ustawia dodatkowe nagłówki wysyłane z webhookiem.",
"dnsCacheDescription": "Może nie działać w niektórych środowiskach z IPv6. Wyłącz, jeśli napotkasz jakiekolwiek problemy.",
"webhookAdditionalHeadersDesc": "Ustawia dodatkowe nagłówki wysyłane z webhookiem. Każdy nagłówek powinien być zdefiniowany jako klucz/wartość JSON.",
"dnsCacheDescription": "Może nie działać w niektórych środowiskach IPv6, wyłącz, jeśli napotkasz jakiekolwiek problemy.",
"wayToGetKookBotToken": "Utwórz aplikację i uzyskaj swój token bota na {0}",
"wayToGetKookGuildID": "Włącz 'Developer Mode' w ustawieniach Kook'a i kliknij prawym przyciskiem myszy na gildię, aby uzyskać jej ID",
"Game": "Gra",
@@ -661,7 +659,7 @@
"Disable": "Wyłącz",
"Date and Time": "Data i czas",
"IconUrl": "URL ikony",
"Enable DNS Cache": "Włącz pamięć podręczną DNS",
"Enable DNS Cache": "Włącz pamięć podręczną DNS dla monitorów HTTP",
"Single Maintenance Window": "Pojedyncze okno konserwacji",
"Effective Date Range": "Zakres dat obowiązywania (opcjonalnie)",
"Schedule Maintenance": "Planowanie konserwacji",
@@ -732,7 +730,7 @@
"twilioToNumber": "Do numeru",
"lunaseaTarget": "Cel",
"twilioAccountSID": "SID konta",
"twilioAuthToken": "Token autoryzacyjny",
"twilioAuthToken": "Token autoryzacji / klucz Api Secret",
"apiKeyAddedMsg": "Twój klucz API został dodany. Prosimy o zanotowanie go, ponieważ nie będzie on już więcej pokazywany.",
"telegramMessageThreadID": "(Opcjonalne) ID wątku wiadomości",
"telegramMessageThreadIDDescription": "Opcjonalny Unikalny identyfikator dla docelowego wątku wiadomości (tematu) forum; tylko dla supergrup forum",
@@ -750,7 +748,7 @@
"sameAsServerTimezone": "Tak jak strefa czasowa serwera",
"endDateTime": "Data/godzina zakończenia",
"cronExpression": "Wyrażenie Cron",
"ntfyAuthenticationMethod": "Metoda Uwierzytelnienia",
"ntfyAuthenticationMethod": "Metoda uwierzytelniania",
"ntfyUsernameAndPassword": "Nazwa użytkownika i hasło",
"noGroupMonitorMsg": "Niedostępna. Stwórz najpierw grupę monitorów.",
"Close": "Zamknij",
@@ -759,5 +757,86 @@
"Group": "Grupa",
"Monitor Group": "Grupa monitora",
"Reconnecting...": "Ponowne łączenie...",
"Cannot connect to the socket server": "Nie można połączyć się z serwerem gniazda"
"Cannot connect to the socket server": "Nie można połączyć się z serwerem gniazda",
"Badge Label Suffix": "Sufiks etykiety odznaki",
"Badge Warn Color": "Kolor ostrzeżenia odznaki",
"Badge Style": "Styl odznaki",
"Badge value (For Testing only.)": "Wartość odznaki (tylko do testów.)",
"Show Clickable Link": "Pokaż klikalne łącze",
"Show Clickable Link Description": "Jeśli to pole jest zaznaczone, każdy, kto ma dostęp do tej strony stanu, może mieć dostęp do adresu URL monitora.",
"Open Badge Generator": "Generator odznak Open Badge",
"Badge Generator": "{0} Generator odznak",
"Monitor Setting": "{0} Ustawienia monitora",
"Badge Duration": "Czas trwania odznaki",
"Badge Label": "Etykieta odznaki",
"Badge Suffix": "Sufiks wartości odznaki",
"chromeExecutable": "Plik wykonywalny Chrome/Chromium",
"chromeExecutableAutoDetect": "Wykryj automatycznie",
"chromeExecutableDescription": "W przypadku użytkowników Dockera, jeśli Chromium nie jest jeszcze zainstalowany, instalacja i wyświetlenie wyniku testu może zająć kilka minut. Zajmuje 1 GB miejsca na dysku.",
"Edit Maintenance": "Edycja konserwacji",
"Badge Type": "Typ odznaki",
"Badge Prefix": "Prefiks wartości odznaki",
"Badge Color": "Kolor odznaki",
"Badge Label Color": "Kolor etykiety Odznaki",
"Badge Label Prefix": "Prefiks etykiety identyfikatora",
"Badge Pending Color": "Oczekujący kolor odznaki",
"Badge Maintenance Color": "Kolor utrzymania odznaki",
"Badge URL": "Adres URL odznaki",
"gamedigGuessPort": "Gamedig: Port Guess",
"filterActive": "Aktywny",
"webhookCustomBodyDesc": "Definiuje niestandardową treść HTTP dla żądania. Akceptowane są zmienne szablonowe {msg}, {heartbeat}, {monitor}.",
"Select": "Wybierz",
"aboutNotifyChannel": "Powiadomienie kanału wywoła powiadomienie na komputerze lub urządzeniu mobilnym dla wszystkich członków kanału, niezależnie od tego, czy ich dostępność jest ustawiona jako aktywna, czy nie.",
"twilioApiKey": "Klucz API (opcjonalnie)",
"styleElapsedTime": "Czas, który upłynął pod paskiem bicia serca",
"tailscalePingWarning": "Aby korzystać z monitora Tailscale Ping, należy zainstalować Uptime Kuma bez Dockera, a także zainstalować klienta Tailscale na serwerze.",
"invertKeywordDescription": "Słowo kluczowe powinno być raczej nieobecne niż obecne.",
"jsonQueryDescription": "Wykonaj zapytanie json względem odpowiedzi i sprawdź oczekiwaną wartość (wartość zwracana zostanie przekonwertowana na ciąg znaków do porównania). Sprawdź <a href='https://jsonata.org/'>jsonata.org</a>, aby uzyskać dokumentację dotyczącą języka zapytań. Plac zabaw można znaleźć <a href='https://try.jsonata.org/'>tutaj</a>.",
"Server URL should not contain the nfty topic": "Adres URL serwera nie powinien zawierać tematu nfty",
"Badge Duration (in hours)": "Czas trwania odznaki (w godzinach)",
"Enter the list of brokers": "Wprowadź listę brokerów",
"Enable Kafka Producer Auto Topic Creation": "Włącz automatyczne tworzenie tematów w producencie Kafka",
"showCertificateExpiry": "Pokaż wygaśnięcie certyfikatu",
"gamedigGuessPortDescription": "Port używany przez Valve Server Query Protocol może różnić się od portu klienta. Spróbuj tego, jeśli monitor nie może połączyć się z serwerem.",
"Secret AccessKey": "Tajny klucz AccessKey",
"wayToGetFlashDutyKey": "Możesz przejść do Channel -> (Select a Channel) -> Integrations -> Add a new integration' page, dodać \"Custom Event\", aby uzyskać adres push, skopiować klucz integracji w adresie. Więcej informacji można znaleźć na stronie",
"Badge Down Color": "Kolor odznaki Offline",
"Notify Channel": "Powiadom kanał",
"Request Timeout": "Limit czasu żądania",
"timeoutAfter": "Przekroczenie limitu czasu po {0} sekundach",
"styleElapsedTimeShowNoLine": "Pokaż (bez linii)",
"styleElapsedTimeShowWithLine": "Pokaż (z linią)",
"filterActivePaused": "Wstrzymany",
"webhookBodyCustomOption": "Niestandardowa treść",
"webhookBodyPresetOption": "Wstępne ustawienie - {0}",
"selectedMonitorCount": "Wybrano: {0}",
"Check/Uncheck": "Zaznacz/Odznacz",
"PushDeer Server": "Serwer PushDeer",
"pushDeerServerDescription": "Pozostaw puste, aby korzystać z oficjalnego serwera",
"Badge Preview": "Podgląd odznaki",
"Kafka Brokers": "Broker Kafka",
"Press Enter to add broker": "Naciśnij Enter, aby dodać brokera",
"Kafka Topic Name": "Nazwa tematu Kafka",
"Kafka Producer Message": "Wiadomość producenta Kafka",
"Enable Kafka SSL": "Włącz Kafka SSL",
"Kafka SASL Options": "Opcje SASL Kafki",
"Mechanism": "Mechanizm",
"Pick a SASL Mechanism...": "Wybierz mechanizm SASL...",
"nostrRelaysHelp": "Jeden adres URL przekaźnika w wierszu",
"nostrRecipients": "Klucze publiczne odbiorców (npub)",
"nostrRecipientsHelp": "format npub, po jednym w wierszu",
"Authorization Identity": "Identyfikacja autoryzacji",
"AccessKey Id": "Identyfikator klucza AccessKey",
"Session Token": "Token sesji",
"Request Body": "Treść żądania",
"FlashDuty Severity": "Poziom istotności",
"nostrRelays": "Przekaźniki Nostr",
"nostrSender": "Prywatny klucz nadawcy (nsec)",
"Badge Up Color": "Kolor odznaki Online",
"Badge Down Days": "Odznaka dni offline",
"Badge Warn Days": "Odznaka dni z ostrzeżeniem",
"noOrBadCertificate": "Brak/zły certyfikat",
"Invert Keyword": "Odwróć słowo kluczowe",
"Expected Value": "Oczekiwana wartość",
"Json Query": "Zapytanie Json"
}

View File

@@ -29,7 +29,7 @@
"Settings": "Configurações",
"Dashboard": "Painel",
"New Update": "Nova Atualização",
"Language": "Linguagem",
"Language": "Idioma",
"Appearance": "Aparência",
"Theme": "Tema",
"General": "Geral",
@@ -476,13 +476,13 @@
"Query": "Query",
"settingsCertificateExpiry": "O Certificado TLS Expira",
"Connection Type": "Tipo Da Conexão",
"signedInDisp": "Assinado como {0}",
"signedInDisp": "Logado como {0}",
"RadiusCallingStationId": "ID Da Estação De Chamada",
"RadiusCalledStationIdDescription": "Identificador do dispositivo de chamada",
"Coming Soon": "Em Breve",
"Connection String": "String De Conexão",
"Docker Daemon": "Daemon Do Docker",
"Show Powered By": "Mostrar Distribuído Por",
"Show Powered By": "Mostrar Fornecido Por",
"RadiusSecret": "Segredo Radius",
"RadiusCalledStationId": "ID Da Estação Chamada",
"deleteDockerHostMsg": "Você tem certeza que quer deletar esse host do Docker para todos os monitores?",
@@ -523,7 +523,6 @@
"Example:": "Exemplo: {0}",
"Read more:": "Leia mais em: {0}",
"promosmsAllowLongSMS": "Permitir SMS grandes",
"Android": "Android",
"Huawei": "Huawei",
"smseagleTo": "Números Dos Telefones",
"smseaglePriority": "Prioridade da mensagem (0-9, padrão=0)",
@@ -570,10 +569,10 @@
"disableAPIKeyMsg": "Você tem certeza de que quer desativar essa chave de API?",
"smtp": "Email (SMTP)",
"secureOptionTLS": "TLS (465)",
"From Email": "Email De",
"From Email": "Remetente",
"smtpCC": "CC",
"smtpBCC": "CCO",
"To Email": "Email Para",
"To Email": "Destinatário",
"Recipients": "Destinatários",
"Google Analytics ID": "ID Google Analytics",
"Post": "Post",
@@ -584,5 +583,10 @@
"Automations can optionally be triggered in Home Assistant:": "Automações podem opcionalmente ser disparadas no Home Assistant:",
"secureOptionNone": "Nenhum / STARTTLS (25, 587)",
"apiKeyAddedMsg": "Sua chave de API foi adicionada. Por favor anote essa chave, ela não será mostrada novamente.",
"Show Clickable Link": "Mostrar Link Clicável"
"Show Clickable Link": "Mostrar Link Clicável",
"backupOutdatedWarning": "Obsoleto: Já que muitos recursos foram adicionados e este recurso de backup não foi atualizado, ele não consegue gerar ou restaurar um backup completo.",
"wayToGetDiscordURL": "Voce pode configurar isso indo à Configurações do Servidor -> Integrações -> Ver Webhooks -> Novo Webhook",
"Home": "Início",
"Reconnecting...": "Reconectando...",
"Cannot connect to the socket server": "Não foi possível conectar ao servidor socket"
}

View File

@@ -114,7 +114,7 @@
"Notification Type": "Tipo de Notificação",
"Email": "Email",
"Test": "Testar",
"Certificate Info": "Info. do Certificado ",
"Certificate Info": "Info. do Certificado",
"Resolver Server": "Resolver Servidor",
"Resource Record Type": "Tipo de registro de aplicação",
"Last Result": "Último resultado",

39
src/lang/pt.json Normal file
View File

@@ -0,0 +1,39 @@
{
"Settings": "Definições",
"Help": "Ajuda",
"New Update": "Nova actualização",
"Language": "Linguagem",
"Appearance": "Aspecto",
"Theme": "Tema",
"General": "Geral",
"Game": "Jogo",
"Version": "Versão",
"List": "Lista",
"Add": "Adicionar",
"Quick Stats": "Estatísticas rápidas",
"Up": "Acima",
"Down": "Abaixo",
"Pending": "Pendente",
"statusMaintenance": "Manutenção",
"Maintenance": "Manutenção",
"Unknown": "Desconhecido",
"Reconnecting...": "Reconectando...",
"pauseDashboardHome": "Pausa",
"Pause": "Pausa",
"Name": "Nome",
"Status": "Estado",
"Message": "Mensagem",
"Resume": "Retomar",
"Edit": "Editar",
"Delete": "Remover",
"Current": "Actual",
"Uptime": "Tempo de atividade",
"day": "dia | dias",
"languageName": "Português",
"Primary Base URL": "URL base primário",
"No important events": "Nenhum evento importante",
"Dashboard": "Dashboard",
"Add New Monitor": "Adicionar Novo Monitor",
"Home": "Home",
"Check Update On GitHub": "Verificar por Actualizações no GitHub"
}

View File

@@ -6,7 +6,7 @@
"upsideDownModeDescription": "Реверс статуса сервиса. Если сервис доступен, то он помечается как НЕДОСТУПНЫЙ.",
"maxRedirectDescription": "Максимальное количество перенаправлений. Поставьте 0, чтобы отключить перенаправления.",
"acceptedStatusCodesDescription": "Выберите коды статусов для определения доступности сервиса.",
"passwordNotMatchMsg": "Введёные пароли не совпадают",
"passwordNotMatchMsg": "Введённые пароли не совпадают",
"notificationDescription": "Привяжите уведомления к мониторам.",
"keywordDescription": "Поиск слова в чистом HTML или в JSON-ответе (чувствительно к регистру).",
"pauseDashboardHome": "Пауза",
@@ -43,7 +43,7 @@
"Delete": "Удалить",
"Current": "Текущий",
"Uptime": "Аптайм",
"Cert Exp.": "Сертификат истекает",
"Cert Exp.": "Сертификат ист.",
"day": "день | дней",
"-day": "-дней",
"hour": "час",
@@ -421,8 +421,6 @@
"For safety, must use secret key": "В целях безопасности необходимо использовать секретный ключ",
"Device Token": "Токен устройства",
"Platform": "Платформа",
"iOS": "iOS",
"Android": "Android",
"Huawei": "Huawei",
"High": "High",
"Retry": "Повторить",
@@ -448,7 +446,7 @@
"Message:": "Сообщение:",
"Don't know how to get the token? Please read the guide:": "Не знаете, как получить токен? Пожалуйста, прочтите руководство:",
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Текущее соединение может быть потеряно, если вы в данный момент подключаетесь через туннель Cloudflare. Вы уверены, что хотите это остановить? Введите свой текущий пароль, чтобы подтвердить это.",
"HTTP Headers": "заголовки HTTP",
"HTTP Headers": "Заголовки HTTP",
"Trust Proxy": "Доверять прокси",
"Other Software": "Другое программное обеспечение",
"For example: nginx, Apache and Traefik.": "К примеру: nginx, Apache и Traefik.",
@@ -544,7 +542,7 @@
"Container Name / ID": "Название контейнера / ID",
"Docker Host": "Хост Docker",
"Docker Hosts": "Хосты Docker",
"ntfy Topic": "тема ntfy",
"ntfy Topic": "Тема ntfy",
"Domain": "Домен",
"Workstation": "Рабочая станция",
"disableCloudflaredNoAuthMsg": "Вы находитесь в режиме без авторизации, пароль не требуется.",
@@ -641,7 +639,7 @@
"Server Timezone": "Часовой пояс сервера",
"statusPageMaintenanceEndDate": "Конец",
"IconUrl": "URL иконки",
"Enable DNS Cache": "Включить DNS кэш",
"Enable DNS Cache": "Включить DNS кэш для мониторов HTTP(S)",
"Enable": "Включить",
"Disable": "Отключить",
"Single Maintenance Window": "Единое окно техбслуживания",
@@ -654,7 +652,7 @@
"enableGRPCTls": "Разрешить отправлять gRPC запрос через TLS соединение",
"Free Mobile API Key": "API ключ Free Mobile",
"Edit Tag": "Редактировать тэг",
"webhookAdditionalHeadersDesc": "Устанавливает дополнительные заголовки, отправляемые с помощью веб-хука.",
"webhookAdditionalHeadersDesc": "Устанавливает дополнительные заголовки, отправляемые с помощью веб-хука. Каждый заголовок должен быть определён как JSON ключ/значение.",
"topic": "Тема",
"Customize": "Персонализировать",
"Custom Footer": "Пользовательский footer",
@@ -748,9 +746,9 @@
"Proto Method": "Метод Proto",
"Proto Content": "Содержание Proto",
"telegramMessageThreadID": "(Необязательно) ID цепочки сообщений",
"statusPageRefreshIn": "Обновлять каждые: {0}",
"statusPageRefreshIn": "Обновление через: {0}",
"twilioAccountSID": "SID учетной записи",
"twilioAuthToken": "Токен авторизации",
"twilioAuthToken": "Токен авторизации / Секретный API ключ",
"twilioFromNumber": "С номера",
"twilioToNumber": "На номер",
"sameAsServerTimezone": "Аналогично часовому поясу сервера",
@@ -767,7 +765,7 @@
"Badge Type": "Тип значка",
"Badge Duration": "Срок действия значка",
"Badge Label": "Надпись для значка",
"Badge Prefix": "Префикс значка",
"Badge Prefix": "Значение префикса значка",
"Badge Label Color": "Цвет надписи значка",
"Badge Color": "Цвет значка",
"Badge Label Prefix": "Префикс надписи для значка",
@@ -776,7 +774,7 @@
"Badge Pending Color": "Цвет значка для статуса \"Ожидание\"",
"Badge Maintenance Color": "Цвет значка для статуса \"Техобслуживание\"",
"Badge Style": "Стиль значка",
"Badge Suffix": "Суффикс значка",
"Badge Suffix": "Значение суффикса значка",
"Badge value (For Testing only.)": "Значение значка (только для тестирования)",
"Badge URL": "URL значка",
"Group": "Группа",
@@ -793,5 +791,61 @@
"Badge Down Days": "Значок для \"дней недоступности\"",
"Home": "Главная",
"noGroupMonitorMsg": "Не доступно. Создайте сначала группу мониторов.",
"Close": "Закрыть"
"Close": "Закрыть",
"chromeExecutableDescription": "Для пользователей Docker, если Chromium еще не установлен, может потребоваться несколько минут для установки и отображения результата тестирования. Он занимает 1 ГБ дискового пространства.",
"chromeExecutable": "Исполняемый файл Chrome/Chromium",
"chromeExecutableAutoDetect": "Автообнаружение",
"Badge Preview": "Предпросмотр значка",
"Badge Duration (in hours)": "Срок действия значка (в часах)",
"twilioApiKey": "API ключ (необязательно)",
"Expected Value": "Ожидаемое значение",
"Json Query": "JSON запрос",
"Kafka Brokers": "Kafka Brokers",
"Press Enter to add broker": "Нажмите Enter чтобы добавить брокера",
"Kafka Topic Name": "Название темы Kafka",
"Kafka Producer Message": "Сообщение продюсера Kafka",
"Kafka SASL Options": "Параметры SASL в Kafka",
"Mechanism": "Механизм",
"Pick a SASL Mechanism...": "Выберите механизм SASL...",
"AccessKey Id": "AccessKey Id",
"Secret AccessKey": "Секретный ключ доступа",
"Session Token": "Токен сессии",
"jsonQueryDescription": "Выполните json-запрос к ответу и проверьте наличие ожидаемого значения (возвращаемое значение будет преобразовано в строку для сравнения). Посмотрите <a href='https://jsonata.org/'>jsonata.org</a> для получения документации по языку запросов. A Потренироваться вы можете <a href='https://try.jsonata.org/'>сдесь</a>.",
"Notify Channel": "Канал оповещений",
"aboutNotifyChannel": "Уведомление о канале вызовет настольное или мобильное уведомление для всех участников канала, независимо от того, установлена ли их доступность как активная или отсутствующая.",
"Enter the list of brokers": "Введите список брокеров",
"Enable Kafka SSL": "Включение протокола Kafka SSL",
"Enable Kafka Producer Auto Topic Creation": "Включение автоматического создания тем в Kafka Producer",
"Authorization Identity": "Авторизационная идентичность",
"Request Body": "Тело запроса",
"webhookCustomBodyDesc": "Определите пользовательское HTTP Body для запроса. Принимаются шаблонные переменные {msg}, {heartbeat}, {monitor}.",
"webhookBodyCustomOption": "Кастомное тело",
"webhookBodyPresetOption": "Пресет - {}",
"invertKeywordDescription": "Искать, чтобы ключевое слово отсутствовало, а не присутствовало.",
"filterActive": "Активный",
"filterActivePaused": "На паузе",
"Invert Keyword": "Инвертировать ключевое слово",
"tailscalePingWarning": "Для того чтобы использовать монитор Tailscale Ping, необходимо установить Uptime Kuma без Docker, а также установить на сервер клиент Tailscale.",
"PushDeer Server": "Сервер PushDeer",
"pushDeerServerDescription": "Оставьте пустым для использования официального сервера",
"showCertificateExpiry": "Показывать истекающий сертификат",
"Request Timeout": "Тайм-Аут запроса",
"timeoutAfter": "Тайм-Аут через {0} секунд",
"Select": "Выбрать",
"selectedMonitorCount": "Выбрано: {0}",
"Check/Uncheck": "Отметить/Снять",
"gamedigGuessPort": "Gamedig: Угадай порт",
"styleElapsedTime": "Прошедшее время под полосой частоты опроса",
"noOrBadCertificate": "Отсутствие сертификата",
"gamedigGuessPortDescription": "Порт, используемый протоколом Valve Server Query Protocol, может отличаться от порта клиента. Попробуйте это сделать, если монитор не может подключиться к серверу.",
"nostrSender": "Закрытый ключ отправителя (nsec)",
"wayToGetFlashDutyKey": "Вы можете перейти на страницу \"Канал\" -> (Выберите канал) -> \"Интеграции\" -> \"Добавить новую страницу интеграции\", добавить \"Пользовательское событие\", чтобы получить push-адрес, скопировать ключ интеграции в адрес. Для получения дополнительной информации, пожалуйста, посетите",
"styleElapsedTimeShowNoLine": "Показать (Без линии)",
"styleElapsedTimeShowWithLine": "Показать (С линией)",
"Server URL should not contain the nfty topic": "URL сервера не должен содержать тему nfty",
"nostrRecipients": "Открытые ключи получателей (npub)",
"nostrRecipientsHelp": "формат npub, по одному в строке",
"FlashDuty Severity": "Серьёзность",
"nostrRelays": "Реле Nostr",
"nostrRelaysHelp": "Один URL-адрес ретрансляции в каждой строке"
}

Some files were not shown because too many files have changed in this diff Show More