Compare commits

..

199 Commits

Author SHA1 Message Date
shamoon
01eea51555 Merge pull request #850 from benphelps/revert-644-feat/unprivileged-container
Revert "use unprivileged user in a container"
2023-01-19 19:09:42 -08:00
shamoon
67e72fb96a Revert "use unprivileged user in a container" 2023-01-19 19:09:00 -08:00
shamoon
c7e4a52b99 Merge pull request #841 from JacksonBarker/main
Added Brave search provider
2023-01-18 18:52:11 -08:00
Jason Fischer
627ce179ef Merge pull request #448 from jameswynn/kubernetes
Support for Kubernetes and Longhorn
2023-01-18 14:54:38 -08:00
Anonymous
1ee2356028 Translated using Weblate (Latvian)
Currently translated at 39.7% (119 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/lv/
2023-01-18 21:51:21 +01:00
Anonymous
335e2fcb1f Translated using Weblate (Japanese)
Currently translated at 5.0% (15 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ja/
2023-01-18 21:51:21 +01:00
Anonymous
a71fe3796f Translated using Weblate (Ukrainian)
Currently translated at 98.6% (295 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/uk/
2023-01-18 21:51:21 +01:00
Anonymous
ab8114ee4f Translated using Weblate (Esperanto)
Currently translated at 34.4% (103 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/eo/
2023-01-18 21:51:20 +01:00
Anonymous
be4ed7481a Translated using Weblate (Hindi)
Currently translated at 3.0% (9 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hi/
2023-01-18 21:51:20 +01:00
Anonymous
4ee85bc108 Translated using Weblate (Malay)
Currently translated at 84.6% (253 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ms/
2023-01-18 21:51:20 +01:00
Anonymous
a88a5aa922 Translated using Weblate (Danish)
Currently translated at 66.2% (198 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/da/
2023-01-18 21:51:20 +01:00
Anonymous
87e82f5339 Translated using Weblate (Czech)
Currently translated at 75.2% (225 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/cs/
2023-01-18 21:51:19 +01:00
Anonymous
c741fee788 Translated using Weblate (Arabic)
Currently translated at 14.7% (44 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ar/
2023-01-18 21:51:19 +01:00
Anonymous
98ecb192fd Translated using Weblate (Serbian)
Currently translated at 3.0% (9 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sr/
2023-01-18 21:51:19 +01:00
Anonymous
ba34bb5aba Translated using Weblate (Turkish)
Currently translated at 77.2% (231 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/tr/
2023-01-18 21:51:18 +01:00
Anonymous
1f9f9070a9 Translated using Weblate (Bulgarian)
Currently translated at 15.3% (46 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/bg/
2023-01-18 21:51:18 +01:00
Anonymous
a86fa90a58 Translated using Weblate (Telugu)
Currently translated at 72.5% (217 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/te/
2023-01-18 21:51:18 +01:00
Anonymous
388bc74464 Translated using Weblate (Finnish)
Currently translated at 41.1% (123 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fi/
2023-01-18 21:51:18 +01:00
Anonymous
dd66f51105 Translated using Weblate (Yue)
Currently translated at 39.4% (118 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/yue/
2023-01-18 21:51:18 +01:00
Anonymous
e126a04a35 Translated using Weblate (Portuguese (Brazil))
Currently translated at 39.1% (117 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt_BR/
2023-01-18 21:51:17 +01:00
Anonymous
83ec439513 Translated using Weblate (Romanian)
Currently translated at 45.8% (137 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ro/
2023-01-18 21:51:17 +01:00
Anonymous
8afcb4e427 Translated using Weblate (Hebrew)
Currently translated at 33.7% (101 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/he/
2023-01-18 21:51:17 +01:00
Anonymous
e84ea3a89d Translated using Weblate (Hungarian)
Currently translated at 36.1% (108 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hu/
2023-01-18 21:51:17 +01:00
Anonymous
b80bda077d Translated using Weblate (Croatian)
Currently translated at 95.6% (286 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hr/
2023-01-18 21:51:16 +01:00
Anonymous
e1247a40a7 Translated using Weblate (Swedish)
Currently translated at 44.1% (132 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sv/
2023-01-18 21:51:16 +01:00
Anonymous
238835c625 Translated using Weblate (Polish)
Currently translated at 91.9% (275 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pl/
2023-01-18 21:51:16 +01:00
Anonymous
8b229c0096 Translated using Weblate (Catalan)
Currently translated at 86.2% (258 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ca/
2023-01-18 21:51:16 +01:00
Anonymous
41290cf909 Translated using Weblate (Chinese (Traditional))
Currently translated at 87.6% (262 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hant/
2023-01-18 21:51:15 +01:00
Anonymous
96ec29efd9 Translated using Weblate (Dutch)
Currently translated at 29.4% (88 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/
2023-01-18 21:51:15 +01:00
Anonymous
9c6a71c463 Translated using Weblate (Vietnamese)
Currently translated at 14.7% (44 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/vi/
2023-01-18 21:51:15 +01:00
Anonymous
f7f4033e21 Translated using Weblate (Norwegian Bokmål)
Currently translated at 26.4% (79 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nb_NO/
2023-01-18 21:51:15 +01:00
Anonymous
af3f65a648 Translated using Weblate (Italian)
Currently translated at 96.3% (288 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/it/
2023-01-18 21:51:14 +01:00
Anonymous
b73d36fbd4 Translated using Weblate (Chinese (Simplified))
Currently translated at 56.1% (168 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hans/
2023-01-18 21:51:14 +01:00
Anonymous
23a2c43e50 Translated using Weblate (Russian)
Currently translated at 16.0% (48 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ru/
2023-01-18 21:51:14 +01:00
Anonymous
fe7d7a9feb Translated using Weblate (Portuguese)
Currently translated at 85.6% (256 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt/
2023-01-18 21:51:13 +01:00
Anonymous
ce8cef99e8 Translated using Weblate (French)
Currently translated at 98.6% (295 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fr/
2023-01-18 21:51:13 +01:00
Anonymous
60958cad5f Translated using Weblate (Spanish)
Currently translated at 98.6% (295 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2023-01-18 21:51:13 +01:00
Anonymous
76701c245c Translated using Weblate (German)
Currently translated at 76.2% (228 of 299 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/de/
2023-01-18 21:51:13 +01:00
Armīns Jeltajevs
2053ce7361 Translated using Weblate (Latvian)
Currently translated at 40.3% (119 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/lv/
2023-01-18 21:50:51 +01:00
Jason Fischer
1935965095 Merge pull request #834 from williamwoldum/octoPrint
OctoPrint Widget
2023-01-18 12:50:45 -08:00
williamwoldum
006fb80533 Added celcius labels 2023-01-18 21:04:49 +01:00
Jackson Barker
ab2c3c6412 Added Brave search provider 2023-01-18 14:10:01 -05:00
williamwoldum
2c3947ea3f Removed refresh intervals 2023-01-18 19:33:55 +01:00
James Wynn
725189a7b0 Issue with dotnext PVC preventing normal deployments
* fixed k3d-deploy.sh directory reference
2023-01-18 10:05:12 -06:00
Armīns Jeltajevs
7b61ca81bc Translated using Weblate (Latvian)
Currently translated at 29.8% (88 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/lv/
2023-01-18 14:49:45 +01:00
Graphix Media
f2d737b156 Translated using Weblate (Dutch)
Currently translated at 29.8% (88 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/
2023-01-18 14:49:45 +01:00
gallegonovato
b6bee279d4 Translated using Weblate (Spanish)
Currently translated at 100.0% (295 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2023-01-18 14:49:44 +01:00
williamwoldum
365783204a realized that 'pausing' and 'resuming' are also states while printing 2023-01-18 00:47:51 +01:00
williamwoldum
047f7af99a removed silencing feature 2023-01-17 23:36:48 +01:00
williamwoldum
a880cdbc68 silenced more request errors + small fix in display logic 2023-01-17 12:50:08 +01:00
williamwoldum
9f008fc04e initial 2023-01-17 03:54:24 +01:00
Anonymous
aa8c41e715 Translated using Weblate (Latvian)
Currently translated at 100.0% (0 of 0 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/lv/
2023-01-17 01:09:40 +01:00
Dan
2a5442940f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (295 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/uk/
2023-01-17 01:09:38 +01:00
Nonoss117
3317cd8b5b Translated using Weblate (French)
Currently translated at 100.0% (295 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fr/
2023-01-17 01:09:38 +01:00
Armīns Jeltajevs
d9241e03bb Added translation using Weblate (Latvian) 2023-01-17 01:09:19 +01:00
Anonymous
8e191d4103 Translated using Weblate (Japanese)
Currently translated at 5.0% (15 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ja/
2023-01-17 00:31:08 +01:00
Anonymous
d882e43603 Translated using Weblate (Ukrainian)
Currently translated at 98.9% (292 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/uk/
2023-01-17 00:31:08 +01:00
Anonymous
4edd0edc3d Translated using Weblate (Esperanto)
Currently translated at 34.9% (103 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/eo/
2023-01-17 00:31:07 +01:00
Anonymous
9043e4d648 Translated using Weblate (Hindi)
Currently translated at 3.0% (9 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hi/
2023-01-17 00:31:07 +01:00
Anonymous
fb3f1d61cc Translated using Weblate (Malay)
Currently translated at 85.7% (253 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ms/
2023-01-17 00:31:07 +01:00
Anonymous
4b21740e64 Translated using Weblate (Danish)
Currently translated at 67.1% (198 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/da/
2023-01-17 00:31:07 +01:00
Anonymous
ef5a063af3 Translated using Weblate (Czech)
Currently translated at 76.2% (225 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/cs/
2023-01-17 00:31:06 +01:00
Anonymous
5aa29aafb7 Translated using Weblate (Arabic)
Currently translated at 14.9% (44 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ar/
2023-01-17 00:31:06 +01:00
Anonymous
d7be68e040 Translated using Weblate (Serbian)
Currently translated at 3.0% (9 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sr/
2023-01-17 00:31:06 +01:00
Anonymous
3d96b508d5 Translated using Weblate (Turkish)
Currently translated at 78.3% (231 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/tr/
2023-01-17 00:31:06 +01:00
Anonymous
6c13e65802 Translated using Weblate (Bulgarian)
Currently translated at 15.5% (46 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/bg/
2023-01-17 00:31:05 +01:00
Anonymous
fe9c355af5 Translated using Weblate (Telugu)
Currently translated at 73.5% (217 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/te/
2023-01-17 00:31:05 +01:00
Anonymous
ef7afb2589 Translated using Weblate (Finnish)
Currently translated at 41.6% (123 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fi/
2023-01-17 00:31:05 +01:00
Anonymous
0e19765e8b Translated using Weblate (Yue)
Currently translated at 40.0% (118 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/yue/
2023-01-17 00:31:05 +01:00
Anonymous
857fec1d47 Translated using Weblate (Portuguese (Brazil))
Currently translated at 39.6% (117 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt_BR/
2023-01-17 00:31:04 +01:00
Anonymous
a8287cb20f Translated using Weblate (Romanian)
Currently translated at 46.4% (137 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ro/
2023-01-17 00:31:04 +01:00
Anonymous
2507848575 Translated using Weblate (Hebrew)
Currently translated at 34.2% (101 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/he/
2023-01-17 00:31:04 +01:00
Anonymous
fdd66c1435 Translated using Weblate (Hungarian)
Currently translated at 36.6% (108 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hu/
2023-01-17 00:31:04 +01:00
Anonymous
827679ced6 Translated using Weblate (Croatian)
Currently translated at 96.9% (286 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hr/
2023-01-17 00:31:03 +01:00
Anonymous
e112b3f737 Translated using Weblate (Swedish)
Currently translated at 44.7% (132 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sv/
2023-01-17 00:31:03 +01:00
Anonymous
8598f4c315 Translated using Weblate (Polish)
Currently translated at 93.2% (275 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pl/
2023-01-17 00:31:03 +01:00
Anonymous
8329aabe74 Translated using Weblate (Catalan)
Currently translated at 87.4% (258 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ca/
2023-01-17 00:31:03 +01:00
Anonymous
667519f81e Translated using Weblate (Chinese (Traditional))
Currently translated at 88.8% (262 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hant/
2023-01-17 00:31:03 +01:00
Anonymous
ea9fa2b9c2 Translated using Weblate (Dutch)
Currently translated at 21.3% (63 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/
2023-01-17 00:31:02 +01:00
Anonymous
df3bac842e Translated using Weblate (Vietnamese)
Currently translated at 14.9% (44 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/vi/
2023-01-17 00:31:02 +01:00
Anonymous
32e7323b45 Translated using Weblate (Norwegian Bokmål)
Currently translated at 26.7% (79 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nb_NO/
2023-01-17 00:31:02 +01:00
Anonymous
62e1cfea59 Translated using Weblate (Italian)
Currently translated at 97.6% (288 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/it/
2023-01-17 00:31:01 +01:00
Anonymous
92b3433e1d Translated using Weblate (Chinese (Simplified))
Currently translated at 56.9% (168 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hans/
2023-01-17 00:31:01 +01:00
Anonymous
8723b1f101 Translated using Weblate (Russian)
Currently translated at 16.2% (48 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ru/
2023-01-17 00:31:01 +01:00
Anonymous
88d2ce7d6f Translated using Weblate (Portuguese)
Currently translated at 86.7% (256 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt/
2023-01-17 00:31:01 +01:00
Anonymous
f65884183d Translated using Weblate (French)
Currently translated at 98.9% (292 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fr/
2023-01-17 00:31:01 +01:00
Anonymous
fa1f51d42c Translated using Weblate (Spanish)
Currently translated at 98.9% (292 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2023-01-17 00:31:00 +01:00
Anonymous
578de2c52e Translated using Weblate (German)
Currently translated at 77.2% (228 of 295 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/de/
2023-01-17 00:31:00 +01:00
Jason Fischer
12e111b76c Merge pull request #832 from umens/main
Add Medusa widget
2023-01-16 15:29:40 -08:00
Ulysse Mensa
82a6553c58 Merge branch 'benphelps:main' into main 2023-01-16 22:39:51 +01:00
Ulysse Mensa
2a24277757 Add Medusa widget 2023-01-16 22:39:01 +01:00
Luis Miguel Soto Sánchez
e20a0e90b2 Translated using Weblate (Spanish)
Currently translated at 100.0% (292 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2023-01-16 17:48:14 +01:00
Dan
b3e976860a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (292 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/uk/
2023-01-15 02:57:28 +01:00
Nonoss117
1a9acd753c Translated using Weblate (French)
Currently translated at 100.0% (292 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fr/
2023-01-15 02:57:28 +01:00
gallegonovato
7f7e083a41 Translated using Weblate (Spanish)
Currently translated at 100.0% (292 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2023-01-15 02:57:27 +01:00
Antonio Sanchez Castellón
3aec4e6da4 Translated using Weblate (Spanish)
Currently translated at 100.0% (292 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2023-01-15 02:57:27 +01:00
shamoon
59bec6e65e Merge pull request #817 from Jose134/bookmark-fix-814 2023-01-14 07:53:54 -08:00
José Manuel Jurado Bujalance
93dda99aaa use abbr as icon fallback 2023-01-13 22:45:08 +01:00
Jason Fischer
16c419f816 Merge pull request #644 from ajgon/feat/unprivileged-container
use unprivileged user in a container
2023-01-13 09:41:37 -08:00
Anonymous
a8e506504a Translated using Weblate (Japanese)
Currently translated at 5.1% (15 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ja/
2023-01-12 22:55:42 +01:00
Anonymous
bf5b82445f Translated using Weblate (Ukrainian)
Currently translated at 98.6% (288 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/uk/
2023-01-12 22:55:41 +01:00
Anonymous
a58eebb448 Translated using Weblate (Esperanto)
Currently translated at 35.2% (103 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/eo/
2023-01-12 22:55:41 +01:00
Anonymous
233391fc4a Translated using Weblate (Hindi)
Currently translated at 3.0% (9 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hi/
2023-01-12 22:55:41 +01:00
Anonymous
7a4ac9ddd9 Translated using Weblate (Malay)
Currently translated at 86.6% (253 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ms/
2023-01-12 22:55:41 +01:00
Anonymous
9de4bfc6fe Translated using Weblate (Danish)
Currently translated at 67.8% (198 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/da/
2023-01-12 22:55:40 +01:00
Anonymous
c981a737a6 Translated using Weblate (Czech)
Currently translated at 77.0% (225 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/cs/
2023-01-12 22:55:40 +01:00
Anonymous
5a6b65aeb0 Translated using Weblate (Arabic)
Currently translated at 15.0% (44 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ar/
2023-01-12 22:55:40 +01:00
Anonymous
fa325b2497 Translated using Weblate (Serbian)
Currently translated at 3.0% (9 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sr/
2023-01-12 22:55:39 +01:00
Anonymous
f355464aae Translated using Weblate (Turkish)
Currently translated at 79.1% (231 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/tr/
2023-01-12 22:55:39 +01:00
Anonymous
893b709f8b Translated using Weblate (Bulgarian)
Currently translated at 15.7% (46 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/bg/
2023-01-12 22:55:39 +01:00
Anonymous
a4d1589493 Translated using Weblate (Telugu)
Currently translated at 74.3% (217 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/te/
2023-01-12 22:55:39 +01:00
Anonymous
4060fdc902 Translated using Weblate (Finnish)
Currently translated at 42.1% (123 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fi/
2023-01-12 22:55:38 +01:00
Anonymous
54f263da15 Translated using Weblate (Yue)
Currently translated at 40.4% (118 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/yue/
2023-01-12 22:55:38 +01:00
Anonymous
2a777e55d9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 40.0% (117 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt_BR/
2023-01-12 22:55:38 +01:00
Anonymous
e1d6d46420 Translated using Weblate (Romanian)
Currently translated at 46.9% (137 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ro/
2023-01-12 22:55:38 +01:00
Anonymous
ed8e7aa01d Translated using Weblate (Hebrew)
Currently translated at 34.5% (101 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/he/
2023-01-12 22:55:37 +01:00
Anonymous
56618ead39 Translated using Weblate (Hungarian)
Currently translated at 36.9% (108 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hu/
2023-01-12 22:55:37 +01:00
Anonymous
1549bc67be Translated using Weblate (Croatian)
Currently translated at 97.9% (286 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hr/
2023-01-12 22:55:37 +01:00
Anonymous
a7f9dad6df Translated using Weblate (Swedish)
Currently translated at 45.2% (132 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sv/
2023-01-12 22:55:37 +01:00
Anonymous
5d6e078c87 Translated using Weblate (Polish)
Currently translated at 94.1% (275 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pl/
2023-01-12 22:55:36 +01:00
Anonymous
6100cdba93 Translated using Weblate (Catalan)
Currently translated at 88.3% (258 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ca/
2023-01-12 22:55:36 +01:00
Anonymous
e04594defb Translated using Weblate (Chinese (Traditional))
Currently translated at 89.7% (262 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hant/
2023-01-12 22:55:36 +01:00
Anonymous
5bc475b9df Translated using Weblate (Dutch)
Currently translated at 21.5% (63 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/
2023-01-12 22:55:36 +01:00
Anonymous
d27262c934 Translated using Weblate (Vietnamese)
Currently translated at 15.0% (44 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/vi/
2023-01-12 22:55:35 +01:00
Anonymous
20e4449fd5 Translated using Weblate (Norwegian Bokmål)
Currently translated at 27.0% (79 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nb_NO/
2023-01-12 22:55:35 +01:00
Anonymous
f3698aaeb5 Translated using Weblate (Italian)
Currently translated at 98.6% (288 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/it/
2023-01-12 22:55:35 +01:00
Anonymous
7fec2af8e3 Translated using Weblate (Chinese (Simplified))
Currently translated at 57.5% (168 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hans/
2023-01-12 22:55:35 +01:00
Anonymous
dc01dbd649 Translated using Weblate (Russian)
Currently translated at 16.4% (48 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ru/
2023-01-12 22:55:34 +01:00
Anonymous
5e44ac2448 Translated using Weblate (Portuguese)
Currently translated at 87.6% (256 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt/
2023-01-12 22:55:34 +01:00
Anonymous
113bbc3ef1 Translated using Weblate (French)
Currently translated at 98.6% (288 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fr/
2023-01-12 22:55:34 +01:00
Anonymous
294b27ab71 Translated using Weblate (Spanish)
Currently translated at 98.6% (288 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2023-01-12 22:55:34 +01:00
Anonymous
a444945faa Translated using Weblate (German)
Currently translated at 78.0% (228 of 292 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/de/
2023-01-12 22:55:33 +01:00
Eizock
0febf05d8d Add Moonraker (Klipper) widget (#798)
* Add Moonraker (Klipper) widget

* Fix linting

* Removed filename, to adhere to standards

* Removed unused translation

* fix conditional in moonraker component

Co-authored-by: Eizock <>
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2023-01-12 13:55:07 -08:00
Igor Rzegocki
03294b5a2f use unprivileged user in a container 2023-01-12 21:17:01 +01:00
Dan
a04c7677e4 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/uk/
2023-01-11 23:50:52 +01:00
Milo Ivir
67f63219f4 Translated using Weblate (Croatian)
Currently translated at 99.3% (286 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hr/
2023-01-11 23:50:51 +01:00
Chun Chi Hsieh
9634a89c81 Translated using Weblate (Chinese (Traditional))
Currently translated at 90.9% (262 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hant/
2023-01-11 23:50:51 +01:00
nightly_brew
f36c0710d8 Translated using Weblate (Italian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/it/
2023-01-11 23:50:50 +01:00
James Wynn
b724f520cd added k3d test scripts 2023-01-11 09:47:34 -06:00
Jason Fischer
a7f290dfdd Merge pull request #609 from benphelps/fix-576
Fix: settings not picked up after first container creation
2023-01-09 16:53:24 -08:00
James Wynn
98ce0e8c2e Updated package lock with kubernetes deps to resolve offline builds 2023-01-09 10:41:06 -06:00
James Wynn
b6e8b64a2e Merge branch 'main' into kubernetes 2023-01-09 08:34:43 -06:00
James Wynn
4d6ce1f7e2 Widgets in discovered services now work correctly 2023-01-09 08:30:50 -06:00
shamoon
cf38395100 Merge pull request #791 from benphelps/fix-787
Fix: useWidgetAPI refreshInterval not working
2023-01-09 01:37:21 -08:00
Michael Shamoon
fc2e17fa59 fix useWidgetAPI refreshInterval 2023-01-09 01:33:58 -08:00
Chun Chi Hsieh
642f21e56b Translated using Weblate (Chinese (Traditional))
Currently translated at 42.7% (123 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hant/
2023-01-08 16:48:30 +01:00
shamoon
e1799f17e3 Merge pull request #777 from jhollowe-forks/truenas-apikey
Change TrueNAS to use API key
2023-01-07 11:05:43 -08:00
Michael Shamoon
730f1c5ec1 Support api key + username / pass for truenas widget 2023-01-07 10:00:25 -08:00
John Hollowell
34a7b25c9c Add truenas key to credentialed proxy handler
Revert "Change TrueNAS to use API key"

This reverts commit 1926c26b77d8e048d92da6e20ff24a3056237daf.

Co-Authored-By: John Hollowell <jhollowe@johnhollowell.com>
2023-01-07 10:00:16 -08:00
Anonymous
f93106970a Translated using Weblate (Japanese)
Currently translated at 5.2% (15 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ja/
2023-01-07 01:13:54 +01:00
SASAGAWA, Kiyoshi
2b4fb03dcf Translated using Weblate (Japanese)
Currently translated at 5.2% (15 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ja/
2023-01-06 01:14:21 +01:00
Anonymous
11fad11b6d Translated using Weblate (Japanese)
Currently translated at 100.0% (0 of 0 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ja/
2023-01-05 10:26:06 +01:00
Milo Ivir
885dca1750 Translated using Weblate (Croatian)
Currently translated at 97.9% (282 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hr/
2023-01-05 10:26:03 +01:00
ze cabra
1caa9faded Translated using Weblate (Portuguese)
Currently translated at 88.8% (256 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt/
2023-01-05 10:26:03 +01:00
SASAGAWA, Kiyoshi
4f24c0f909 Added translation using Weblate (Japanese) 2023-01-05 10:25:44 +01:00
shamoon
1fd198c255 Merge pull request #771 from benphelps/datetime-locale
Feature: allow setting locale for datetime widget directly
2023-01-04 19:12:23 -08:00
Michael Shamoon
84b7f103c3 Allow setting locale for datetime widget directly 2023-01-04 13:53:06 -08:00
shamoon
272be2c086 Merge pull request #770 from HaroldVB/patch-1
Giving Read Only rights to homepage
2023-01-04 12:28:31 -08:00
Harold
6705197a35 Giving Read Only rights to homepage
Giving Read Only rights to homepage container.
Adding :RO to the docker.sock volume. When the container gets compromised the intruder will have root access basically. The container doesn't need the write privileges.

This measure will stop inexperienced people from exposing their docker.socket to the public internet.
2023-01-04 20:10:18 +01:00
shamoon
2ac06937f9 Merge pull request #769 from benphelps/downloadstation-support-v6+v7
Fix: Support Synology DownloadStation v6 + v7
2023-01-03 23:19:56 -08:00
Michael Shamoon
35a2cd9b94 Support Synology DownloadStation v6 + v7
Co-Authored-By: Benoit SERRA <11260343+Oupsman@users.noreply.github.com>
2023-01-03 15:51:21 -08:00
James Wynn
9a072cddde added documentation 2023-01-03 16:50:24 -06:00
James Wynn
36ed1022e3 detection now uses annotation "gethomepage.dev/enabled" instead of label 2023-01-03 16:15:08 -06:00
shamoon
3a43cf247b Merge pull request #765 from benphelps/fix-764
Use tabular nums for datetime to prevent size changing
2023-01-02 08:34:49 -08:00
Michael Shamoon
af29f5b266 Use tabular nums for datetime to prevent size changing 2023-01-02 08:30:57 -08:00
James Wynn
e15ba1c82c Merge branch 'main' into kubernetes 2022-12-31 11:19:42 -06:00
James Wynn
7ac862be75 removed overly verbose logging message 2022-12-31 11:13:52 -06:00
shamoon
f6b1304e22 Merge pull request #749 from benphelps/fix-docker-log-error
Fix: remove error on no discovered services
2022-12-30 20:32:11 -08:00
Michael Shamoon
ee729a7e6a remove error on no discovered services 2022-12-30 20:31:25 -08:00
Michael Shamoon
bc7937db71 omada widget cleanup 2022-12-29 00:25:50 -08:00
shamoon
0e1aeaf54c Merge pull request #719 from benphelps/docker-server-failovers
Fix: Handle docker server failures if others succeed
2022-12-28 18:40:08 -08:00
shamoon
2e8717247d Merge pull request #745 from benphelps/fix-version-check-cache
Fix: version check caching
2022-12-28 18:38:50 -08:00
Michael Shamoon
d17a17bd3c Use server-side endpoint to properly cache GH release data 2022-12-28 18:33:14 -08:00
Michael Shamoon
0afc1b96f1 CPU / memory / disk usage bars start from 0
Closes #737
2022-12-28 16:21:04 -08:00
Michael Shamoon
5fbc6702bc Prevent blocking error on GH releases failure
Closes #738
2022-12-28 16:17:49 -08:00
Nonoss117
75455a23e2 Translated using Weblate (French)
Currently translated at 100.0% (288 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fr/
2022-12-27 12:50:18 +01:00
gallegonovato
2aed46671f Translated using Weblate (Spanish)
Currently translated at 100.0% (288 of 288 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/
2022-12-27 12:50:18 +01:00
shamoon
88934ec39a Correct debug messages in Pyload widget
Closes #733
2022-12-26 06:07:43 -08:00
shamoon
21c0c687cd Update README.md 2022-12-26 01:17:54 -08:00
shamoon
9f63a5a1d5 Merge pull request #732 from benphelps/fix-update-checker
Fix broken update checker
2022-12-26 01:02:37 -08:00
Michael Shamoon
679704949e Fix broken update checker 2022-12-26 01:02:01 -08:00
Michael Shamoon
6b90d3ef28 Handle docker server failures if others succeed 2022-12-22 21:16:52 -08:00
James Wynn
51ff424d98 added check for nodes without disks 2022-12-09 17:00:05 -06:00
James Wynn
ec08535204 fixed podSelector discovery 2022-12-09 07:56:51 -06:00
James Wynn
a146c13c4f fixed unintentional blank default podSelector from discovery 2022-12-09 07:52:32 -06:00
James Wynn
8543118607 updated ingress selector label, added href override annotation 2022-12-09 07:43:52 -06:00
James Wynn
27d067dc4c Typo in kubernetes component 2022-12-08 18:31:51 -06:00
James Wynn
09eb172079 new status format, new podSelector field, more accurate pod stats
* renamed pod label prefix from "homepage" to "gethomepage.dev"
  which is more inline with typical kubernetes practices
2022-12-08 16:04:33 -06:00
James Wynn
174cb651b4 Merge branch 'main' into kubernetes 2022-12-08 09:57:51 -06:00
Michael Shamoon
c01b60dbd1 try to detect invalid settings load 2022-12-03 00:14:07 -08:00
James Wynn
c54374068d fixed a formatting error and longhorn's usage bar 2022-11-25 10:21:51 -06:00
James Wynn
a1f2003a77 Merge branch 'main' into kubernetes 2022-11-19 09:09:23 -06:00
James Wynn
1ca61114ef Merge branch 'benphelps:main' into kubernetes 2022-11-18 18:02:53 -06:00
James Wynn
fdb143304f Separated kubernetes widgets from resources widgets 2022-11-18 18:02:23 -06:00
James Wynn
056e26dfd3 Improved handling of empty or disabled kubernetes configuration 2022-11-06 06:58:52 -06:00
James Wynn
0c6f7dbee1 Cleaned up some variable names 2022-11-06 06:58:52 -06:00
James Wynn
4fc6db49ca Improved kubernetes error handling 2022-11-06 06:58:52 -06:00
James Wynn
8887fcc3ee longhorn support
* longhorn widget for showing storage stats as "disks"
2022-11-06 06:58:52 -06:00
James Wynn
c4333fd2dc Kubernetes support
* Total CPU and Memory usage for the entire cluster
* Total CPU and Memory usage for kubernetes pods
* Service discovery via annotations on ingress
* No storage stats yet
* No network stats yet
2022-11-06 06:58:52 -06:00
94 changed files with 12669 additions and 700 deletions

View File

@@ -20,5 +20,7 @@
**/obj **/obj
**/secrets.dev.yaml **/secrets.dev.yaml
**/values.dev.yaml **/values.dev.yaml
**/.next
README.md README.md
config/ config/
k3d/

22
Dockerfile-tilt Normal file
View File

@@ -0,0 +1,22 @@
# syntax = docker/dockerfile:latest
FROM docker.io/node:18-alpine
WORKDIR /app
COPY --link package.json pnpm-lock.yaml* ./
RUN <<EOF
set -xe
apk add libc6-compat
apk add --virtual .gyp python3 make g++
npm install -g pnpm
npm install -g next
EOF
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store pnpm fetch | grep -v "cross-device link not permitted\|Falling back to copying packages from store"
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store pnpm install -r --offline
COPY . .
CMD ["npx", "next", "dev"]

View File

@@ -45,15 +45,17 @@
- Container status (Running / Stopped) & statistics (CPU, Memory, Network) - Container status (Running / Stopped) & statistics (CPU, Memory, Network)
- Automatic service discovery (via labels) - Automatic service discovery (via labels)
- Service Integration - Service Integration
- Sonarr, Radarr, Readarr, Prowlarr, Bazarr, Lidarr, Emby, Jellyfin, Tautulli (Plex) - Sonarr, Radarr, Readarr, Prowlarr, Bazarr, Lidarr, Emby, Jellyfin, Tautulli, Plex and more
- Ombi, Overseerr, Jellyseerr, Jackett, NZBGet, SABnzbd, ruTorrent, Transmission, qBittorrent - Ombi, Overseerr, Jellyseerr, Jackett, NZBGet, SABnzbd, ruTorrent, Transmission, qBittorrent and more
- Portainer, Traefik, Speedtest Tracker, PiHole, AdGuard Home, Nginx Proxy Manager, Gotify, Syncthing Relay Server, Authentik, Proxmox - Portainer, Traefik, Speedtest Tracker, PiHole, AdGuard Home, Nginx Proxy Manager, Gotify, Syncthing Relay Server, Authentik, Proxmox and more
- Information Providers - Information Providers
- Coin Market Cap, Mastodon - Coin Market Cap, Mastodon and more
- Information & Utility Widgets - Information & Utility Widgets
- System Stats (Disk, CPU, Memory) - System Stats (Disk, CPU, Memory)
- Weather via [OpenWeatherMap](https://openweathermap.org/) or [Open-Meteo](https://open-meteo.com/) - Weather via [OpenWeatherMap](https://openweathermap.org/) or [Open-Meteo](https://open-meteo.com/)
- Search Bar - Web Search Bar
- UniFi Console, Glances and more
- Instant "Quick-launch" search
- Customizable - Customizable
- 21 theme colors with light and dark mode support - 21 theme colors with light and dark mode support
- Background image support - Background image support
@@ -63,7 +65,7 @@
If you have any questions, suggestions, or general issues, please start a discussion on the [Discussions](https://github.com/benphelps/homepage/discussions) page. If you have any questions, suggestions, or general issues, please start a discussion on the [Discussions](https://github.com/benphelps/homepage/discussions) page.
If you have a more specific issue, please open an issue on the [Issues](https://github.com/benphelps/homepage/issues) page. For bug reports, please open an issue on the [Issues](https://github.com/benphelps/homepage/issues) page.
## Getting Started ## Getting Started
@@ -83,7 +85,7 @@ services:
- 3000:3000 - 3000:3000
volumes: volumes:
- /path/to/config:/app/config # Make sure your local config directory exists - /path/to/config:/app/config # Make sure your local config directory exists
- /var/run/docker.sock:/var/run/docker.sock # (optional) For docker integrations - /var/run/docker.sock:/var/run/docker.sock:ro # (optional) For docker integrations
``` ```
or docker run: or docker run:

2
k3d/.envrc Normal file
View File

@@ -0,0 +1,2 @@
#shellcheck disable=SC2148,SC2155
export KUBECONFIG=$(readlink -f ./kubeconfig)

2
k3d/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
kubeconfig

64
k3d/README.md Normal file
View File

@@ -0,0 +1,64 @@
# Kubernetes Development
These configs and scripts attempt to simplify spinning up a kubernetes cluster
for development and testing purposes. It leverages [k3d](https://k3d.io) to create
a [k3s](https://k3s.io) cluster in Docker. Homepage can then be deployed either via
the `k3d-deploy.sh` script, or [tilt](https://tilt.dev) can be used to spin up a
local CI loop that will automatically update the deployment.
All the commands in the document should be run from the `k3d` directory.
## Requisite Tools
| Tool | Description |
|-------------------------------------------------------------|----------------------------------------------------------|
| [docker](https://docker.io) | Docker container runtime |
| [kubectl](https://kubernetes.io/releases/download/#kubectl) | Kubernetes CLI |
| [helm](https://helm.sh) | Kubernetes package manager |
| [k3d](https://k3d.io) | Kubernetes on Docker - used to create the cluster |
| [k9s](https://k9scli.io) | (Optional) Command line view for kubernetes cluster |
| [tilt](https://tilt.dev) | (Optional) Local CI loop for kubernetes deployment |
| [direnv](https://direnv.net/) | (Optional) Automatically loads `kubeconfig` via `.envrc` |
## One-off Test Deployments
Create a cluster:
```sh
./k3d-up.sh
```
Build and deploy:
```sh
./k3d-deploy.sh
```
Open the Homepage deployment:
```sh
xdg-open http://homepage.k3d.localhost:8080/
```
## Continuous Deployment
Create a cluster:
```sh
./k3d-up.sh
```
Kick off tilt:
```sh
tilt up
```
Press space bar to open the tilt web UI, which is quite informative.
Open the Homepage deployment:
```sh
xdg-open http://homepage.k3d.localhost:8080/
```

25
k3d/Tiltfile Normal file
View File

@@ -0,0 +1,25 @@
docker_build('k3d-registry.localhost:55000/homepage:local', '..',
dockerfile = "../Dockerfile-tilt",
build_args={'node_env': 'development'},
#entrypoint='pnpm run nodemon /app/server.js',
live_update=[
sync('.', '/app'),
run('cd /app && pnpm install', trigger=['.package.json', './pnpm-lock.yaml'])
]
)
load('ext://helm_resource', 'helm_resource', 'helm_repo')
helm_repo('jameswynn', 'https://jameswynn.github.io/helm-charts')
helm_resource('homepage', 'jameswynn/homepage',
image_deps=[
"k3d-registry.localhost:55000/homepage:local"
],
image_keys=[
("image.repository", "image.tag")
],
# image_selector= "k3d-registry.localhost:55000/homepage:local",
flags=[
"-f", "k3d-helm-values.yaml",
"--set", "persistence.dotnext.enabled=true"
]
)

14
k3d/k3d-deploy.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
DOCKER_BUILDKIT=1 docker build -t k3d-registry.localhost:55000/homepage:local ..
docker push k3d-registry.localhost:55000/homepage:local
HELM_REPO_NAME=jameswynn
HELM_REPO_URL=https://jameswynn.github.io/helm-charts
if ! helm repo list | grep $HELM_REPO_URL > /dev/null; then
helm repo add $HELM_REPO_NAME $HELM_REPO_URL
helm repo update
fi
helm upgrade --install homepage jameswynn/homepage -f k3d-helm-values.yaml

4
k3d/k3d-down.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
k3d cluster delete homepage
rm kubeconfig

78
k3d/k3d-helm-values.yaml Normal file
View File

@@ -0,0 +1,78 @@
image:
repository: k3d-registry.localhost:55000/homepage
tag: local
pullPolicy: Always
config:
bookmarks:
- Developer:
- Github:
- abbr: GH
href: https://github.com/
services:
- My First Group:
- My First Service:
href: http://localhost/
description: Homepage is awesome
- My Second Group:
- My Second Service:
href: http://localhost/
description: Homepage is the best
- My Third Group:
- My Third Service:
href: http://localhost/
description: Homepage is 😎
widgets:
# show the kubernetes widget, with the cluster summary and individual nodes
- kubernetes:
cluster:
show: true
cpu: true
memory: true
showLabel: true
label: "cluster"
nodes:
show: true
cpu: true
memory: true
showLabel: true
- search:
provider: duckduckgo
target: _blank
kubernetes:
mode: cluster
docker:
settings:
serviceAccount:
create: true
name: homepage
enableRbac: true
ingress:
main:
enabled: true
annotations:
gethomepage.dev/enabled: "true"
gethomepage.dev/name: "Homepage"
gethomepage.dev/description: "Dynamically Detected Homepage"
gethomepage.dev/group: "Dynamic"
gethomepage.dev/icon: "homepage.png"
hosts:
- host: homepage.k3d.localhost
paths:
- path: /
pathType: Prefix
persistence:
# this persists the .next directory which greatly improves successive pod startup times in Tilt,
# but it breaks normal deployments, so it is disabled by default
dotnext:
enabled: false
type: pvc
accessMode: ReadWriteOnce
size: 1Gi
mountPath: /app/.next

9
k3d/k3d-up.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
k3d cluster create --config k3d.yaml --wait
k3d kubeconfig get homepage > kubeconfig
chmod 600 kubeconfig
export KUBECONFIG=$(pwd)/kubeconfig
echo "Waiting for traefik install job to complete (CTRL+C is safe if you're impatient)"
kubectl wait jobs/helm-install-traefik -n kube-system --for condition=complete --timeout 90s && echo "Completed" || echo "Timed out (but it should still come up eventually)"

59
k3d/k3d.yaml Normal file
View File

@@ -0,0 +1,59 @@
kind: Simple
apiVersion: k3d.io/v1alpha3
name: homepage
servers: 1
agents: 2
kubeAPI:
hostIP: 0.0.0.0
hostPort: "6443"
image: rancher/k3s:v1.25.5-k3s1
volumes:
- volume: /tmp:/tmp/k3d-homepage
nodeFilters:
- all
ports:
- port: 8080:80
nodeFilters:
- loadbalancer
- port: 0.0.0.0:8443:443
nodeFilters:
- loadbalancer
options:
k3d:
wait: true
timeout: 6m0s
disableLoadbalancer: false
disableImageVolume: false
disableRollback: false
k3s:
extraArgs:
- arg: --tls-san=127.0.0.1
nodeFilters:
- server:*
nodeLabels: []
kubeconfig:
updateDefaultKubeconfig: false
switchCurrentContext: false
runtime:
gpuRequest: ""
serversMemory: "1024Mi"
agentsMemory: "1024Mi"
labels:
- label: foo=bar
nodeFilters:
- server:0
- loadbalancer
env:
- envVar: bar=baz
nodeFilters:
- all
registries:
create:
name: k3d-registry
# host: 0.0.0.0
hostPort: "55000"
config: |
mirrors:
"k3d-registry.localhost:55000":
endpoint:
- http://k3d-registry:5000

147
kubernetes.md Normal file
View File

@@ -0,0 +1,147 @@
# Kubernetes Support
## Requirements
* Kubernetes 1.19+
* Metrics service
* An Ingress controller
## Deployment
Use the unofficial helm chart: https://github.com/jameswynn/helm-charts/tree/main/charts/homepage
```sh
helm repo add jameswynn https://jameswynn.github.io/helm-charts
helm install my-release jameswynn/homepage
```
### Configuration
Set the `mode` in the `kubernetes.yaml` to `cluster`.
```yaml
mode: default
```
## Widgets
The Kubernetes widget can show a high-level overview of the cluster,
individual nodes, or both.
```yaml
- kubernetes:
cluster:
# Shows the cluster node
show: true
# Shows the aggregate CPU stats
cpu: true
# Shows the aggregate memory stats
memory: true
# Shows a custom label
showLabel: true
label: "cluster"
nodes:
# Shows the clusters
show: true
# Shows the CPU for each node
cpu: true
# Shows the memory for each node
memory: true
# Shows the label, which is always the node name
showLabel: true
```
## Service Discovery
Sample yaml:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homepage
annotations:
gethomepage.dev/enabled: "true"
gethomepage.dev/description: Dynamically Detected Homepage
gethomepage.dev/group: Operations
gethomepage.dev/icon: homepage.png
gethomepage.dev/name: Homepage
spec:
rules:
- host: homepage.example.com
http:
paths:
- backend:
service:
name: homepage
port:
number: 3000
path: /
pathType: Prefix
```
## Service Widgets
To manually configure a Service Widget the `namespace` and `app` fields must
be configured on the service entry.
```yaml
- Home Automation
- Home-Assistant:
icon: home-assistant.png
href: https://home.example.com
description: Home Automation
app: home-assistant
namespace: home
```
This works by creating a label selector `app.kubernetes.io/name=home-assistant`,
which typically will be the same both for the ingress and the deployment. However,
some deployments can be complex and will not conform to this rule. In such
cases the `podSelector` variable can bridge the gap. Any field selector can
be used in it which allows for some powerful selection capabilities.
For instance, it can be utilized to roll multiple underlying deployments under
one application to see a high-level aggregate:
```yaml
- Comms
- Element Chat:
icon: matrix-light.png
href: https://chat.example.com
description: Matrix Synapse Powered Chat
app: matrix-element
namespace: comms
podSelector: >-
app.kubernetes.io/instance in (
matrix-element,
matrix-media-repo,
matrix-media-repo-postgresql,
matrix-synapse
)
```
## Longhorn Widget
There is a widget for showing storage stats from [Longhorn](https://longhorn.io).
Configure it from the `widgets.yaml`.
```yaml
- longhorn:
# Show the expanded
expanded: true
# Shows a node representing the aggregate values
total: true
# Shows the node names as labels
labels: true
# Show the nodes
nodes: true
# An explicit list of nodes to show. All are shown by default if "nodes" is true
include:
- node1
- node2
```
## Testing
Refer to the [k3d readme](k3d/README.md).

8518
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@headlessui/react": "^1.7.2", "@headlessui/react": "^1.7.2",
"@kubernetes/client-node": "^0.17.1",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"compare-versions": "^5.0.1", "compare-versions": "^5.0.1",
"dockerode": "^3.3.4", "dockerode": "^3.3.4",

480
pnpm-lock.yaml generated
View File

@@ -2,6 +2,7 @@ lockfileVersion: 5.4
specifiers: specifiers:
'@headlessui/react': ^1.7.2 '@headlessui/react': ^1.7.2
'@kubernetes/client-node': ^0.17.1
'@tailwindcss/forms': ^0.5.3 '@tailwindcss/forms': ^0.5.3
autoprefixer: ^10.4.12 autoprefixer: ^10.4.12
classnames: ^2.3.2 classnames: ^2.3.2
@@ -44,6 +45,7 @@ specifiers:
dependencies: dependencies:
'@headlessui/react': 1.7.2_biqbaboplfbrettd7655fr4n2y '@headlessui/react': 1.7.2_biqbaboplfbrettd7655fr4n2y
'@kubernetes/client-node': 0.17.1
classnames: 2.3.2 classnames: 2.3.2
compare-versions: 5.0.1 compare-versions: 5.0.1
dockerode: 3.3.4 dockerode: 3.3.4
@@ -171,6 +173,30 @@ packages:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: true dev: true
/@kubernetes/client-node/0.17.1:
resolution: {integrity: sha512-qXANjukuTq/drb1hq1NCYZafpdRTvbyTzbliWO6RwW7eEb2b9qwINbw0DiVHpBQg3e9DeQd8+brI1sR1Fck5kQ==}
dependencies:
byline: 5.0.0
execa: 5.0.0
isomorphic-ws: 4.0.1_ws@7.5.9
js-yaml: 4.1.0
jsonpath-plus: 0.19.0
request: 2.88.2
rfc4648: 1.5.2
shelljs: 0.8.5
stream-buffers: 3.0.2
tar: 6.1.13
tmp-promise: 3.0.3
tslib: 1.14.1
underscore: 1.13.6
ws: 7.5.9
optionalDependencies:
openid-client: 5.3.1
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: false
/@next/env/12.3.1: /@next/env/12.3.1:
resolution: {integrity: sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==} resolution: {integrity: sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==}
dev: false dev: false
@@ -467,7 +493,6 @@ packages:
fast-json-stable-stringify: 2.1.0 fast-json-stable-stringify: 2.1.0
json-schema-traverse: 0.4.1 json-schema-traverse: 0.4.1
uri-js: 4.4.1 uri-js: 4.4.1
dev: true
/ansi-regex/5.0.1: /ansi-regex/5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
@@ -546,6 +571,11 @@ packages:
safer-buffer: 2.1.2 safer-buffer: 2.1.2
dev: false dev: false
/assert-plus/1.0.0:
resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
engines: {node: '>=0.8'}
dev: false
/ast-types-flow/0.0.7: /ast-types-flow/0.0.7:
resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==}
dev: true dev: true
@@ -574,6 +604,14 @@ packages:
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
dev: true dev: true
/aws-sign2/0.7.0:
resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
dev: false
/aws4/1.12.0:
resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==}
dev: false
/axe-core/4.4.3: /axe-core/4.4.3:
resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==} resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -585,7 +623,6 @@ packages:
/balanced-match/1.0.2: /balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base64-js/1.5.1: /base64-js/1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -615,7 +652,6 @@ packages:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
concat-map: 0.0.1 concat-map: 0.0.1
dev: true
/braces/3.0.2: /braces/3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
@@ -648,6 +684,11 @@ packages:
dev: false dev: false
optional: true optional: true
/byline/5.0.0:
resolution: {integrity: sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==}
engines: {node: '>=0.10.0'}
dev: false
/bytes/3.1.2: /bytes/3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -673,6 +714,10 @@ packages:
/caniuse-lite/1.0.30001410: /caniuse-lite/1.0.30001410:
resolution: {integrity: sha512-QoblBnuE+rG0lc3Ur9ltP5q47lbguipa/ncNMyyGuqPk44FxbScWAeEO+k5fSQ8WekdAK4mWqNs1rADDAiN5xQ==} resolution: {integrity: sha512-QoblBnuE+rG0lc3Ur9ltP5q47lbguipa/ncNMyyGuqPk44FxbScWAeEO+k5fSQ8WekdAK4mWqNs1rADDAiN5xQ==}
/caseless/0.12.0:
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
dev: false
/chalk/4.1.2: /chalk/4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -700,6 +745,11 @@ packages:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: false dev: false
/chownr/2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
dev: false
/classnames/2.3.2: /classnames/2.3.2:
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
dev: false dev: false
@@ -758,7 +808,6 @@ packages:
/concat-map/0.0.1: /concat-map/0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/confusing-browser-globals/1.0.11: /confusing-browser-globals/1.0.11:
resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==}
@@ -774,13 +823,17 @@ packages:
requiresBuild: true requiresBuild: true
dev: false dev: false
/core-util-is/1.0.2:
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
dev: false
/cpu-features/0.0.4: /cpu-features/0.0.4:
resolution: {integrity: sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==} resolution: {integrity: sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
requiresBuild: true requiresBuild: true
dependencies: dependencies:
buildcheck: 0.0.3 buildcheck: 0.0.3
nan: 2.16.0 nan: 2.17.0
dev: false dev: false
optional: true optional: true
@@ -791,7 +844,6 @@ packages:
path-key: 3.1.1 path-key: 3.1.1
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
dev: true
/cssesc/3.0.0: /cssesc/3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
@@ -807,6 +859,13 @@ packages:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
dev: true dev: true
/dashdash/1.14.1:
resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
engines: {node: '>=0.10'}
dependencies:
assert-plus: 1.0.0
dev: false
/debug/2.6.9: /debug/2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies: peerDependencies:
@@ -928,6 +987,13 @@ packages:
esutils: 2.0.3 esutils: 2.0.3
dev: true dev: true
/ecc-jsbn/0.1.2:
resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
dependencies:
jsbn: 0.1.1
safer-buffer: 2.1.2
dev: false
/electron-to-chromium/1.4.261: /electron-to-chromium/1.4.261:
resolution: {integrity: sha512-fVXliNUGJ7XUVJSAasPseBbVgJIeyw5M1xIkgXdTSRjlmCqBbiSTsEdLOCJS31Fc8B7CaloQ/BFAg8By3ODLdg==} resolution: {integrity: sha512-fVXliNUGJ7XUVJSAasPseBbVgJIeyw5M1xIkgXdTSRjlmCqBbiSTsEdLOCJS31Fc8B7CaloQ/BFAg8By3ODLdg==}
dev: true dev: true
@@ -1396,9 +1462,32 @@ packages:
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true dev: true
/execa/5.0.0:
resolution: {integrity: sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==}
engines: {node: '>=10'}
dependencies:
cross-spawn: 7.0.3
get-stream: 6.0.1
human-signals: 2.1.0
is-stream: 2.0.1
merge-stream: 2.0.0
npm-run-path: 4.0.1
onetime: 5.1.2
signal-exit: 3.0.7
strip-final-newline: 2.0.0
dev: false
/extend/3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
dev: false
/extsprintf/1.3.0:
resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
engines: {'0': node >=0.6.0}
dev: false
/fast-deep-equal/3.1.3: /fast-deep-equal/3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-diff/1.2.0: /fast-diff/1.2.0:
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
@@ -1417,7 +1506,6 @@ packages:
/fast-json-stable-stringify/2.1.0: /fast-json-stable-stringify/2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: true
/fast-levenshtein/2.0.6: /fast-levenshtein/2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
@@ -1481,6 +1569,19 @@ packages:
optional: true optional: true
dev: false dev: false
/forever-agent/0.6.1:
resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
dev: false
/form-data/2.3.3:
resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
engines: {node: '>= 0.12'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/form-data/3.0.1: /form-data/3.0.1:
resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@@ -1498,9 +1599,15 @@ packages:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: false dev: false
/fs-minipass/2.1.0:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
engines: {node: '>= 8'}
dependencies:
minipass: 3.3.6
dev: false
/fs.realpath/1.0.0: /fs.realpath/1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
/fsevents/2.3.2: /fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
@@ -1512,7 +1619,6 @@ packages:
/function-bind/1.1.1: /function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: true
/function.prototype.name/1.1.5: /function.prototype.name/1.1.5:
resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
@@ -1536,6 +1642,11 @@ packages:
has-symbols: 1.0.3 has-symbols: 1.0.3
dev: true dev: true
/get-stream/6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
dev: false
/get-symbol-description/1.0.0: /get-symbol-description/1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -1544,6 +1655,12 @@ packages:
get-intrinsic: 1.1.3 get-intrinsic: 1.1.3
dev: true dev: true
/getpass/0.1.7:
resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
dependencies:
assert-plus: 1.0.0
dev: false
/glob-parent/5.1.2: /glob-parent/5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@@ -1578,7 +1695,6 @@ packages:
minimatch: 3.1.2 minimatch: 3.1.2
once: 1.4.0 once: 1.4.0
path-is-absolute: 1.0.1 path-is-absolute: 1.0.1
dev: true
/globals/13.17.0: /globals/13.17.0:
resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==}
@@ -1603,6 +1719,20 @@ packages:
resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
dev: true dev: true
/har-schema/2.0.0:
resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
engines: {node: '>=4'}
dev: false
/har-validator/5.1.5:
resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
engines: {node: '>=6'}
deprecated: this library is no longer supported
dependencies:
ajv: 6.12.6
har-schema: 2.0.0
dev: false
/has-bigints/1.0.2: /has-bigints/1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
dev: true dev: true
@@ -1635,7 +1765,6 @@ packages:
engines: {node: '>= 0.4.0'} engines: {node: '>= 0.4.0'}
dependencies: dependencies:
function-bind: 1.1.1 function-bind: 1.1.1
dev: true
/hoist-non-react-statics/3.3.2: /hoist-non-react-statics/3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
@@ -1660,6 +1789,20 @@ packages:
toidentifier: 1.0.1 toidentifier: 1.0.1
dev: false dev: false
/http-signature/1.2.0:
resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==}
engines: {node: '>=0.8', npm: '>=1.3.7'}
dependencies:
assert-plus: 1.0.0
jsprim: 1.4.2
sshpk: 1.17.0
dev: false
/human-signals/2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
dev: false
/i18next-fs-backend/1.1.5: /i18next-fs-backend/1.1.5:
resolution: {integrity: sha512-raTel3EfshiUXxR0gvmIoqp75jhkj8+7R1LjB006VZKPTFBbXyx6TlUVhb8Z9+7ahgpFbcQg1QWVOdf/iNzI5A==} resolution: {integrity: sha512-raTel3EfshiUXxR0gvmIoqp75jhkj8+7R1LjB006VZKPTFBbXyx6TlUVhb8Z9+7ahgpFbcQg1QWVOdf/iNzI5A==}
dev: false dev: false
@@ -1704,7 +1847,6 @@ packages:
dependencies: dependencies:
once: 1.4.0 once: 1.4.0
wrappy: 1.0.2 wrappy: 1.0.2
dev: true
/inherits/2.0.4: /inherits/2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -1718,6 +1860,11 @@ packages:
side-channel: 1.0.4 side-channel: 1.0.4
dev: true dev: true
/interpret/1.4.0:
resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
engines: {node: '>= 0.10'}
dev: false
/is-arrayish/0.3.2: /is-arrayish/0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: false dev: false
@@ -1752,7 +1899,6 @@ packages:
resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==}
dependencies: dependencies:
has: 1.0.3 has: 1.0.3
dev: true
/is-date-object/1.0.5: /is-date-object/1.0.5:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
@@ -1823,6 +1969,10 @@ packages:
has-symbols: 1.0.3 has-symbols: 1.0.3
dev: true dev: true
/is-typedarray/1.0.0:
resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
dev: false
/is-weakref/1.0.2: /is-weakref/1.0.2:
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
dependencies: dependencies:
@@ -1831,7 +1981,23 @@ packages:
/isexe/2.0.0: /isexe/2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/isomorphic-ws/4.0.1_ws@7.5.9:
resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==}
peerDependencies:
ws: '*'
dependencies:
ws: 7.5.9
dev: false
/isstream/0.1.2:
resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
dev: false
/jose/4.11.2:
resolution: {integrity: sha512-njj0VL2TsIxCtgzhO+9RRobBvws4oYyCM8TpvoUQwl/MbIM3NFJRR9+e6x0sS5xXaP1t6OCBkaBME98OV9zU5A==}
dev: false
optional: true
/js-sdsl/4.1.4: /js-sdsl/4.1.4:
resolution: {integrity: sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==} resolution: {integrity: sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==}
@@ -1846,18 +2012,29 @@ packages:
dependencies: dependencies:
argparse: 2.0.1 argparse: 2.0.1
/jsbn/0.1.1:
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
dev: false
/json-rpc-2.0/1.4.1: /json-rpc-2.0/1.4.1:
resolution: {integrity: sha512-OX1NJhpIfuK4GjDnJ/gKtZy1HOYo0l4eL0a4rb0rNeQheX1xlyQ9+JMmPzs/sFNthpS/TXKPWlGo09X7B5l81A==} resolution: {integrity: sha512-OX1NJhpIfuK4GjDnJ/gKtZy1HOYo0l4eL0a4rb0rNeQheX1xlyQ9+JMmPzs/sFNthpS/TXKPWlGo09X7B5l81A==}
dev: false dev: false
/json-schema-traverse/0.4.1: /json-schema-traverse/0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: true
/json-schema/0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
dev: false
/json-stable-stringify-without-jsonify/1.0.1: /json-stable-stringify-without-jsonify/1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
dev: true dev: true
/json-stringify-safe/5.0.1:
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
dev: false
/json5/1.0.1: /json5/1.0.1:
resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==}
hasBin: true hasBin: true
@@ -1865,6 +2042,21 @@ packages:
minimist: 1.2.6 minimist: 1.2.6
dev: true dev: true
/jsonpath-plus/0.19.0:
resolution: {integrity: sha512-GSVwsrzW9LsA5lzsqe4CkuZ9wp+kxBb2GwNniaWzI2YFn5Ig42rSW8ZxVpWXaAfakXNrx5pgY5AbQq7kzX29kg==}
engines: {node: '>=6.0'}
dev: false
/jsprim/1.4.2:
resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
engines: {node: '>=0.6.0'}
dependencies:
assert-plus: 1.0.0
extsprintf: 1.3.0
json-schema: 0.4.0
verror: 1.10.0
dev: false
/jsx-ast-utils/3.3.3: /jsx-ast-utils/3.3.3:
resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
@@ -1932,12 +2124,15 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
dependencies: dependencies:
yallist: 4.0.0 yallist: 4.0.0
dev: true
/memory-cache/0.2.0: /memory-cache/0.2.0:
resolution: {integrity: sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==} resolution: {integrity: sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==}
dev: false dev: false
/merge-stream/2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
dev: false
/merge2/1.4.1: /merge2/1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -1963,6 +2158,11 @@ packages:
mime-db: 1.52.0 mime-db: 1.52.0
dev: false dev: false
/mimic-fn/2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
dev: false
/mini-svg-data-uri/1.4.4: /mini-svg-data-uri/1.4.4:
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
hasBin: true hasBin: true
@@ -1972,16 +2172,43 @@ packages:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies: dependencies:
brace-expansion: 1.1.11 brace-expansion: 1.1.11
dev: true
/minimist/1.2.6: /minimist/1.2.6:
resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
dev: true dev: true
/minipass/3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
engines: {node: '>=8'}
dependencies:
yallist: 4.0.0
dev: false
/minipass/4.0.0:
resolution: {integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==}
engines: {node: '>=8'}
dependencies:
yallist: 4.0.0
dev: false
/minizlib/2.1.2:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
engines: {node: '>= 8'}
dependencies:
minipass: 3.3.6
yallist: 4.0.0
dev: false
/mkdirp-classic/0.5.3: /mkdirp-classic/0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
dev: false dev: false
/mkdirp/1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
hasBin: true
dev: false
/ms/2.0.0: /ms/2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
dev: true dev: true
@@ -1992,8 +2219,8 @@ packages:
/ms/2.1.3: /ms/2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
/nan/2.16.0: /nan/2.17.0:
resolution: {integrity: sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==} resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==}
dev: false dev: false
optional: true optional: true
@@ -2102,11 +2329,28 @@ packages:
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true dev: true
/npm-run-path/4.0.1:
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
engines: {node: '>=8'}
dependencies:
path-key: 3.1.1
dev: false
/oauth-sign/0.9.0:
resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
dev: false
/object-assign/4.1.1: /object-assign/4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true dev: true
/object-hash/2.2.0:
resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==}
engines: {node: '>= 6'}
dev: false
optional: true
/object-hash/3.0.0: /object-hash/3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@@ -2165,6 +2409,12 @@ packages:
es-abstract: 1.20.3 es-abstract: 1.20.3
dev: true dev: true
/oidc-token-hash/5.0.1:
resolution: {integrity: sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==}
engines: {node: ^10.13.0 || >=12.0.0}
dev: false
optional: true
/once/1.4.0: /once/1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies: dependencies:
@@ -2176,6 +2426,24 @@ packages:
fn.name: 1.1.0 fn.name: 1.1.0
dev: false dev: false
/onetime/5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}
dependencies:
mimic-fn: 2.1.0
dev: false
/openid-client/5.3.1:
resolution: {integrity: sha512-RLfehQiHch9N6tRWNx68cicf3b1WR0x74bJWHRc25uYIbSRwjxYcTFaRnzbbpls5jroLAaB/bFIodTgA5LJMvw==}
requiresBuild: true
dependencies:
jose: 4.11.2
lru-cache: 6.0.0
object-hash: 2.2.0
oidc-token-hash: 5.0.1
dev: false
optional: true
/optionator/0.9.1: /optionator/0.9.1:
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -2217,22 +2485,23 @@ packages:
/path-is-absolute/1.0.1: /path-is-absolute/1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true
/path-key/3.1.1: /path-key/3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true
/path-parse/1.0.7: /path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
/path-type/4.0.0: /path-type/4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/performance-now/2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
dev: false
/picocolors/1.0.0: /picocolors/1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@@ -2371,6 +2640,11 @@ packages:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'} engines: {node: '>=6'}
/qs/6.5.3:
resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
engines: {node: '>=0.6'}
dev: false
/querystringify/2.2.0: /querystringify/2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
dev: false dev: false
@@ -2464,6 +2738,13 @@ packages:
picomatch: 2.3.1 picomatch: 2.3.1
dev: true dev: true
/rechoir/0.6.2:
resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
engines: {node: '>= 0.10'}
dependencies:
resolve: 1.22.1
dev: false
/regenerator-runtime/0.13.9: /regenerator-runtime/0.13.9:
resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
@@ -2481,6 +2762,33 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/request/2.88.2:
resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
engines: {node: '>= 6'}
deprecated: request has been deprecated, see https://github.com/request/request/issues/3142
dependencies:
aws-sign2: 0.7.0
aws4: 1.12.0
caseless: 0.12.0
combined-stream: 1.0.8
extend: 3.0.2
forever-agent: 0.6.1
form-data: 2.3.3
har-validator: 5.1.5
http-signature: 1.2.0
is-typedarray: 1.0.0
isstream: 0.1.2
json-stringify-safe: 5.0.1
mime-types: 2.1.35
oauth-sign: 0.9.0
performance-now: 2.1.0
qs: 6.5.3
safe-buffer: 5.2.1
tough-cookie: 2.5.0
tunnel-agent: 0.6.0
uuid: 3.4.0
dev: false
/requires-port/1.0.0: /requires-port/1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
dev: false dev: false
@@ -2497,7 +2805,6 @@ packages:
is-core-module: 2.10.0 is-core-module: 2.10.0
path-parse: 1.0.7 path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0 supports-preserve-symlinks-flag: 1.0.0
dev: true
/resolve/2.0.0-next.4: /resolve/2.0.0-next.4:
resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==}
@@ -2513,12 +2820,15 @@ packages:
engines: {iojs: '>=1.0.0', node: '>=0.10.0'} engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true dev: true
/rfc4648/1.5.2:
resolution: {integrity: sha512-tLOizhR6YGovrEBLatX1sdcuhoSCXddw3mqNVAcKxGJ+J0hFeJ+SjeWCv5UPA/WU3YzWPPuCVYgXBKZUPGpKtg==}
dev: false
/rimraf/3.0.2: /rimraf/3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true hasBin: true
dependencies: dependencies:
glob: 7.2.3 glob: 7.2.3
dev: true
/run-parallel/1.2.0: /run-parallel/1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -2588,12 +2898,20 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dependencies: dependencies:
shebang-regex: 3.0.0 shebang-regex: 3.0.0
dev: true
/shebang-regex/3.0.0: /shebang-regex/3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true
/shelljs/0.8.5:
resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==}
engines: {node: '>=4'}
hasBin: true
dependencies:
glob: 7.2.3
interpret: 1.4.0
rechoir: 0.6.2
dev: false
/shvl/3.0.0: /shvl/3.0.0:
resolution: {integrity: sha512-5IomAM3ykE/g9K9L6lhODc+TpCuN03rrhlboegeKyyfh66DDdpRD5JN37DYhNHH+RaYjiIDx64K/Ms/xQYOR5w==} resolution: {integrity: sha512-5IomAM3ykE/g9K9L6lhODc+TpCuN03rrhlboegeKyyfh66DDdpRD5JN37DYhNHH+RaYjiIDx64K/Ms/xQYOR5w==}
@@ -2607,6 +2925,10 @@ packages:
object-inspect: 1.12.2 object-inspect: 1.12.2
dev: true dev: true
/signal-exit/3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: false
/simple-swizzle/0.2.2: /simple-swizzle/0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
dependencies: dependencies:
@@ -2635,7 +2957,23 @@ packages:
bcrypt-pbkdf: 1.0.2 bcrypt-pbkdf: 1.0.2
optionalDependencies: optionalDependencies:
cpu-features: 0.0.4 cpu-features: 0.0.4
nan: 2.16.0 nan: 2.17.0
dev: false
/sshpk/1.17.0:
resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
engines: {node: '>=0.10.0'}
hasBin: true
dependencies:
asn1: 0.2.6
assert-plus: 1.0.0
bcrypt-pbkdf: 1.0.2
dashdash: 1.14.1
ecc-jsbn: 0.1.2
getpass: 0.1.7
jsbn: 0.1.1
safer-buffer: 2.1.2
tweetnacl: 0.14.5
dev: false dev: false
/stack-trace/0.0.10: /stack-trace/0.0.10:
@@ -2647,6 +2985,11 @@ packages:
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
dev: false dev: false
/stream-buffers/3.0.2:
resolution: {integrity: sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==}
engines: {node: '>= 0.10.0'}
dev: false
/string.prototype.matchall/4.0.7: /string.prototype.matchall/4.0.7:
resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==} resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==}
dependencies: dependencies:
@@ -2694,6 +3037,11 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/strip-final-newline/2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
dev: false
/strip-json-comments/3.1.1: /strip-json-comments/3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -2725,7 +3073,6 @@ packages:
/supports-preserve-symlinks-flag/1.0.0: /supports-preserve-symlinks-flag/1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dev: true
/swr/1.3.0_react@18.2.0: /swr/1.3.0_react@18.2.0:
resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==} resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==}
@@ -2797,6 +3144,18 @@ packages:
readable-stream: 3.6.0 readable-stream: 3.6.0
dev: false dev: false
/tar/6.1.13:
resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==}
engines: {node: '>=10'}
dependencies:
chownr: 2.0.0
fs-minipass: 2.1.0
minipass: 4.0.0
minizlib: 2.1.2
mkdirp: 1.0.4
yallist: 4.0.0
dev: false
/text-hex/1.0.0: /text-hex/1.0.0:
resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
dev: false dev: false
@@ -2805,6 +3164,19 @@ packages:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true dev: true
/tmp-promise/3.0.3:
resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
dependencies:
tmp: 0.2.1
dev: false
/tmp/0.2.1:
resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
engines: {node: '>=8.17.0'}
dependencies:
rimraf: 3.0.2
dev: false
/to-regex-range/5.0.1: /to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'} engines: {node: '>=8.0'}
@@ -2817,6 +3189,14 @@ packages:
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
dev: false dev: false
/tough-cookie/2.5.0:
resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
engines: {node: '>=0.8'}
dependencies:
psl: 1.9.0
punycode: 2.1.1
dev: false
/tough-cookie/4.1.2: /tough-cookie/4.1.2:
resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -2846,7 +3226,6 @@ packages:
/tslib/1.14.1: /tslib/1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
/tslib/2.4.0: /tslib/2.4.0:
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
@@ -2862,6 +3241,12 @@ packages:
typescript: 4.8.3 typescript: 4.8.3
dev: true dev: true
/tunnel-agent/0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
dependencies:
safe-buffer: 5.2.1
dev: false
/tweetnacl/0.14.5: /tweetnacl/0.14.5:
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
dev: false dev: false
@@ -2893,6 +3278,10 @@ packages:
which-boxed-primitive: 1.0.2 which-boxed-primitive: 1.0.2
dev: true dev: true
/underscore/1.13.6:
resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==}
dev: false
/universalify/0.2.0: /universalify/0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'} engines: {node: '>= 4.0.0'}
@@ -2918,7 +3307,6 @@ packages:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies: dependencies:
punycode: 2.1.1 punycode: 2.1.1
dev: true
/url-parse/1.5.10: /url-parse/1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
@@ -2938,6 +3326,21 @@ packages:
/util-deprecate/1.0.2: /util-deprecate/1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
/uuid/3.4.0:
resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
hasBin: true
dev: false
/verror/1.10.0:
resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
engines: {'0': node >=0.6.0}
dependencies:
assert-plus: 1.0.0
core-util-is: 1.0.2
extsprintf: 1.3.0
dev: false
/void-elements/3.1.0: /void-elements/3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -2970,7 +3373,6 @@ packages:
hasBin: true hasBin: true
dependencies: dependencies:
isexe: 2.0.0 isexe: 2.0.0
dev: true
/winston-transport/4.5.0: /winston-transport/4.5.0:
resolution: {integrity: sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==} resolution: {integrity: sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==}
@@ -3006,6 +3408,19 @@ packages:
/wrappy/1.0.2: /wrappy/1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
/ws/7.5.9:
resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==}
engines: {node: '>=8.3.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: false
/xml-js/1.6.11: /xml-js/1.6.11:
resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
hasBin: true hasBin: true
@@ -3020,7 +3435,6 @@ packages:
/yallist/4.0.0: /yallist/4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true
/yaml/1.10.2: /yaml/1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"print_progress": "Progress",
"printer_state": "Printer State",
"print_status": "Print Status",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"print_progress": "Progress",
"printer_state": "Printer State",
"print_status": "Print Status",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -255,6 +255,11 @@
"status_count": "Posts", "status_count": "Posts",
"domain_count": "Domains" "domain_count": "Domains"
}, },
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"miniflux": { "miniflux": {
"read": "Read", "read": "Read",
"unread": "Unread" "unread": "Unread"
@@ -412,5 +417,17 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"layers": "Layers",
"print_progress": "Progress"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -164,7 +164,7 @@
"qbittorrent": { "qbittorrent": {
"download": "Bajada", "download": "Bajada",
"upload": "Subida", "upload": "Subida",
"leech": "Leech", "leech": "Depender",
"seed": "Semillas" "seed": "Semillas"
}, },
"mastodon": { "mastodon": {
@@ -347,14 +347,14 @@
"deluge": { "deluge": {
"download": "Descarga", "download": "Descarga",
"upload": "Subida", "upload": "Subida",
"leech": "Leech", "leech": "Depender",
"seed": "Semilla" "seed": "Semilla"
}, },
"flood": { "flood": {
"download": "Descargar", "download": "Descargar",
"upload": "Subir", "upload": "Subir",
"leech": "Leech", "leech": "Depender",
"seed": "Seed" "seed": "Semillas"
}, },
"tdarr": { "tdarr": {
"queue": "Cola", "queue": "Cola",
@@ -394,14 +394,31 @@
"numberOfLeases": "Alquileres" "numberOfLeases": "Alquileres"
}, },
"xteve": { "xteve": {
"streams_all": "All Streams", "streams_all": "Todas las corrientes",
"streams_active": "Active Streams", "streams_active": "Corrientes activas",
"streams_xepg": "XEPG Channels" "streams_xepg": "Canales XEPG"
}, },
"opnsense": { "opnsense": {
"cpu": "CPU Load", "cpu": "Carga de la CPU",
"memory": "Active Memory", "memory": "Memoria activa",
"wanUpload": "WAN Upload", "wanUpload": "Carga WAN",
"wanDownload": "WAN Download" "wanDownload": "Descargar WAN"
},
"moonraker": {
"printer_state": "Estado de la impresora",
"print_status": "Estado de la impresora",
"print_progress": "Progreso",
"layers": "Capas"
},
"medusa": {
"wanted": "Querido",
"queued": "A la espera",
"series": "Serie"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -399,9 +399,26 @@
"streams_xepg": "Canal XEPG" "streams_xepg": "Canal XEPG"
}, },
"opnsense": { "opnsense": {
"cpu": "CPU Load", "cpu": "Charge CPU",
"memory": "Active Memory", "memory": "Mém. Utilisée",
"wanUpload": "WAN Upload", "wanUpload": "WAN Envoi",
"wanDownload": "WAN Download" "wanDownload": "WAN Récep."
},
"moonraker": {
"printer_state": "État Imprimante",
"print_status": "Statut Imprimante",
"print_progress": "Progression",
"layers": "Couches"
},
"medusa": {
"wanted": "Demande",
"queued": "En attente",
"series": "Séries"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -77,13 +77,13 @@
"emby": { "emby": {
"playing": "Reprodukcija", "playing": "Reprodukcija",
"transcoding": "Prekodiranje", "transcoding": "Prekodiranje",
"bitrate": "Brzina prijenosa", "bitrate": "Stopa bitova",
"no_active": "Nema aktivnih prijenosa" "no_active": "Nema aktivnih prijenosa"
}, },
"tautulli": { "tautulli": {
"playing": "Reprodukcija", "playing": "Reprodukcija",
"transcoding": "Prekodiranje", "transcoding": "Prekodiranje",
"bitrate": "Brzina prijenosa", "bitrate": "Stopa bitova",
"no_active": "Nema aktivnih prijenosa" "no_active": "Nema aktivnih prijenosa"
}, },
"nzbget": { "nzbget": {
@@ -347,61 +347,78 @@
"deluge": { "deluge": {
"download": "Preuzimanje", "download": "Preuzimanje",
"upload": "Prijenos", "upload": "Prijenos",
"leech": "Leech", "leech": "Korištenje tuđeg sadržaja",
"seed": "Seed" "seed": "Prenošenje preuzetog sadržaja"
}, },
"flood": { "flood": {
"download": "Preuzimanje", "download": "Preuzimanje",
"upload": "Prijenos", "upload": "Prijenos",
"leech": "Leech", "leech": "Korištenje tuđeg sadržaja",
"seed": "Seed" "seed": "Prenošenje preuzetog sadržaja"
}, },
"tdarr": { "tdarr": {
"queue": "Queue", "queue": "Red čekanja",
"processed": "Processed", "processed": "Obrađeno",
"errored": "Errored", "errored": "S greškom",
"saved": "Saved" "saved": "Spremljeno"
}, },
"miniflux": { "miniflux": {
"read": "Read", "read": "Pročitano",
"unread": "Unread" "unread": "Nepročitano"
}, },
"nextdns": { "nextdns": {
"wait": "Please Wait", "wait": "Pričekaj",
"no_devices": "No Device Data Received" "no_devices": "Podaci o uređaju nisu primljeni"
}, },
"common": { "common": {
"bibyterate": "{{value, rate(bits: false; binary: true)}}", "bibyterate": "{{value, rate(bits: false; binary: true)}}",
"bibitrate": "{{value, rate(bits: true; binary: true)}}" "bibitrate": "{{value, rate(bits: true; binary: true)}}"
}, },
"omada": { "omada": {
"connectedAp": "Connected APs", "connectedAp": "Povezani AP-ovi",
"activeUser": "Active devices", "activeUser": "Aktivni uređaji",
"alerts": "Alerts", "alerts": "Upozorenja",
"connectedGateway": "Connected gateways", "connectedGateway": "Povezani pristupi",
"connectedSwitches": "Connected switches" "connectedSwitches": "Povezani prekidači"
}, },
"downloadstation": { "downloadstation": {
"download": "Download", "download": "Preuzimanje",
"upload": "Upload", "upload": "Prijenos",
"leech": "Leech", "leech": "Korištenje tuđeg sadržaja",
"seed": "Seed" "seed": "Prenošenje preuzetog sadržaja"
}, },
"mikrotik": { "mikrotik": {
"cpuLoad": "CPU Load", "cpuLoad": "CPU opterećenje",
"memoryUsed": "Memory Used", "memoryUsed": "Korištena memorija",
"uptime": "Uptime", "uptime": "Radno vrijeme",
"numberOfLeases": "Leases" "numberOfLeases": "Unajmljivanja"
}, },
"xteve": { "xteve": {
"streams_all": "All Streams", "streams_all": "Svi prijenosi",
"streams_active": "Active Streams", "streams_active": "Aktivni prijenosi",
"streams_xepg": "XEPG Channels" "streams_xepg": "XEPG kanali"
}, },
"opnsense": { "opnsense": {
"cpu": "CPU Load", "cpu": "CPU opterećenje",
"memory": "Active Memory", "memory": "Aktivna memorija",
"wanUpload": "WAN Upload", "wanUpload": "WAN prijenos",
"wanDownload": "WAN Download" "wanDownload": "WAN preuzimanje"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"layers": "Layers",
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -51,7 +51,7 @@
"total": "Totale", "total": "Totale",
"free": "Libero", "free": "Libero",
"used": "In utilizzo", "used": "In utilizzo",
"load": "Carica", "load": "Carico",
"cpu": "CPU" "cpu": "CPU"
}, },
"rutorrent": { "rutorrent": {
@@ -175,7 +175,7 @@
"strelaysrv": { "strelaysrv": {
"numActiveSessions": "Sessioni", "numActiveSessions": "Sessioni",
"numConnections": "Connessioni", "numConnections": "Connessioni",
"dataRelayed": "Ritrasmettessi", "dataRelayed": "Ritrasmessi",
"transferRate": "Velocità" "transferRate": "Velocità"
}, },
"authentik": { "authentik": {
@@ -222,10 +222,10 @@
"wmo": { "wmo": {
"65-day": "Pioggia Intensa", "65-day": "Pioggia Intensa",
"2-night": "Parzialmente Nuvoloso", "2-night": "Parzialmente Nuvoloso",
"0-day": "Solleggiato", "0-day": "Soleggiato",
"0-night": "Pulisci", "0-night": "Sereno",
"1-day": "Principalmente Soleggiato", "1-day": "Prevalentemente Soleggiato",
"1-night": "Principalmente Sereno", "1-night": "Prevalentemente Sereno",
"2-day": "Parzialmente Nuvoloso", "2-day": "Parzialmente Nuvoloso",
"3-day": "Nuvoloso", "3-day": "Nuvoloso",
"3-night": "Nuvoloso", "3-night": "Nuvoloso",
@@ -314,7 +314,7 @@
}, },
"navidrome": { "navidrome": {
"nothing_streaming": "Nessun Sistema Attivo", "nothing_streaming": "Nessun Sistema Attivo",
"please_wait": "Attendere, Prego" "please_wait": "Attendere prego"
}, },
"pyload": { "pyload": {
"speed": "Velocità", "speed": "Velocità",
@@ -391,17 +391,34 @@
"cpuLoad": "Carico della CPU", "cpuLoad": "Carico della CPU",
"memoryUsed": "Memoria Utilizzata", "memoryUsed": "Memoria Utilizzata",
"uptime": "Tempo di attività", "uptime": "Tempo di attività",
"numberOfLeases": "Leases" "numberOfLeases": "Lease"
}, },
"xteve": { "xteve": {
"streams_all": "All Streams", "streams_all": "Tutti gli stream",
"streams_active": "Active Streams", "streams_active": "Stream attivi",
"streams_xepg": "XEPG Channels" "streams_xepg": "Canali XEPG"
}, },
"opnsense": { "opnsense": {
"cpu": "CPU Load", "cpu": "Carico CPU",
"memory": "Active Memory", "memory": "Memoria in uso",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -0,0 +1,424 @@
{
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"npm": {
"total": "Total",
"enabled": "Enabled",
"disabled": "Disabled"
},
"strelaysrv": {
"numActiveSessions": "Sessions",
"numConnections": "Connections",
"dataRelayed": "Relayed",
"transferRate": "Rate"
},
"glances": {
"mem": "MEM",
"cpu": "CPU",
"wait": "Please wait"
},
"autobrr": {
"filters": "Filters",
"indexers": "Indexers",
"approvedPushes": "Approved",
"rejectedPushes": "Rejected"
},
"gluetun": {
"region": "Region",
"country": "Country",
"public_ip": "Public IP"
},
"common": {
"bibyterate": "{{value, rate(bits: false; binary: true)}}",
"bibitrate": "{{value, rate(bits: true; binary: true)}}"
},
"widget": {
"api_error": "APIエラー",
"information": "情報",
"missing_type": "見つからないウィジェットタイプ: {{type}}",
"status": "ステータス",
"url": "URL",
"raw_error": "生のエラー",
"response_data": "レスポンスデータ"
},
"weather": {
"current": "Current Location",
"allow": "Click to allow",
"updating": "Updating",
"wait": "Please wait"
},
"search": {
"placeholder": "Search…"
},
"resources": {
"cpu": "CPU",
"total": "Total",
"free": "Free",
"used": "Used",
"load": "Load"
},
"unifi": {
"users": "Users",
"uptime": "System Uptime",
"days": "Days",
"wan": "WAN",
"lan": "LAN",
"wlan": "WLAN",
"devices": "Devices",
"lan_devices": "LAN Devices",
"wlan_devices": "WLAN Devices",
"lan_users": "LAN Users",
"wlan_users": "WLAN Users",
"up": "UP",
"down": "DOWN",
"wait": "Please wait"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "MEM",
"cpu": "CPU",
"offline": "Offline",
"error": "Error",
"unknown": "Unknown"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"emby": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"changedetectionio": {
"totalObserved": "Total Observed",
"diffsDetected": "Diffs Detected"
},
"tautulli": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
"alerts": "Alerts",
"connectedGateway": "Connected gateways",
"connectedSwitches": "Connected switches"
},
"nzbget": {
"rate": "Rate",
"remaining": "Remaining",
"downloaded": "Downloaded"
},
"plex": {
"streams": "Active Streams",
"movies": "Movies",
"tv": "TV Shows"
},
"sabnzbd": {
"rate": "Rate",
"queue": "Queue",
"timeleft": "Time Left"
},
"rutorrent": {
"active": "Active",
"upload": "Upload",
"download": "Download"
},
"transmission": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"downloadstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"radarr": {
"wanted": "Wanted",
"missing": "Missing",
"queued": "Queued",
"movies": "Movies"
},
"lidarr": {
"wanted": "Wanted",
"queued": "Queued",
"albums": "Albums"
},
"readarr": {
"wanted": "Wanted",
"queued": "Queued",
"books": "Books"
},
"bazarr": {
"missingEpisodes": "Missing Episodes",
"missingMovies": "Missing Movies"
},
"ombi": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"pihole": {
"queries": "Queries",
"blocked": "Blocked",
"gravity": "Gravity"
},
"adguard": {
"queries": "Queries",
"blocked": "Blocked",
"filtered": "Filtered",
"latency": "Latency"
},
"speedtest": {
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},
"portainer": {
"running": "Running",
"stopped": "Stopped",
"total": "Total"
},
"tdarr": {
"queue": "Queue",
"processed": "Processed",
"errored": "Errored",
"saved": "Saved"
},
"traefik": {
"routers": "Routers",
"services": "Services",
"middleware": "Middleware"
},
"coinmarketcap": {
"configure": "Configure one or more crypto currencies to track",
"1hour": "1 Hour",
"1day": "1 Day",
"7days": "7 Days",
"30days": "30 Days"
},
"gotify": {
"apps": "Applications",
"clients": "Clients",
"messages": "Messages"
},
"prowlarr": {
"enableIndexers": "Indexers",
"numberOfGrabs": "Grabs",
"numberOfQueries": "Queries",
"numberOfFailGrabs": "Fail Grabs",
"numberOfFailQueries": "Fail Queries"
},
"jackett": {
"configured": "Configured",
"errored": "Errored"
},
"mastodon": {
"user_count": "Users",
"status_count": "Posts",
"domain_count": "Domains"
},
"miniflux": {
"read": "Read",
"unread": "Unread"
},
"authentik": {
"users": "Users",
"loginsLast24H": "Logins (24h)",
"failedLoginsLast24H": "Failed Logins (24h)"
},
"proxmox": {
"mem": "MEM",
"cpu": "CPU",
"lxc": "LXC",
"vms": "VMs"
},
"quicklaunch": {
"bookmark": "Bookmark",
"service": "Service"
},
"wmo": {
"0-day": "Sunny",
"1-day": "Mainly Sunny",
"0-night": "Clear",
"1-night": "Mainly Clear",
"2-day": "Partly Cloudy",
"2-night": "Partly Cloudy",
"3-day": "Cloudy",
"3-night": "Cloudy",
"45-day": "Foggy",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"51-day": "Light Drizzle",
"51-night": "Light Drizzle",
"53-day": "Drizzle",
"53-night": "Drizzle",
"55-day": "Heavy Drizzle",
"55-night": "Heavy Drizzle",
"56-day": "Light Freezing Drizzle",
"56-night": "Light Freezing Drizzle",
"57-day": "Freezing Drizzle",
"57-night": "Freezing Drizzle",
"61-day": "Light Rain",
"61-night": "Light Rain",
"63-day": "Rain",
"63-night": "Rain",
"67-night": "Freezing Rain",
"71-day": "Light Snow",
"65-day": "Heavy Rain",
"65-night": "Heavy Rain",
"66-day": "Freezing Rain",
"66-night": "Freezing Rain",
"67-day": "Freezing Rain",
"71-night": "Light Snow",
"73-day": "Snow",
"73-night": "Snow",
"75-day": "Heavy Snow",
"75-night": "Heavy Snow",
"77-day": "Snow Grains",
"77-night": "Snow Grains",
"80-day": "Light Showers",
"80-night": "Light Showers",
"81-day": "Showers",
"81-night": "Showers",
"82-day": "Heavy Showers",
"82-night": "Heavy Showers",
"85-day": "Snow Showers",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"95-day": "Thunderstorm",
"95-night": "Thunderstorm",
"96-day": "Thunderstorm With Hail",
"96-night": "Thunderstorm With Hail",
"99-day": "Thunderstorm With Hail",
"99-night": "Thunderstorm With Hail"
},
"homebridge": {
"available_update": "System",
"updates": "Updates",
"update_available": "Update Available",
"up_to_date": "Up to Date",
"child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"nextdns": {
"wait": "Please Wait",
"no_devices": "No Device Data Received"
},
"mikrotik": {
"cpuLoad": "CPU Load",
"memoryUsed": "Memory Used",
"uptime": "Uptime",
"numberOfLeases": "Leases"
},
"xteve": {
"streams_all": "All Streams",
"streams_active": "Active Streams",
"streams_xepg": "XEPG Channels"
},
"opnsense": {
"cpu": "CPU Load",
"memory": "Active Memory",
"wanUpload": "WAN Upload",
"wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
}
}

View File

@@ -0,0 +1,424 @@
{
"common": {
"bibyterate": "{{value, rate(bits: false; binary: true)}}",
"bibitrate": "{{value, rate(bits: true; binary: true)}}"
},
"widget": {
"missing_type": "Iztrūkst logrīka tips: {{type}}",
"api_error": "API kļūda",
"information": "Informācija",
"status": "Statuss",
"url": "URL",
"raw_error": "Kļūda",
"response_data": "Atbilde"
},
"weather": {
"current": "Pašreizējā atrašanās vieta",
"allow": "Piemiedziet, lai atļaut",
"updating": "Atjaunina",
"wait": "Lūdzu, uzgaidiet"
},
"search": {
"placeholder": "Meklēt…"
},
"resources": {
"cpu": "CPU",
"total": "Kopā",
"free": "Brīvs",
"used": "Izmantojas",
"load": "Ielādē"
},
"unifi": {
"users": "Lietotāji",
"uptime": "Sistēmas darbības laiks",
"days": "Dienas",
"wan": "WAN",
"lan": "LAN",
"wlan": "WLAN",
"devices": "Ierīces",
"lan_devices": "LAN ierīces",
"wlan_devices": "WLAN ierīces",
"lan_users": "LAN lietotāji",
"wlan_users": "WLAN lietotāji",
"up": "DARBOJAS",
"down": "NEDARBOJAS",
"wait": "Lūdzu, uzgaidiet"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "Atmiņa",
"cpu": "CPU",
"offline": "Bezsaistē",
"error": "Kļūda",
"unknown": "Nezināms"
},
"ping": {
"error": "Kļūda",
"ping": "Ping"
},
"emby": {
"playing": "Atskaņo",
"transcoding": "Pārkodē",
"bitrate": "Bitrate",
"no_active": "Nav aktīvu straumju"
},
"flood": {
"download": "Lejupielāde",
"upload": "Augšupielāde",
"leech": "Ņēmēji",
"seed": "Devēji"
},
"changedetectionio": {
"totalObserved": "Kopā novēro",
"diffsDetected": "Atšķirības atrastas"
},
"tautulli": {
"playing": "Atskaņo",
"transcoding": "Pārkodē",
"bitrate": "Bitrate",
"no_active": "Nav aktīvu straumju"
},
"omada": {
"connectedAp": "Savienotie piekļuves punkti",
"activeUser": "Aktīvās ierīces",
"alerts": "Paziņojumi",
"connectedGateway": "Savienotās vārtejas",
"connectedSwitches": "Savienotie komutatori"
},
"nzbget": {
"rate": "Rate",
"remaining": "Palika",
"downloaded": "Lejupielādēts"
},
"plex": {
"streams": "Aktīvās straumes",
"movies": "Filmas",
"tv": "TV pārraides"
},
"sabnzbd": {
"rate": "Rate",
"queue": "Rindā",
"timeleft": "Atlikušais laiks"
},
"rutorrent": {
"active": "Aktīvs",
"upload": "Augšupielāde",
"download": "Lejupielāde"
},
"transmission": {
"download": "Lejupielāde",
"upload": "Augšupielāde",
"leech": "Leech",
"seed": "Devēji"
},
"qbittorrent": {
"download": "Lejupielāde",
"upload": "Augšupielāde",
"leech": "Leech",
"seed": "Devēji"
},
"deluge": {
"download": "Lejupielāde",
"upload": "Augšupielāde",
"leech": "Leech",
"seed": "Devēji"
},
"downloadstation": {
"download": "Download",
"upload": "Augšupielāde",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"radarr": {
"wanted": "Wanted",
"missing": "Missing",
"queued": "Queued",
"movies": "Filmas"
},
"lidarr": {
"wanted": "Wanted",
"queued": "Queued",
"albums": "Albumi"
},
"readarr": {
"wanted": "Wanted",
"queued": "Queued",
"books": "Grāmatas"
},
"bazarr": {
"missingEpisodes": "Missing Episodes",
"missingMovies": "Missing Movies"
},
"ombi": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"pihole": {
"queries": "Queries",
"blocked": "Blocked",
"gravity": "Gravity"
},
"adguard": {
"queries": "Queries",
"blocked": "Blocked",
"filtered": "Filtered",
"latency": "Latency"
},
"speedtest": {
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},
"portainer": {
"running": "Running",
"stopped": "Stopped",
"total": "Total"
},
"tdarr": {
"queue": "Queue",
"processed": "Processed",
"errored": "Errored",
"saved": "Saved"
},
"traefik": {
"routers": "Routers",
"services": "Services",
"middleware": "Middleware"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"npm": {
"enabled": "Enabled",
"disabled": "Disabled",
"total": "Total"
},
"coinmarketcap": {
"configure": "Configure one or more crypto currencies to track",
"1hour": "1 Hour",
"1day": "1 Day",
"7days": "7 Days",
"30days": "30 Days"
},
"gotify": {
"apps": "Applications",
"clients": "Clients",
"messages": "Messages"
},
"prowlarr": {
"enableIndexers": "Indexers",
"numberOfGrabs": "Grabs",
"numberOfQueries": "Queries",
"numberOfFailGrabs": "Fail Grabs",
"numberOfFailQueries": "Fail Queries"
},
"jackett": {
"configured": "Configured",
"errored": "Errored"
},
"strelaysrv": {
"numActiveSessions": "Sessions",
"numConnections": "Connections",
"dataRelayed": "Relayed",
"transferRate": "Rate"
},
"mastodon": {
"user_count": "Users",
"status_count": "Posts",
"domain_count": "Domains"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"miniflux": {
"read": "Read",
"unread": "Unread"
},
"authentik": {
"users": "Users",
"loginsLast24H": "Logins (24h)",
"failedLoginsLast24H": "Failed Logins (24h)"
},
"proxmox": {
"mem": "MEM",
"cpu": "CPU",
"lxc": "LXC",
"vms": "VMs"
},
"glances": {
"cpu": "CPU",
"mem": "MEM",
"wait": "Please wait"
},
"quicklaunch": {
"bookmark": "Bookmark",
"service": "Service"
},
"wmo": {
"0-day": "Saulains",
"0-night": "Skaidrs",
"1-day": "Galvenokārt saulains",
"1-night": "Galvenokārt skaidrs",
"2-day": "Daļēji apmācies",
"2-night": "Daļēji apmācies",
"3-day": "Apmācies",
"3-night": "Apmācies",
"45-day": "Miglains",
"45-night": "Miglains",
"48-day": "Miglains",
"48-night": "Miglains",
"51-day": "Neliels lietus",
"51-night": "Neliels lietus",
"53-day": "Lietus",
"53-night": "Lietus",
"55-day": "Spēcīgs lietus",
"55-night": "Spēcīgs lietus",
"56-day": "Neliels stindzinošs lietus",
"56-night": "Neliels stindzinošs lietus",
"57-day": "Sasalstošs lietus",
"57-night": "Freezing Drizzle",
"61-day": "Viegls lietus",
"61-night": "Viegls lietus",
"63-day": "Lietus",
"63-night": "Lietus",
"65-day": "Spēcīgs lietus",
"65-night": "Spēcīgs lietus",
"66-day": "Ledains lietus",
"66-night": "Ledains lietus",
"67-day": "Ledains lietus",
"67-night": "Ledains lietus",
"71-day": "Neliels sniegs",
"71-night": "Neliels sniegs",
"73-day": "Sniegs",
"73-night": "Sniegs",
"75-day": "Heavy Snow",
"75-night": "Heavy Snow",
"77-day": "Snow Grains",
"77-night": "Snow Grains",
"80-day": "Light Showers",
"80-night": "Light Showers",
"81-day": "Showers",
"81-night": "Showers",
"82-day": "Heavy Showers",
"82-night": "Heavy Showers",
"85-day": "Snow Showers",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"95-day": "Thunderstorm",
"95-night": "Thunderstorm",
"96-day": "Thunderstorm With Hail",
"96-night": "Thunderstorm With Hail",
"99-day": "Thunderstorm With Hail",
"99-night": "Thunderstorm With Hail"
},
"homebridge": {
"available_update": "System",
"updates": "Updates",
"update_available": "Update Available",
"up_to_date": "Up to Date",
"child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"nextdns": {
"wait": "Please Wait",
"no_devices": "No Device Data Received"
},
"mikrotik": {
"cpuLoad": "CPU Load",
"memoryUsed": "Memory Used",
"uptime": "Uptime",
"numberOfLeases": "Leases"
},
"xteve": {
"streams_all": "All Streams",
"streams_active": "Active Streams",
"streams_xepg": "XEPG Channels"
},
"opnsense": {
"cpu": "CPU Load",
"memory": "Active Memory",
"wanUpload": "WAN Upload",
"wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
}
}

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -3,16 +3,16 @@
"missing_type": "Missing Widget Type: {{type}}", "missing_type": "Missing Widget Type: {{type}}",
"api_error": "API Error", "api_error": "API Error",
"status": "Status", "status": "Status",
"information": "Information", "information": "Informatie",
"url": "URL", "url": "URL",
"raw_error": "Raw Error", "raw_error": "Raw Fout",
"response_data": "Response Data" "response_data": "Reactiegegevens"
}, },
"resources": { "resources": {
"total": "Totaal", "total": "Totaal",
"free": "Vrij", "free": "Vrij",
"used": "Gebruikt", "used": "Gebruikt",
"load": "Load", "load": "Laadt",
"cpu": "CPU" "cpu": "CPU"
}, },
"docker": { "docker": {
@@ -21,8 +21,8 @@
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline", "offline": "Offline",
"error": "Error", "error": "Fout",
"unknown": "Unknown" "unknown": "Onbekend"
}, },
"speedtest": { "speedtest": {
"upload": "Upload", "upload": "Upload",
@@ -190,20 +190,20 @@
"vms": "VMs" "vms": "VMs"
}, },
"unifi": { "unifi": {
"users": "Users", "users": "Gebruikers",
"lan_users": "LAN Users", "lan_users": "LAN Gebruikers",
"uptime": "System Uptime", "uptime": "Uptime van het systeem",
"days": "Days", "days": "Dagen",
"wan": "WAN", "wan": "WAN",
"wlan_users": "WLAN Users", "wlan_users": "WLAN Gebruikers",
"up": "UP", "up": "UP",
"down": "DOWN", "down": "DOWN",
"wait": "Please wait", "wait": "Wachten aub",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "Apparaten",
"lan_devices": "LAN Devices", "lan_devices": "LAN Apparaten",
"wlan_devices": "WLAN Devices" "wlan_devices": "WLAN Apparaten"
}, },
"plex": { "plex": {
"streams": "Active Streams", "streams": "Active Streams",
@@ -216,7 +216,7 @@
"wait": "Please wait" "wait": "Please wait"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Totaal waargenomen",
"diffsDetected": "Diffs Detected" "diffsDetected": "Diffs Detected"
}, },
"wmo": { "wmo": {
@@ -332,7 +332,7 @@
"hd": "HD" "hd": "HD"
}, },
"ping": { "ping": {
"error": "Error", "error": "Fout",
"ping": "Ping" "ping": "Ping"
}, },
"scrutiny": { "scrutiny": {
@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"widget": { "widget": {
"missing_type": "Widget ausente: {{type}}", "missing_type": "Tipo de Widget ausente: {{type}}",
"api_error": "Erro da API", "api_error": "Erro da API",
"status": "Estado", "status": "Estado",
"information": "Informação", "information": "Informação",
@@ -14,8 +14,8 @@
"resources": { "resources": {
"total": "Total", "total": "Total",
"free": "Livre", "free": "Livre",
"used": "Usado", "used": "Utilizado",
"load": "Carregar", "load": "Carga",
"cpu": "CPU" "cpu": "CPU"
}, },
"docker": { "docker": {
@@ -53,7 +53,7 @@
"wanted": "Desejado", "wanted": "Desejado",
"queued": "Fila", "queued": "Fila",
"movies": "Filmes", "movies": "Filmes",
"missing": "Missing" "missing": "Faltando"
}, },
"readarr": { "readarr": {
"wanted": "Desejados", "wanted": "Desejados",
@@ -111,14 +111,14 @@
"weather": { "weather": {
"current": "Localização atual", "current": "Localização atual",
"allow": "Clicar para permitir", "allow": "Clicar para permitir",
"updating": "A atualizar", "updating": "Atualizando",
"wait": "Por favor aguarde" "wait": "Por favor aguarde"
}, },
"overseerr": { "overseerr": {
"pending": "Pendente", "pending": "Pendente",
"approved": "Aprovado", "approved": "Aprovado",
"available": "Disponível", "available": "Disponível",
"processing": "Processing" "processing": "Processando"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Taxa", "rate": "Taxa",
@@ -192,9 +192,9 @@
"transferRate": "Taxa" "transferRate": "Taxa"
}, },
"authentik": { "authentik": {
"loginsLast24H": "Logins (24h)", "loginsLast24H": "Inícios de sessão (24h)",
"failedLoginsLast24H": "Failed Logins (24h)", "failedLoginsLast24H": "Inícios de sessão falhados (24h)",
"users": "Users" "users": "Utilizadores"
}, },
"proxmox": { "proxmox": {
"mem": "MEM", "mem": "MEM",
@@ -204,13 +204,13 @@
}, },
"unifi": { "unifi": {
"users": "Utilizadores", "users": "Utilizadores",
"uptime": "Tempo de Atividade do Sistema", "uptime": "Sistema Ativo",
"days": "Dias", "days": "Dias",
"wan": "WAN", "wan": "WAN",
"lan_users": "Utilizadores LAN", "lan_users": "Utilizadores LAN",
"wlan_users": "Utilizadores WLAN", "wlan_users": "Utilizadores WLAN",
"up": "Ligados", "up": "Ligado",
"down": "Desligados", "down": "Desligado",
"wait": "Por favor, aguarde", "wait": "Por favor, aguarde",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
@@ -241,7 +241,7 @@
"2-night": "Parcialmente nublado", "2-night": "Parcialmente nublado",
"3-day": "Nublado", "3-day": "Nublado",
"3-night": "Nublado", "3-night": "Nublado",
"99-night": "Thunderstorm With Hail", "99-night": "Trovoada com granizo",
"45-day": "Nevoeiro", "45-day": "Nevoeiro",
"45-night": "Nevoeiro", "45-night": "Nevoeiro",
"48-day": "Nevoeiro", "48-day": "Nevoeiro",
@@ -257,160 +257,177 @@
"57-day": "Freezing Drizzle", "57-day": "Freezing Drizzle",
"57-night": "Freezing Drizzle", "57-night": "Freezing Drizzle",
"66-day": "Freezing Rain", "66-day": "Freezing Rain",
"61-day": "Light Rain", "61-day": "Chuva fraca",
"61-night": "Light Rain", "61-night": "Chuva fraca",
"63-day": "Rain", "63-day": "Chuva",
"63-night": "Rain", "63-night": "Chuva",
"65-day": "Heavy Rain", "65-day": "Chuva forte",
"66-night": "Freezing Rain", "66-night": "Freezing Rain",
"65-night": "Heavy Rain", "65-night": "Chuva forte",
"67-day": "Freezing Rain", "67-day": "Freezing Rain",
"67-night": "Freezing Rain", "67-night": "Freezing Rain",
"71-day": "Light Snow", "71-day": "Neve fraca",
"71-night": "Light Snow", "71-night": "Neve fraca",
"73-day": "Snow", "73-day": "Neve",
"73-night": "Snow", "73-night": "Neve",
"75-day": "Heavy Snow", "75-day": "Neve forte",
"75-night": "Heavy Snow", "75-night": "Neve forte",
"77-day": "Snow Grains", "77-day": "Snow Grains",
"77-night": "Snow Grains", "77-night": "Snow Grains",
"80-day": "Light Showers", "80-day": "Neve fraca",
"80-night": "Light Showers", "80-night": "Chuviscos ligeiros",
"81-day": "Showers", "81-day": "Chuviscos",
"81-night": "Showers", "81-night": "Chuviscos",
"82-day": "Heavy Showers", "82-day": "Chuviscos fortes",
"82-night": "Heavy Showers", "82-night": "Chuviscos fortes",
"85-day": "Snow Showers", "85-day": "Snow Showers",
"85-night": "Snow Showers", "85-night": "Snow Showers",
"86-day": "Snow Showers", "86-day": "Snow Showers",
"86-night": "Snow Showers", "86-night": "Snow Showers",
"95-day": "Thunderstorm", "95-day": "Trovoada",
"95-night": "Thunderstorm", "95-night": "Trovoada",
"96-day": "Thunderstorm With Hail", "96-day": "Trovoada com granizo",
"96-night": "Thunderstorm With Hail", "96-night": "Trovoada com granizo",
"99-day": "Thunderstorm With Hail" "99-day": "Trovoada com granizo"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Marcador", "bookmark": "Marcador",
"service": "Serviço" "service": "Serviço"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "Sistema",
"updates": "Updates", "updates": "Atualizações",
"update_available": "Update Available", "update_available": "Atualização disponível",
"up_to_date": "Up to Date", "up_to_date": "Atualizado",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
}, },
"autobrr": { "autobrr": {
"approvedPushes": "Approved", "approvedPushes": "Aprovado",
"rejectedPushes": "Rejected", "rejectedPushes": "Rejeitado",
"filters": "Filters", "filters": "Filtros",
"indexers": "Indexers" "indexers": "Indexadores"
}, },
"watchtower": { "watchtower": {
"containers_scanned": "Scanned", "containers_scanned": "Verificado",
"containers_updated": "Updated", "containers_updated": "Atualizado",
"containers_failed": "Failed" "containers_failed": "Falhou"
}, },
"tubearchivist": { "tubearchivist": {
"downloads": "Queue", "downloads": "Fila",
"videos": "Videos", "videos": "Vídeos",
"channels": "Channels", "channels": "Canais",
"playlists": "Playlists" "playlists": "Listas"
}, },
"truenas": { "truenas": {
"load": "System Load", "load": "Carga do sistema",
"uptime": "Uptime", "uptime": "Ligado",
"alerts": "Alerts", "alerts": "Alertas",
"time": "{{value, number(style: unit; unitDisplay: long;)}}" "time": "{{value, number(style: unit; unitDisplay: long;)}}"
}, },
"navidrome": { "navidrome": {
"nothing_streaming": "No Active Streams", "nothing_streaming": "Sem streams ativos",
"please_wait": "Please Wait" "please_wait": "Por favor aguarde"
}, },
"pyload": { "pyload": {
"queue": "Queue", "queue": "Fila",
"total": "Total", "total": "Total",
"speed": "Speed", "speed": "Velocidade",
"active": "Active" "active": "Ativo"
}, },
"gluetun": { "gluetun": {
"region": "Region", "region": "Região",
"country": "Country", "country": "País",
"public_ip": "Public IP" "public_ip": "IP público"
}, },
"hdhomerun": { "hdhomerun": {
"channels": "Channels", "channels": "Canais",
"hd": "HD" "hd": "HD"
}, },
"ping": { "ping": {
"error": "Erro", "error": "Erro",
"ping": "Ping" "ping": "Tempo de resposta"
}, },
"scrutiny": { "scrutiny": {
"passed": "Passed", "passed": "Aprovado",
"failed": "Failed", "failed": "Falhou",
"unknown": "Unknown" "unknown": "Desconhecido"
}, },
"paperlessngx": { "paperlessngx": {
"inbox": "Inbox", "inbox": "Caixa de entrada",
"total": "Total" "total": "Total"
}, },
"deluge": { "deluge": {
"download": "Download", "download": "Descarregar",
"upload": "Upload", "upload": "Enviar",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Semente"
}, },
"flood": { "flood": {
"download": "Descarregar", "download": "Descarregar",
"upload": "Carregar", "upload": "Carregar",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Semente"
}, },
"tdarr": { "tdarr": {
"queue": "Queue", "queue": "Fila",
"processed": "Processed", "processed": "Processado",
"errored": "Errored", "errored": "Erro",
"saved": "Saved" "saved": "Guardado"
}, },
"miniflux": { "miniflux": {
"read": "Read", "read": "Lido",
"unread": "Unread" "unread": "Não lido"
}, },
"nextdns": { "nextdns": {
"wait": "Please Wait", "wait": "Aguarde",
"no_devices": "No Device Data Received" "no_devices": "Nenhum dado do dispositivo recebido"
}, },
"omada": { "omada": {
"connectedAp": "Connected APs", "connectedAp": "APs Ligados",
"activeUser": "Active devices", "activeUser": "Dispositivos activos",
"alerts": "Alerts", "alerts": "Alertas",
"connectedGateway": "Connected gateways", "connectedGateway": "Gateways ligados",
"connectedSwitches": "Connected switches" "connectedSwitches": "Switches ligados"
}, },
"downloadstation": { "downloadstation": {
"download": "Download", "download": "Descarregar",
"upload": "Upload", "upload": "Enviar",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Semente"
}, },
"mikrotik": { "mikrotik": {
"cpuLoad": "CPU Load", "cpuLoad": "Carga do CPU",
"memoryUsed": "Memory Used", "memoryUsed": "Memória Utilizada",
"uptime": "Uptime", "uptime": "Ativo",
"numberOfLeases": "Leases" "numberOfLeases": "Leases"
}, },
"xteve": { "xteve": {
"streams_all": "All Streams", "streams_all": "Todos os Streams",
"streams_active": "Active Streams", "streams_active": "Streams ativos",
"streams_xepg": "XEPG Channels" "streams_xepg": "Canais XEPG"
}, },
"opnsense": { "opnsense": {
"cpu": "CPU Load", "cpu": "Carga do CPU",
"memory": "Active Memory", "memory": "Memória Ativa",
"wanUpload": "WAN Upload", "wanUpload": "Envio WAN",
"wanDownload": "WAN Download" "wanDownload": "WAN Descarga"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"print_progress": "Progress",
"printer_state": "Printer State",
"print_status": "Print Status",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -23,8 +23,8 @@
"deluge": { "deluge": {
"download": "Завантаження", "download": "Завантаження",
"upload": "Відправлення", "upload": "Відправлення",
"leech": "Leech", "leech": "Ліч",
"seed": "Seed" "seed": "Сід"
}, },
"readarr": { "readarr": {
"wanted": "Розшукується", "wanted": "Розшукується",
@@ -32,76 +32,76 @@
"books": "Книжки" "books": "Книжки"
}, },
"wmo": { "wmo": {
"55-day": "Heavy Drizzle", "55-day": "Сильна мряка",
"55-night": "Heavy Drizzle", "55-night": "Сильна мряка",
"56-day": "Light Freezing Drizzle", "56-day": "Невеликий морозний дощ",
"56-night": "Light Freezing Drizzle", "56-night": "Невеликий морозний дощ",
"0-day": "Sunny", "0-day": "Сонячно",
"0-night": "Clear", "0-night": "Ясно",
"1-day": "Mainly Sunny", "1-day": "Переважно сонячно",
"1-night": "Mainly Clear", "1-night": "Переважно ясно",
"2-day": "Partly Cloudy", "2-day": "Частково хмарно",
"2-night": "Partly Cloudy", "2-night": "Частково хмарно",
"3-day": "Cloudy", "3-day": "Хмарно",
"3-night": "Cloudy", "3-night": "Хмарно",
"53-day": "Drizzle", "53-day": "Мряка",
"45-day": "Foggy", "45-day": "Туманно",
"45-night": "Foggy", "45-night": "Туманно",
"48-day": "Foggy", "48-day": "Туманно",
"48-night": "Foggy", "48-night": "Туманно",
"51-day": "Light Drizzle", "51-day": "Легка мряка",
"51-night": "Light Drizzle", "51-night": "Легка мряка",
"53-night": "Drizzle", "53-night": "Мряка",
"57-day": "Freezing Drizzle", "57-day": "Морозний дощ",
"57-night": "Freezing Drizzle", "57-night": "Морозний дощ",
"61-day": "Light Rain", "61-day": "Невеликий дощ",
"61-night": "Light Rain", "61-night": "Невеликий дощ",
"63-day": "Rain", "63-day": "Дощ",
"63-night": "Rain", "63-night": "Дощ",
"65-day": "Heavy Rain", "65-day": "Сильний дощ",
"65-night": "Heavy Rain", "65-night": "Сильний дощ",
"66-day": "Freezing Rain", "66-day": "Холодний дощ",
"66-night": "Freezing Rain", "66-night": "Холодний дощ",
"67-day": "Freezing Rain", "67-day": "Холодний дощ",
"67-night": "Freezing Rain", "67-night": "Холодний дощ",
"71-day": "Light Snow", "71-day": "Невеликий сніг",
"71-night": "Light Snow", "71-night": "Невеликий сніг",
"73-day": "Snow", "73-day": "Сніг",
"73-night": "Snow", "73-night": "Сніг",
"75-day": "Heavy Snow", "75-day": "Снігопад",
"75-night": "Heavy Snow", "75-night": "Снігопад",
"77-day": "Snow Grains", "77-day": "Снігові зерна",
"77-night": "Snow Grains", "77-night": "Снігові зерна",
"80-day": "Light Showers", "80-day": "Невелика злива",
"80-night": "Light Showers", "80-night": "Невелика злива",
"81-day": "Showers", "81-day": "Злива",
"82-day": "Heavy Showers", "82-day": "Сильна злива",
"82-night": "Heavy Showers", "82-night": "Сильна злива",
"81-night": "Showers", "81-night": "Злива",
"85-day": "Snow Showers", "85-day": "Дощ зі снігом",
"85-night": "Snow Showers", "85-night": "Дощ зі снігом",
"86-day": "Snow Showers", "86-day": "Дощ зі снігом",
"86-night": "Snow Showers", "86-night": "Дощ зі снігом",
"95-day": "Thunderstorm", "95-day": "Гроза",
"95-night": "Thunderstorm", "95-night": "Гроза",
"96-day": "Thunderstorm With Hail", "96-day": "Гроза з градом",
"96-night": "Thunderstorm With Hail", "96-night": "Гроза з градом",
"99-day": "Thunderstorm With Hail", "99-day": "Гроза з градом",
"99-night": "Thunderstorm With Hail" "99-night": "Гроза з градом"
}, },
"pyload": { "pyload": {
"speed": "Speed", "speed": "Швидкість",
"active": "Active", "active": "Активно",
"queue": "Queue", "queue": "Черга",
"total": "Total" "total": "Всього"
}, },
"gluetun": { "gluetun": {
"country": "Country", "country": "Країна",
"public_ip": "Public IP", "public_ip": "Публічний IP",
"region": "Region" "region": "Регіон"
}, },
"hdhomerun": { "hdhomerun": {
"channels": "Channels", "channels": "Канали",
"hd": "HD" "hd": "HD"
}, },
"widget": { "widget": {
@@ -167,8 +167,8 @@
"flood": { "flood": {
"download": "Завантаження", "download": "Завантаження",
"upload": "Відправлення", "upload": "Відправлення",
"leech": "Leech", "leech": "Ліч",
"seed": "Seed" "seed": "Сід"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Всього спостережень", "totalObserved": "Всього спостережень",
@@ -193,20 +193,20 @@
"transmission": { "transmission": {
"download": "Завантаження", "download": "Завантаження",
"upload": "Відправлення", "upload": "Відправлення",
"leech": "Leech", "leech": "Ліч",
"seed": "Seed" "seed": "Сід"
}, },
"qbittorrent": { "qbittorrent": {
"download": "Завантаження", "download": "Завантаження",
"upload": "Відправлення", "upload": "Відправлення",
"leech": "Leech", "leech": "Ліч",
"seed": "Seed" "seed": "Сід"
}, },
"downloadstation": { "downloadstation": {
"download": "Завантаження", "download": "Завантаження",
"upload": "Відправлення", "upload": "Відправлення",
"leech": "Leech", "leech": "Ліч",
"seed": "Seed" "seed": "Сід"
}, },
"sonarr": { "sonarr": {
"wanted": "Розшукується", "wanted": "Розшукується",
@@ -225,13 +225,13 @@
"albums": "Альбоми" "albums": "Альбоми"
}, },
"traefik": { "traefik": {
"middleware": "Middleware", "middleware": "Проміжне програмне забезпечення",
"routers": "Роутери", "routers": "Роутери",
"services": "Сервіси" "services": "Сервіси"
}, },
"navidrome": { "navidrome": {
"nothing_streaming": "No Active Streams", "nothing_streaming": "Немає активних потоків",
"please_wait": "Please Wait" "please_wait": "Будь ласка, зачекайте"
}, },
"bazarr": { "bazarr": {
"missingEpisodes": "Відсутні епізоди", "missingEpisodes": "Відсутні епізоди",
@@ -281,127 +281,144 @@
"saved": "Збережено" "saved": "Збережено"
}, },
"npm": { "npm": {
"enabled": "Enabled", "enabled": "Увімкнено",
"disabled": "Disabled", "disabled": "Вимкнено",
"total": "Total" "total": "Всього"
}, },
"coinmarketcap": { "coinmarketcap": {
"configure": "Configure one or more crypto currencies to track", "configure": "Налаштуйте одну або кілька криптовалют для відстеження",
"1hour": "1 Hour", "1hour": "1 година",
"1day": "1 Day", "1day": "1 день",
"7days": "7 Days", "7days": "7 днів",
"30days": "30 Days" "30days": "30 днів"
}, },
"mastodon": { "mastodon": {
"domain_count": "Domains", "domain_count": "Домени",
"user_count": "Users", "user_count": "Користувачі",
"status_count": "Posts" "status_count": "Пости"
}, },
"miniflux": { "miniflux": {
"read": "Read", "read": "Прочитано",
"unread": "Unread" "unread": "Не прочитано"
}, },
"gotify": { "gotify": {
"apps": "Applications", "apps": "Застосунки",
"clients": "Clients", "clients": "Клієнти",
"messages": "Messages" "messages": "Повідомлення"
}, },
"prowlarr": { "prowlarr": {
"enableIndexers": "Indexers", "enableIndexers": "Індексатори",
"numberOfGrabs": "Grabs", "numberOfGrabs": "Захоплення",
"numberOfQueries": "Queries", "numberOfQueries": "Запити",
"numberOfFailGrabs": "Fail Grabs", "numberOfFailGrabs": "Невдалі захоплення",
"numberOfFailQueries": "Fail Queries" "numberOfFailQueries": "Невдалі запити"
}, },
"jackett": { "jackett": {
"configured": "Configured", "configured": "Налаштовано",
"errored": "Errored" "errored": "Помилка"
}, },
"strelaysrv": { "strelaysrv": {
"numActiveSessions": "Sessions", "numActiveSessions": "Сесії",
"numConnections": "Connections", "numConnections": "Підключення",
"dataRelayed": "Relayed", "dataRelayed": "Ретрансльовано",
"transferRate": "Rate" "transferRate": "Швидкість"
}, },
"authentik": { "authentik": {
"users": "Users", "users": "Користувачі",
"loginsLast24H": "Logins (24h)", "loginsLast24H": "Вхід (24 години)",
"failedLoginsLast24H": "Failed Logins (24h)" "failedLoginsLast24H": "Невдалі входи (24 години)"
}, },
"proxmox": { "proxmox": {
"mem": "MEM", "mem": "Пам'ять",
"cpu": "CPU", "cpu": "CPU",
"vms": "VMs", "vms": "Віртуальні машини",
"lxc": "LXC" "lxc": "Контейнери Linux"
}, },
"glances": { "glances": {
"cpu": "CPU", "cpu": "CPU",
"mem": "MEM", "mem": "Пам'ять",
"wait": "Please wait" "wait": "Будь ласка, зачекайте"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "Закладка",
"service": "Service" "service": "Сервіс"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "Система",
"updates": "Updates", "updates": "Оновлення",
"child_bridges_status": "{{ok}}/{{total}}", "child_bridges_status": "{{ok}}/{{total}}",
"update_available": "Update Available", "update_available": "Доступне оновлення",
"up_to_date": "Up to Date", "up_to_date": "Актуально",
"child_bridges": "Child Bridges" "child_bridges": "Дитячі мости"
}, },
"watchtower": { "watchtower": {
"containers_scanned": "Scanned", "containers_scanned": "Відскановано",
"containers_updated": "Updated", "containers_updated": "Оновлено",
"containers_failed": "Failed" "containers_failed": "Невдача"
}, },
"autobrr": { "autobrr": {
"approvedPushes": "Approved", "approvedPushes": "Схвалено",
"rejectedPushes": "Rejected", "rejectedPushes": "Відхилено",
"filters": "Filters", "filters": "Фільтри",
"indexers": "Indexers" "indexers": "Індексатори"
}, },
"tubearchivist": { "tubearchivist": {
"downloads": "Queue", "downloads": "Черга",
"videos": "Videos", "videos": "Відео",
"channels": "Channels", "channels": "Канали",
"playlists": "Playlists" "playlists": "Плейлисти"
}, },
"truenas": { "truenas": {
"load": "System Load", "load": "Завантаження системи",
"uptime": "Uptime", "uptime": "Час роботи",
"alerts": "Alerts", "alerts": "Сповіщення",
"time": "{{value, number(style: unit; unitDisplay: long;)}}" "time": "{{value, number(style: unit; unitDisplay: long;)}}"
}, },
"scrutiny": { "scrutiny": {
"passed": "Passed", "passed": "Пройшов",
"failed": "Failed", "failed": "Невдача",
"unknown": "Unknown" "unknown": "Невідомо"
}, },
"paperlessngx": { "paperlessngx": {
"inbox": "Inbox", "inbox": "Вхідні",
"total": "Total" "total": "Всього"
}, },
"nextdns": { "nextdns": {
"wait": "Please Wait", "wait": "Будь ласка, зачекайте",
"no_devices": "No Device Data Received" "no_devices": "Дані про пристрій не отримано"
}, },
"mikrotik": { "mikrotik": {
"cpuLoad": "CPU Load", "cpuLoad": "Завантаження CPU",
"memoryUsed": "Memory Used", "memoryUsed": "Використана пам'ять",
"uptime": "Uptime", "uptime": "Час роботи",
"numberOfLeases": "Leases" "numberOfLeases": "Оренди"
}, },
"xteve": { "xteve": {
"streams_all": "All Streams", "streams_all": "Всі потоки",
"streams_active": "Active Streams", "streams_active": "Активні потоки",
"streams_xepg": "XEPG Channels" "streams_xepg": "Канали XEPG"
}, },
"opnsense": { "opnsense": {
"cpu": "CPU Load", "cpu": "Завантаження CPU",
"memory": "Active Memory", "memory": "Активна пам'ять",
"wanUpload": "WAN Upload", "wanUpload": "Вивантаження WAN",
"wanDownload": "WAN Download" "wanDownload": "Завантаження WAN"
},
"moonraker": {
"printer_state": "Стан принтера",
"print_status": "Статус друку",
"print_progress": "Прогрес",
"layers": "Шари"
},
"medusa": {
"wanted": "Розшукується",
"queued": "У черзі",
"series": "Серії"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"print_progress": "Progress",
"layers": "Layers",
"printer_state": "Printer State",
"print_status": "Print Status"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -403,5 +403,22 @@
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN Upload",
"wanDownload": "WAN Download" "wanDownload": "WAN Download"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -1,407 +1,424 @@
{ {
"widget": { "widget": {
"missing_type": "Missing Widget Type: {{type}}", "missing_type": "遺失小工具的類型: {{type}}",
"api_error": "API Error", "api_error": "API錯誤",
"status": "Status", "status": "狀態",
"information": "Information", "information": "資訊",
"url": "URL", "url": "URL",
"raw_error": "Raw Error", "raw_error": "Raw Error",
"response_data": "Response Data" "response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Current Location", "current": "目前位置",
"allow": "Click to allow", "allow": "點擊以允許",
"updating": "Updating", "updating": "更新中",
"wait": "Please wait" "wait": "請稍後"
}, },
"docker": { "docker": {
"rx": "RX", "rx": "接收",
"offline": "Offline", "offline": "離線",
"tx": "TX", "tx": "發送",
"mem": "MEM", "mem": "記憶體",
"cpu": "CPU", "cpu": "處理器",
"error": "Error", "error": "錯誤",
"unknown": "Unknown" "unknown": "未知的"
}, },
"emby": { "emby": {
"playing": "Playing", "playing": "正在播放",
"transcoding": "Transcoding", "transcoding": "轉碼",
"bitrate": "Bitrate", "bitrate": "位元率",
"no_active": "No Active Streams" "no_active": "無播放活動"
}, },
"tautulli": { "tautulli": {
"playing": "Playing", "playing": "正在播放",
"transcoding": "Transcoding", "transcoding": "轉碼",
"bitrate": "Bitrate", "bitrate": "位元率",
"no_active": "No Active Streams" "no_active": "無播放活動"
}, },
"jellyseerr": { "jellyseerr": {
"pending": "Pending", "pending": "待定",
"approved": "Approved", "approved": "已接受",
"available": "Available" "available": "可用的"
}, },
"search": { "search": {
"placeholder": "Search…" "placeholder": "搜尋…"
}, },
"resources": { "resources": {
"total": "Total", "total": "全部",
"free": "Free", "free": "剩餘",
"used": "Used", "used": "已使用",
"load": "Load", "load": "負載",
"cpu": "CPU" "cpu": "CPU"
}, },
"nzbget": { "nzbget": {
"rate": "Rate", "rate": "速率",
"remaining": "Remaining", "remaining": "剩餘",
"downloaded": "Downloaded" "downloaded": "已下載"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Rate", "rate": "速率",
"queue": "Queue", "queue": "佇列",
"timeleft": "Time Left" "timeleft": "剩餘時間"
}, },
"rutorrent": { "rutorrent": {
"active": "Active", "active": "Active",
"upload": "Upload", "upload": "上傳",
"download": "Download" "download": "下載"
}, },
"radarr": { "radarr": {
"movies": "Movies", "movies": "電影",
"wanted": "Wanted", "wanted": "關注中",
"queued": "Queued", "queued": "已加入佇列",
"missing": "Missing" "missing": "遺失"
}, },
"sonarr": { "sonarr": {
"wanted": "Wanted", "wanted": "關注中",
"queued": "Queued", "queued": "已加入佇列",
"series": "Series" "series": "系列"
}, },
"readarr": { "readarr": {
"wanted": "Wanted", "wanted": "關注中",
"queued": "Queued", "queued": "已加入佇列",
"books": "Books" "books": "書籍"
}, },
"ombi": { "ombi": {
"pending": "Pending", "pending": "待定",
"approved": "Approved", "approved": "已接受",
"available": "Available" "available": "可用的"
}, },
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "待定",
"approved": "Approved", "approved": "已接受",
"available": "Available", "available": "可用的",
"processing": "Processing" "processing": "處理中"
}, },
"pihole": { "pihole": {
"queries": "Queries", "queries": "查詢數",
"blocked": "Blocked", "blocked": "已阻擋",
"gravity": "Gravity" "gravity": "Gravity"
}, },
"speedtest": { "speedtest": {
"upload": "Upload", "upload": "上行",
"download": "Download", "download": "下行",
"ping": "Ping" "ping": "Ping"
}, },
"portainer": { "portainer": {
"running": "Running", "running": "運行中",
"stopped": "Stopped", "stopped": "未運行",
"total": "Total" "total": "全部"
}, },
"traefik": { "traefik": {
"routers": "Routers", "routers": "路由器",
"services": "Services", "services": "服務",
"middleware": "Middleware" "middleware": "中介軟體"
}, },
"gotify": { "gotify": {
"clients": "Clients", "clients": "客戶端",
"apps": "Applications", "apps": "應用程式",
"messages": "Messages" "messages": "訊息"
}, },
"npm": { "npm": {
"enabled": "Enabled", "enabled": "已啟用",
"disabled": "Disabled", "disabled": "已停用",
"total": "Total" "total": "全部"
}, },
"coinmarketcap": { "coinmarketcap": {
"configure": "Configure one or more crypto currencies to track", "configure": "請設定一個或多個欲追蹤的加密貨幣",
"1hour": "1 Hour", "1hour": "1小時",
"1day": "1 Day", "1day": "1",
"7days": "7 Days", "7days": "7",
"30days": "30 Days" "30days": "30"
}, },
"prowlarr": { "prowlarr": {
"enableIndexers": "Indexers", "enableIndexers": "索引器",
"numberOfGrabs": "Grabs", "numberOfGrabs": "抓取",
"numberOfQueries": "Queries", "numberOfQueries": "查詢數",
"numberOfFailGrabs": "Fail Grabs", "numberOfFailGrabs": "抓取失敗",
"numberOfFailQueries": "Fail Queries" "numberOfFailQueries": "查詢失敗"
}, },
"transmission": { "transmission": {
"download": "Download", "download": "下載",
"upload": "Upload", "upload": "上傳",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Seed"
}, },
"jackett": { "jackett": {
"configured": "Configured", "configured": "已配置",
"errored": "Errored" "errored": "發生錯誤"
}, },
"bazarr": { "bazarr": {
"missingEpisodes": "Missing Episodes", "missingEpisodes": "缺失的劇集",
"missingMovies": "Missing Movies" "missingMovies": "缺失的電影"
}, },
"lidarr": { "lidarr": {
"wanted": "Wanted", "wanted": "關注中",
"queued": "Queued", "queued": "已加入佇列",
"albums": "Albums" "albums": "專輯"
}, },
"adguard": { "adguard": {
"queries": "Queries", "queries": "查詢數",
"blocked": "Blocked", "blocked": "已阻擋",
"filtered": "Filtered", "filtered": "已過濾",
"latency": "Latency" "latency": "延遲"
}, },
"qbittorrent": { "qbittorrent": {
"download": "Download", "download": "下載",
"upload": "Upload", "upload": "上傳",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Seed"
}, },
"mastodon": { "mastodon": {
"user_count": "Users", "user_count": "使用者",
"status_count": "Posts", "status_count": "文章",
"domain_count": "Domains" "domain_count": "網域"
}, },
"strelaysrv": { "strelaysrv": {
"numActiveSessions": "Sessions", "numActiveSessions": "工作階段",
"numConnections": "Connections", "numConnections": "連線",
"dataRelayed": "Relayed", "dataRelayed": "中繼",
"transferRate": "Rate" "transferRate": "速率"
}, },
"authentik": { "authentik": {
"users": "Users", "users": "使用者",
"loginsLast24H": "Logins (24h)", "loginsLast24H": "登錄(24h)",
"failedLoginsLast24H": "Failed Logins (24h)" "failedLoginsLast24H": "登錄失敗(24h)"
}, },
"proxmox": { "proxmox": {
"mem": "MEM", "mem": "記憶體",
"cpu": "CPU", "cpu": "CPU",
"lxc": "LXC", "lxc": "LXC",
"vms": "VMs" "vms": "VMs"
}, },
"unifi": { "unifi": {
"users": "Users", "users": "使用者",
"uptime": "System Uptime", "uptime": "系統運行時間",
"days": "Days", "days": "",
"wan": "WAN", "wan": "WAN",
"lan_users": "LAN Users", "lan_users": "LAN使用者",
"wlan_users": "WLAN Users", "wlan_users": "WLAN使用者",
"up": "UP", "up": "UP",
"down": "DOWN", "down": "DOWN",
"wait": "Please wait", "wait": "請稍後",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "設備",
"lan_devices": "LAN Devices", "lan_devices": "LAN設備",
"wlan_devices": "WLAN Devices" "wlan_devices": "WLAN設備"
}, },
"plex": { "plex": {
"streams": "Active Streams", "streams": "正在播放",
"movies": "Movies", "movies": "電影",
"tv": "TV Shows" "tv": "影集"
}, },
"glances": { "glances": {
"cpu": "CPU", "cpu": "CPU",
"mem": "MEM", "mem": "記憶體",
"wait": "Please wait" "wait": "請稍後"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Total Observed",
"diffsDetected": "Diffs Detected" "diffsDetected": "Diffs Detected"
}, },
"wmo": { "wmo": {
"0-day": "Sunny", "0-day": "",
"0-night": "Clear", "0-night": "晴朗",
"71-day": "Light Snow", "71-day": "小雪",
"71-night": "Light Snow", "71-night": "小雪",
"1-day": "Mainly Sunny", "1-day": "晴時多雲",
"1-night": "Mainly Clear", "1-night": "晴時多雲",
"2-day": "Partly Cloudy", "2-day": "多雲時陰",
"2-night": "Partly Cloudy", "2-night": "多雲時陰",
"3-day": "Cloudy", "3-day": "陰天",
"3-night": "Cloudy", "3-night": "陰天",
"45-day": "Foggy", "45-day": "有霧",
"45-night": "Foggy", "45-night": "有霧",
"48-day": "Foggy", "48-day": "有霧",
"48-night": "Foggy", "48-night": "有霧",
"51-day": "Light Drizzle", "51-day": "小毛雨",
"51-night": "Light Drizzle", "51-night": "小毛雨",
"53-day": "Drizzle", "53-day": "毛雨",
"53-night": "Drizzle", "53-night": "毛雨",
"55-day": "Heavy Drizzle", "55-day": "大毛雨",
"55-night": "Heavy Drizzle", "55-night": "大毛雨",
"56-day": "Light Freezing Drizzle", "56-day": "小凍毛雨",
"56-night": "Light Freezing Drizzle", "56-night": "小凍毛雨",
"57-day": "Freezing Drizzle", "57-day": "凍毛雨",
"57-night": "Freezing Drizzle", "57-night": "凍毛雨",
"61-day": "Light Rain", "61-day": "小雨",
"61-night": "Light Rain", "61-night": "小雨",
"63-day": "Rain", "63-day": "",
"63-night": "Rain", "63-night": "",
"65-day": "Heavy Rain", "65-day": "大雨",
"65-night": "Heavy Rain", "65-night": "大雨",
"66-day": "Freezing Rain", "66-day": "凍雨",
"66-night": "Freezing Rain", "66-night": "凍雨",
"67-day": "Freezing Rain", "67-day": "凍雨",
"67-night": "Freezing Rain", "67-night": "凍雨",
"73-day": "Snow", "73-day": "",
"73-night": "Snow", "73-night": "",
"75-day": "Heavy Snow", "75-day": "大雪",
"75-night": "Heavy Snow", "75-night": "大雪",
"77-day": "Snow Grains", "77-day": "雪粒",
"77-night": "Snow Grains", "77-night": "雪粒",
"80-day": "Light Showers", "80-day": "微陣雨",
"80-night": "Light Showers", "80-night": "微陣雨",
"81-day": "Showers", "81-day": "陣雨",
"81-night": "Showers", "81-night": "陣雨",
"82-day": "Heavy Showers", "82-day": "強陣雨",
"82-night": "Heavy Showers", "82-night": "強陣雨",
"85-day": "Snow Showers", "85-day": "陣雪",
"85-night": "Snow Showers", "85-night": "陣雪",
"86-day": "Snow Showers", "86-day": "陣雪",
"86-night": "Snow Showers", "86-night": "陣雪",
"95-day": "Thunderstorm", "95-day": "雷雨",
"95-night": "Thunderstorm", "95-night": "雷雨",
"96-day": "Thunderstorm With Hail", "96-day": "雷雨伴隨冰雹",
"96-night": "Thunderstorm With Hail", "96-night": "雷雨伴隨冰雹",
"99-day": "Thunderstorm With Hail", "99-day": "雷雨伴隨冰雹",
"99-night": "Thunderstorm With Hail" "99-night": "雷雨伴隨冰雹"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "書籤",
"service": "Service" "service": "服務"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "系統",
"updates": "Updates", "updates": "更新",
"update_available": "Update Available", "update_available": "有可用的更新",
"up_to_date": "Up to Date", "up_to_date": "已更新至最新",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
}, },
"autobrr": { "autobrr": {
"approvedPushes": "Approved", "approvedPushes": "接受",
"rejectedPushes": "Rejected", "rejectedPushes": "拒絕",
"filters": "Filters", "filters": "篩選器",
"indexers": "Indexers" "indexers": "索引器"
}, },
"watchtower": { "watchtower": {
"containers_scanned": "Scanned", "containers_scanned": "已掃描",
"containers_updated": "Updated", "containers_updated": "已更新",
"containers_failed": "Failed" "containers_failed": "失敗"
}, },
"tubearchivist": { "tubearchivist": {
"downloads": "Queue", "downloads": "佇列",
"videos": "Videos", "videos": "影片",
"channels": "Channels", "channels": "頻道",
"playlists": "Playlists" "playlists": "播放清單"
}, },
"truenas": { "truenas": {
"load": "System Load", "load": "系統負載",
"uptime": "Uptime", "uptime": "運行時間",
"alerts": "Alerts", "alerts": "警示",
"time": "{{value, number(style: unit; unitDisplay: long;)}}" "time": "{{value, number(style: unit; unitDisplay: long;)}}"
}, },
"navidrome": { "navidrome": {
"nothing_streaming": "No Active Streams", "nothing_streaming": "無播放活動",
"please_wait": "Please Wait" "please_wait": "請稍後"
}, },
"pyload": { "pyload": {
"speed": "Speed", "speed": "速度",
"active": "Active", "active": "運行中",
"queue": "Queue", "queue": "佇列",
"total": "Total" "total": "全部"
}, },
"gluetun": { "gluetun": {
"public_ip": "Public IP", "public_ip": "公用IP",
"region": "Region", "region": "地區",
"country": "Country" "country": "國家"
}, },
"hdhomerun": { "hdhomerun": {
"channels": "Channels", "channels": "頻道",
"hd": "HD" "hd": "高畫質"
}, },
"ping": { "ping": {
"error": "Error", "error": "錯誤",
"ping": "Ping" "ping": "Ping"
}, },
"scrutiny": { "scrutiny": {
"passed": "Passed", "passed": "通過",
"failed": "Failed", "failed": "失敗",
"unknown": "Unknown" "unknown": "未知的"
}, },
"paperlessngx": { "paperlessngx": {
"inbox": "Inbox", "inbox": "收件箱",
"total": "Total" "total": "全部"
}, },
"deluge": { "deluge": {
"download": "Download", "download": "下載",
"upload": "Upload", "upload": "上傳",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Seed"
}, },
"flood": { "flood": {
"download": "Download", "download": "下載",
"upload": "Upload", "upload": "上傳",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Seed"
}, },
"tdarr": { "tdarr": {
"queue": "Queue", "queue": "佇列",
"processed": "Processed", "processed": "已處理",
"errored": "Errored", "errored": "發生錯誤",
"saved": "Saved" "saved": "已儲存"
}, },
"miniflux": { "miniflux": {
"read": "Read", "read": "已讀",
"unread": "Unread" "unread": "未讀"
}, },
"nextdns": { "nextdns": {
"wait": "Please Wait", "wait": "請稍後",
"no_devices": "No Device Data Received" "no_devices": "未收到裝置資料"
}, },
"common": { "common": {
"bibyterate": "{{value, rate(bits: false; binary: true)}}", "bibyterate": "{{value, rate(bits: false; binary: true)}}",
"bibitrate": "{{value, rate(bits: true; binary: true)}}" "bibitrate": "{{value, rate(bits: true; binary: true)}}"
}, },
"omada": { "omada": {
"connectedAp": "Connected APs", "connectedAp": "已連接的存取點",
"activeUser": "Active devices", "activeUser": "在線裝置",
"alerts": "Alerts", "alerts": "警示",
"connectedGateway": "Connected gateways", "connectedGateway": "已連接的閘道",
"connectedSwitches": "Connected switches" "connectedSwitches": "已連接的交換器"
}, },
"downloadstation": { "downloadstation": {
"download": "Download", "download": "下載",
"upload": "Upload", "upload": "上傳",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Seed"
}, },
"mikrotik": { "mikrotik": {
"cpuLoad": "CPU Load", "cpuLoad": "CPU負載",
"memoryUsed": "Memory Used", "memoryUsed": "已使用的記憶體",
"uptime": "Uptime", "uptime": "運行時間",
"numberOfLeases": "Leases" "numberOfLeases": "租約"
}, },
"xteve": { "xteve": {
"streams_all": "All Streams", "streams_all": "所有播放活動",
"streams_active": "Active Streams", "streams_active": "正在播放",
"streams_xepg": "XEPG Channels" "streams_xepg": "XEPG頻道"
}, },
"opnsense": { "opnsense": {
"cpu": "CPU Load", "cpu": "CPU負載",
"memory": "Active Memory", "memory": "Active Memory",
"wanUpload": "WAN Upload", "wanUpload": "WAN上傳",
"wanDownload": "WAN Download" "wanDownload": "WAN下載"
},
"moonraker": {
"printer_state": "Printer State",
"print_status": "Print Status",
"print_progress": "Progress",
"layers": "Layers"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"octoPrint": {
"printer_state": "Status",
"temp_tool": "Tool temp",
"temp_bed": "Bed temp",
"job_completion": "Completion"
} }
} }

View File

@@ -19,7 +19,7 @@ export default function Item({ bookmark }) {
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md"> <div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
{bookmark.icon && {bookmark.icon &&
<div className="flex-shrink-0 w-5 h-5"> <div className="flex-shrink-0 w-5 h-5">
<ResolvedIcon icon={bookmark.icon} /> <ResolvedIcon icon={bookmark.icon} alt={bookmark.abbr} />
</div> </div>
} }
{!bookmark.icon && bookmark.abbr} {!bookmark.icon && bookmark.abbr}

View File

@@ -1,9 +1,9 @@
import Image from "next/future/image"; import Image from "next/future/image";
export default function ResolvedIcon({ icon, width = 32, height = 32 }) { export default function ResolvedIcon({ icon, width = 32, height = 32, alt = "logo" }) {
// direct or relative URLs // direct or relative URLs
if (icon.startsWith("http") || icon.startsWith("/")) { if (icon.startsWith("http") || icon.startsWith("/")) {
return <Image src={`${icon}`} width={width} height={height} alt="logo" />; return <Image src={`${icon}`} width={width} height={height} alt={alt} />;
} }
// mdi- prefixed, material design icons // mdi- prefixed, material design icons
@@ -31,7 +31,7 @@ export default function ResolvedIcon({ icon, width = 32, height = 32 }) {
src={`https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${iconName}.png`} src={`https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${iconName}.png`}
width={width} width={width}
height={height} height={height}
alt="logo" alt={alt}
/> />
); );
} }

View File

@@ -4,8 +4,10 @@ import { useContext, useState } from "react";
import Status from "./status"; import Status from "./status";
import Widget from "./widget"; import Widget from "./widget";
import Ping from "./ping"; import Ping from "./ping";
import KubernetesStatus from "./kubernetes-status";
import Docker from "widgets/docker/component"; import Docker from "widgets/docker/component";
import Kubernetes from "widgets/kubernetes/component";
import { SettingsContext } from "utils/contexts/settings"; import { SettingsContext } from "utils/contexts/settings";
import ResolvedIcon from "components/resolvedicon"; import ResolvedIcon from "components/resolvedicon";
@@ -89,6 +91,16 @@ export default function Item({ service }) {
<span className="sr-only">View container stats</span> <span className="sr-only">View container stats</span>
</button> </button>
)} )}
{service.app && (
<button
type="button"
onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))}
className="flex-shrink-0 flex items-center justify-center cursor-pointer"
>
<KubernetesStatus service={service} />
<span className="sr-only">View container stats</span>
</button>
)}
</div> </div>
</div> </div>
@@ -102,6 +114,16 @@ export default function Item({ service }) {
{statsOpen && <Docker service={{ widget: { container: service.container, server: service.server } }} />} {statsOpen && <Docker service={{ widget: { container: service.container, server: service.server } }} />}
</div> </div>
)} )}
{service.app && (
<div
className={classNames(
statsOpen && !statsClosing ? "max-h-[55px] opacity-100" : " max-h-[0] opacity-0",
"w-full overflow-hidden transition-all duration-300 ease-in-out"
)}
>
{statsOpen && <Kubernetes service={{ widget: { namespace: service.namespace, app: service.app, podSelector: service.podSelector } }} />}
</div>
)}
{service.widget && <Widget service={service} />} {service.widget && <Widget service={service} />}
</div> </div>

View File

@@ -0,0 +1,35 @@
import useSWR from "swr";
import { t } from "i18next";
export default function KubernetesStatus({ service }) {
const podSelectorString = service.podSelector !== undefined ? `podSelector=${service.podSelector}` : "";
const { data, error } = useSWR(`/api/kubernetes/status/${service.namespace}/${service.app}?${podSelectorString}`);
if (error) {
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}>
<div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div>
</div>
}
if (data && data.status === "running") {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health ?? data.status}>
<div className="text-[8px] font-bold text-emerald-500/80 uppercase">{data.health ?? data.status}</div>
</div>
);
}
if (data && (data.status === "not found" || data.status === "down" || data.status === "partial")) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.status}</div>
</div>
);
}
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div>
</div>
);
}

View File

@@ -3,8 +3,6 @@ import useSWR from "swr";
import { compareVersions } from "compare-versions"; import { compareVersions } from "compare-versions";
import { MdNewReleases } from "react-icons/md"; import { MdNewReleases } from "react-icons/md";
import cachedFetch from "utils/proxy/cached-fetch";
export default function Version() { export default function Version() {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
@@ -12,9 +10,7 @@ export default function Version() {
const revision = process.env.NEXT_PUBLIC_REVISION?.length ? process.env.NEXT_PUBLIC_REVISION : "dev"; const revision = process.env.NEXT_PUBLIC_REVISION?.length ? process.env.NEXT_PUBLIC_REVISION : "dev";
const version = process.env.NEXT_PUBLIC_VERSION?.length ? process.env.NEXT_PUBLIC_VERSION : "dev"; const version = process.env.NEXT_PUBLIC_VERSION?.length ? process.env.NEXT_PUBLIC_VERSION : "dev";
const cachedFetcher = (resource) => cachedFetch(resource, 5).then((res) => res.json()); const { data: releaseData } = useSWR("/api/releases");
const { data: releaseData } = useSWR("https://api.github.com/repos/benphelps/homepage/releases", cachedFetcher);
// use Intl.DateTimeFormat to format the date // use Intl.DateTimeFormat to format the date
const formatDate = (date) => { const formatDate = (date) => {
@@ -48,7 +44,7 @@ export default function Version() {
</span> </span>
{version === "main" || version === "dev" || version === "nightly" {version === "main" || version === "dev" || version === "nightly"
? null ? null
: releaseData && : releaseData && latestRelease &&
compareVersions(latestRelease.tag_name, version) > 0 && ( compareVersions(latestRelease.tag_name, version) > 0 && (
<a <a
href={latestRelease.html_url} href={latestRelease.html_url}

View File

@@ -13,22 +13,23 @@ const textSizes = {
}; };
export default function DateTime({ options }) { export default function DateTime({ options }) {
const { text_size: textSize, format } = options; const { text_size: textSize, locale, format } = options;
const { i18n } = useTranslation(); const { i18n } = useTranslation();
const [date, setDate] = useState(""); const [date, setDate] = useState("");
const dateLocale = locale ?? i18n.language;
useEffect(() => { useEffect(() => {
const dateFormat = new Intl.DateTimeFormat(i18n.language, { ...format }); const dateFormat = new Intl.DateTimeFormat(dateLocale, { ...format });
const interval = setInterval(() => { const interval = setInterval(() => {
setDate(dateFormat.format(new Date())); setDate(dateFormat.format(new Date()));
}, 1000); }, 1000);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [date, setDate, i18n.language, format]); }, [date, setDate, dateLocale, format]);
return ( return (
<div className="flex flex-col justify-center first:ml-0 ml-4"> <div className="flex flex-col justify-center first:ml-0 ml-4">
<div className="flex flex-row items-center grow justify-end"> <div className="flex flex-row items-center grow justify-end">
<span className={`text-theme-800 dark:text-theme-200 ${textSizes[textSize || "lg"]}`}> <span className={`text-theme-800 dark:text-theme-200 tabular-nums ${textSizes[textSize || "lg"]}`}>
{date} {date}
</span> </span>
</div> </div>

View File

@@ -0,0 +1,74 @@
import useSWR from "swr";
import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
import Node from "./node";
export default function Widget({ options }) {
const { cluster, nodes } = options;
const { t, i18n } = useTranslation();
const defaultData = {
cpu: {
load: 0,
total: 0,
percent: 0
},
memory: {
used: 0,
total: 0,
free: 0,
precent: 0
}
};
const { data, error } = useSWR(
`/api/widgets/kubernetes?${new URLSearchParams({ lang: i18n.language }).toString()}`, {
refreshInterval: 1500
}
);
if (error || data?.error) {
return (
<div className="flex flex-col justify-center first:ml-0 ml-4">
<div className="flex flex-row items-center justify-end">
<div className="flex flex-row items-center">
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
</div>
</div>
</div>
</div>
);
}
if (!data) {
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className="flex flex-row self-center flex-wrap justify-between">
{cluster.show &&
<Node type="cluster" key="cluster" options={options.cluster} data={defaultData} />
}
{nodes.show &&
<Node type="node" key="nodes" options={options.nodes} data={defaultData} />
}
</div>
</div>
);
}
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className="flex flex-row self-center flex-wrap justify-between">
{cluster.show &&
<Node key="cluster" type="cluster" options={options.cluster} data={data.cluster} />
}
{nodes.show && data.nodes &&
data.nodes.map((node) =>
<Node key={node.name} type="node" options={options.nodes} data={node} />)
}
</div>
</div>
);
}

View File

@@ -0,0 +1,60 @@
import { FaMemory } from "react-icons/fa";
import { FiAlertTriangle, FiCpu, FiServer } from "react-icons/fi";
import { SiKubernetes } from "react-icons/si";
import { useTranslation } from "next-i18next";
import UsageBar from "./usage-bar";
export default function Node({ type, options, data }) {
const { t } = useTranslation();
function icon() {
if (type === "cluster") {
return <SiKubernetes className="text-theme-800 dark:text-theme-200 w-5 h-5" />;
}
if (data.ready) {
return <FiServer className="text-theme-800 dark:text-theme-200 w-5 h-5" />;
}
return <FiAlertTriangle className="text-theme-800 dark:text-theme-200 w-5 h-5" />;
}
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap ml-4">
<div className="flex flex-row self-center flex-wrap justify-between">
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
{icon()}
<div className="flex flex-col ml-3 text-left min-w-[85px]">
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5">
{t("common.number", {
value: data.cpu.percent,
style: "unit",
unit: "percent",
maximumFractionDigits: 0
})}
</div>
<FiCpu className="text-theme-800 dark:text-theme-200 w-3 h-3" />
</div>
<UsageBar percent={data.cpu.percent} />
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5">
{t("common.bytes", {
value: data.memory.free,
maximumFractionDigits: 0,
binary: true
})}
</div>
<FaMemory className="text-theme-800 dark:text-theme-200 w-3 h-3" />
</div>
<UsageBar percent={data.memory.percent} />
{options.showLabel && (
<div className="pt-1 text-center text-theme-800 dark:text-theme-200 text-xs">{type === "cluster" ? options.label : data.name}</div>
)}
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,12 @@
export default function UsageBar({ percent }) {
return (
<div className="mt-0.5 w-full bg-theme-800/30 rounded-full h-1 dark:bg-theme-200/20">
<div
className="bg-theme-800/70 h-1 rounded-full dark:bg-theme-200/50 transition-all duration-1000"
style={{
width: `${percent}%`,
}}
/>
</div>
);
}

View File

@@ -0,0 +1,57 @@
import useSWR from "swr";
import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
import Node from "./node";
export default function Longhorn({ options }) {
const { expanded, total, labels, include, nodes } = options;
const { t } = useTranslation();
const { data, error } = useSWR(`/api/widgets/longhorn`, {
refreshInterval: 1500
});
if (error || data?.error) {
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<BiError className="text-theme-800 dark:text-theme-200 w-5 h-5" />
<div className="flex flex-col ml-3 text-left">
<span className="text-theme-800 dark:text-theme-200 text-xs">{t("widget.api_error")}</span>
</div>
</div>
);
}
if (!data) {
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className="flex flex-row self-center flex-wrap justify-between" />
</div>
);
}
return (
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
<div className="flex flex-row self-center flex-wrap justify-between">
{data.nodes
.filter((node) => {
if (node.id === 'total' && total) {
return true;
}
if (!nodes) {
return false;
}
if (include && !include.includes(node.id)) {
return false;
}
return true;
})
.map((node) =>
<div key={node.id}>
<Node data={{ node }} expanded={expanded} labels={labels} />
</div>
)}
</div>
</div>
);
}

View File

@@ -0,0 +1,32 @@
import { FiHardDrive } from "react-icons/fi";
import { useTranslation } from "next-i18next";
import UsageBar from "../resources/usage-bar";
export default function Node({ data, expanded, labels }) {
const { t } = useTranslation();
return (
<>
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
<FiHardDrive className="text-theme-800 dark:text-theme-200 w-5 h-5" />
<div className="flex flex-col ml-3 text-left min-w-[85px]">
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5">{t("common.bytes", { value: data.node.available })}</div>
<div className="pr-1">{t("resources.free")}</div>
</span>
{expanded && (
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5">{t("common.bytes", { value: data.node.maximum })}</div>
<div className="pr-1">{t("resources.total")}</div>
</span>
)}
<UsageBar percent={Math.round(((data.node.maximum - data.node.available) / data.node.maximum) * 100)} />
</div>
</div>
{labels && (
<div className="ml-6 pt-1 text-center text-theme-800 dark:text-theme-200 text-xs">{data.node.id}</div>
)}
</>
);
}

View File

@@ -38,7 +38,7 @@ export default function Cpu({ expanded }) {
<div className="pr-1">{t("resources.load")}</div> <div className="pr-1">{t("resources.load")}</div>
</div> </div>
)} )}
<UsageBar percent={100} /> <UsageBar percent={0} />
</div> </div>
</div> </div>
); );

View File

@@ -38,7 +38,7 @@ export default function Disk({ options, expanded }) {
<div className="pr-1">{t("resources.total")}</div> <div className="pr-1">{t("resources.total")}</div>
</span> </span>
)} )}
<UsageBar percent={100} /> <UsageBar percent={0} />
</div> </div>
</div> </div>
); );

View File

@@ -38,7 +38,7 @@ export default function Memory({ expanded }) {
<div className="pr-1">{t("resources.total")}</div> <div className="pr-1">{t("resources.total")}</div>
</span> </span>
)} )}
<UsageBar percent={100} /> <UsageBar percent={0} />
</div> </div>
</div> </div>
); );

View File

@@ -1,7 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { FiSearch } from "react-icons/fi"; import { FiSearch } from "react-icons/fi";
import { SiDuckduckgo, SiMicrosoftbing, SiGoogle, SiBaidu } from "react-icons/si"; import { SiDuckduckgo, SiMicrosoftbing, SiGoogle, SiBaidu, SiBrave } from "react-icons/si";
const providers = { const providers = {
google: { google: {
@@ -24,6 +24,11 @@ const providers = {
url: "https://www.baidu.com/s?wd=", url: "https://www.baidu.com/s?wd=",
icon: SiBaidu, icon: SiBaidu,
}, },
brave: {
name: "Brave",
url: "https://search.brave.com/search?q=",
icon: SiBrave,
},
custom: { custom: {
name: "Custom", name: "Custom",
url: false, url: false,

View File

@@ -13,6 +13,8 @@ const widgetMappings = {
unifi_console: dynamic(() => import("components/widgets/unifi_console/unifi_console")), unifi_console: dynamic(() => import("components/widgets/unifi_console/unifi_console")),
glances: dynamic(() => import("components/widgets/glances/glances")), glances: dynamic(() => import("components/widgets/glances/glances")),
openmeteo: dynamic(() => import("components/widgets/openmeteo/openmeteo")), openmeteo: dynamic(() => import("components/widgets/openmeteo/openmeteo")),
longhorn: dynamic(() => import("components/widgets/longhorn/longhorn")),
kubernetes: dynamic(() => import("components/widgets/kubernetes/kubernetes")),
}; };
export default function Widget({ widget }) { export default function Widget({ widget }) {

View File

@@ -0,0 +1,110 @@
import { CoreV1Api, Metrics } from "@kubernetes/client-node";
import getKubeConfig from "../../../../utils/config/kubernetes";
import { parseCpu, parseMemory } from "../../../../utils/kubernetes/kubernetes-utils";
import createLogger from "../../../../utils/logger";
const logger = createLogger("kubernetesStatsService");
export default async function handler(req, res) {
const APP_LABEL = "app.kubernetes.io/name";
const { service, podSelector } = req.query;
const [namespace, appName] = service;
if (!namespace && !appName) {
res.status(400).send({
error: "kubernetes query parameters are required"
});
return;
}
const labelSelector = podSelector !== undefined ? podSelector : `${APP_LABEL}=${appName}`;
try {
const kc = getKubeConfig();
if (!kc) {
res.status(500).send({
error: "No kubernetes configuration"
});
return;
}
const coreApi = kc.makeApiClient(CoreV1Api);
const metricsApi = new Metrics(kc);
const podsResponse = await coreApi.listNamespacedPod(namespace, null, null, null, null, labelSelector)
.then((response) => response.body)
.catch((err) => {
logger.error("Error getting pods: %d %s %s", err.statusCode, err.body, err.response);
return null;
});
if (!podsResponse) {
res.status(500).send({
error: "Error communicating with kubernetes"
});
return;
}
const pods = podsResponse.items;
if (pods.length === 0) {
res.status(404).send({
error: "not found"
});
return;
}
let cpuLimit = 0;
let memLimit = 0;
pods.forEach((pod) => {
pod.spec.containers.forEach((container) => {
if (container?.resources?.limits?.cpu) {
cpuLimit += parseCpu(container?.resources?.limits?.cpu);
}
if (container?.resources?.limits?.memory) {
memLimit += parseMemory(container?.resources?.limits?.memory);
}
});
});
const podStatsList = await Promise.all(pods.map(async (pod) => {
let depMem = 0;
let depCpu = 0;
const podMetrics = await metricsApi.getPodMetrics(namespace, pod.metadata.name)
.then((response) => response)
.catch((err) => {
// 404 generally means that the metrics have not been populated yet
if (err.statusCode !== 404) {
logger.error("Error getting pod metrics: %d %s %s", err.statusCode, err.body, err.response);
}
return null;
});
if (podMetrics) {
podMetrics.containers.forEach((container) => {
depMem += parseMemory(container.usage.memory);
depCpu += parseCpu(container.usage.cpu);
});
}
return {
mem: depMem,
cpu: depCpu
};
}));
const stats = {
mem: 0,
cpu: 0
}
podStatsList.forEach((podStat) => {
stats.mem += podStat.mem;
stats.cpu += podStat.cpu;
});
stats.cpuLimit = cpuLimit;
stats.memLimit = memLimit;
stats.cpuUsage = cpuLimit ? stats.cpu / cpuLimit : 0;
stats.memUsage = memLimit ? stats.mem / memLimit : 0;
res.status(200).json({
stats
});
} catch (e) {
logger.error(e);
res.status(500).send({
error: "unknown error"
});
}
}

View File

@@ -0,0 +1,66 @@
import { CoreV1Api } from "@kubernetes/client-node";
import getKubeConfig from "../../../../utils/config/kubernetes";
import createLogger from "../../../../utils/logger";
const logger = createLogger("kubernetesStatusService");
export default async function handler(req, res) {
const APP_LABEL = "app.kubernetes.io/name";
const { service, podSelector } = req.query;
const [namespace, appName] = service;
if (!namespace && !appName) {
res.status(400).send({
error: "kubernetes query parameters are required",
});
return;
}
const labelSelector = podSelector !== undefined ? podSelector : `${APP_LABEL}=${appName}`;
try {
const kc = getKubeConfig();
if (!kc) {
res.status(500).send({
error: "No kubernetes configuration"
});
return;
}
const coreApi = kc.makeApiClient(CoreV1Api);
const podsResponse = await coreApi.listNamespacedPod(namespace, null, null, null, null, labelSelector)
.then((response) => response.body)
.catch((err) => {
logger.error("Error getting pods: %d %s %s", err.statusCode, err.body, err.response);
return null;
});
if (!podsResponse) {
res.status(500).send({
error: "Error communicating with kubernetes"
});
return;
}
const pods = podsResponse.items;
if (pods.length === 0) {
res.status(404).send({
error: "not found",
});
return;
}
const someReady = pods.find(pod => pod.status.phase === "Running");
const allReady = pods.every((pod) => pod.status.phase === "Running");
let status = "down";
if (allReady) {
status = "running";
} else if (someReady) {
status = "partial";
}
res.status(200).json({
status
});
} catch (e) {
logger.error(e);
res.status(500).send({
error: "unknown error",
});
}
}

View File

@@ -0,0 +1,6 @@
import cachedFetch from "utils/proxy/cached-fetch";
export default async function handler(req, res) {
const releasesURL = "https://api.github.com/repos/benphelps/homepage/releases";
return res.send(await cachedFetch(releasesURL, 5));
}

View File

@@ -0,0 +1,92 @@
import { CoreV1Api, Metrics } from "@kubernetes/client-node";
import getKubeConfig from "../../../utils/config/kubernetes";
import { parseCpu, parseMemory } from "../../../utils/kubernetes/kubernetes-utils";
import createLogger from "../../../utils/logger";
const logger = createLogger("kubernetes-widget");
export default async function handler(req, res) {
try {
const kc = getKubeConfig();
if (!kc) {
return res.status(500).send({
error: "No kubernetes configuration"
});
}
const coreApi = kc.makeApiClient(CoreV1Api);
const metricsApi = new Metrics(kc);
const nodes = await coreApi.listNode()
.then((response) => response.body)
.catch((error) => {
logger.error("Error getting ingresses: %d %s %s", error.statusCode, error.body, error.response);
return null;
});
if (!nodes) {
return res.status(500).send({
error: "unknown error"
});
}
let cpuTotal = 0;
let cpuUsage = 0;
let memTotal = 0;
let memUsage = 0;
const nodeMap = {};
nodes.items.forEach((node) => {
const cpu = Number.parseInt(node.status.capacity.cpu, 10);
const mem = parseMemory(node.status.capacity.memory);
const ready = node.status.conditions.filter(condition => condition.type === "Ready" && condition.status === "True").length > 0;
nodeMap[node.metadata.name] = {
name: node.metadata.name,
ready,
cpu: {
total: cpu
},
memory: {
total: mem
}
};
cpuTotal += cpu;
memTotal += mem;
});
const nodeMetrics = await metricsApi.getNodeMetrics();
nodeMetrics.items.forEach((nodeMetric) => {
const cpu = parseCpu(nodeMetric.usage.cpu);
const mem = parseMemory(nodeMetric.usage.memory);
cpuUsage += cpu;
memUsage += mem;
nodeMap[nodeMetric.metadata.name].cpu.load = cpu;
nodeMap[nodeMetric.metadata.name].cpu.percent = (cpu / nodeMap[nodeMetric.metadata.name].cpu.total) * 100;
nodeMap[nodeMetric.metadata.name].memory.used = mem;
nodeMap[nodeMetric.metadata.name].memory.free = nodeMap[nodeMetric.metadata.name].memory.total - mem;
nodeMap[nodeMetric.metadata.name].memory.percent = (mem / nodeMap[nodeMetric.metadata.name].memory.total) * 100;
});
const cluster = {
cpu: {
load: cpuUsage,
total: cpuTotal,
percent: (cpuUsage / cpuTotal) * 100
},
memory: {
used: memUsage,
total: memTotal,
free: (memTotal - memUsage),
percent: (memUsage / memTotal) * 100
}
};
return res.status(200).json({
cluster,
nodes: Object.entries(nodeMap).map(([name, node]) => ({ name, ...node }))
});
} catch (e) {
logger.error("exception %s", e);
return res.status(500).send({
error: "unknown error"
});
}
}

View File

@@ -0,0 +1,84 @@
import { httpProxy } from "../../../utils/proxy/http";
import createLogger from "../../../utils/logger";
import { getSettings } from "../../../utils/config/config";
const logger = createLogger("longhorn");
function parseLonghornData(data) {
const json = JSON.parse(data);
if (!json) {
return null;
}
const nodes = json.data.map((node) => {
let available = 0;
let maximum = 0;
let reserved = 0;
let scheduled = 0;
if (node.disks) {
Object.keys(node.disks).forEach((diskKey) => {
const disk = node.disks[diskKey];
available += disk.storageAvailable;
maximum += disk.storageMaximum;
reserved += disk.storageReserved;
scheduled += disk.storageScheduled;
});
}
return {
id: node.id,
available,
maximum,
reserved,
scheduled,
};
});
const total = nodes.reduce((summary, node) => ({
available: summary.available + node.available,
maximum: summary.maximum + node.maximum,
reserved: summary.reserved + node.reserved,
scheduled: summary.scheduled + node.scheduled,
}));
total.id = "total";
nodes.push(total);
return nodes;
}
export default async function handler(req, res) {
const settings = getSettings();
const longhornSettings = settings?.providers?.longhorn;
const {url, username, password} = longhornSettings;
if (!url) {
const errorMessage = "Missing Longhorn URL";
logger.error(errorMessage);
return res.status(400).json({ error: errorMessage });
}
const apiUrl = `${url}/v1/nodes`;
const headers = {
"Accept-Encoding": "application/json"
};
if (username && password) {
headers.Authorization = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`
}
const params = { method: "GET", headers };
const [status, contentType, data] = await httpProxy(apiUrl, params);
if (status === 401) {
logger.error("Authorization failure getting data from Longhorn API. Data: %s", data);
}
if (status !== 200) {
logger.error("HTTP %d getting data from Longhorn API. Data: %s", status, data);
}
if (contentType) res.setHeader("Content-Type", contentType);
const nodes = parseLonghornData(data);
return res.status(200).json({
nodes,
});
}

View File

@@ -99,7 +99,7 @@ function Index({ initialSettings, fallback }) {
localStorage.setItem("hash", hashData.hash); localStorage.setItem("hash", hashData.hash);
} }
if (previousHash && previousHash !== hashData.hash) { if (!initialSettings.isValid || (previousHash && previousHash !== hashData.hash)) {
setStale(true); setStale(true);
localStorage.setItem("hash", hashData.hash); localStorage.setItem("hash", hashData.hash);
@@ -111,7 +111,7 @@ function Index({ initialSettings, fallback }) {
} }
} }
} }
}, [hashData]); }, [hashData, initialSettings]);
if (stale) { if (stale) {
return ( return (

View File

@@ -0,0 +1,2 @@
---
# sample kubernetes config

View File

@@ -5,7 +5,12 @@ import path from "path";
import yaml from "js-yaml"; import yaml from "js-yaml";
import checkAndCopyConfig, { getSettings } from "utils/config/config"; import checkAndCopyConfig, { getSettings } from "utils/config/config";
import { servicesFromConfig, servicesFromDocker, cleanServiceGroups } from "utils/config/service-helpers"; import {
servicesFromConfig,
servicesFromDocker,
cleanServiceGroups,
servicesFromKubernetes
} from "utils/config/service-helpers";
import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers"; import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers";
export async function bookmarksResponse() { export async function bookmarksResponse() {
@@ -44,23 +49,35 @@ export async function widgetsResponse() {
} }
export async function servicesResponse() { export async function servicesResponse() {
let discoveredServices; let discoveredDockerServices;
let discoveredKubernetesServices;
let configuredServices; let configuredServices;
let initialSettings; let initialSettings;
try { try {
discoveredServices = cleanServiceGroups(await servicesFromDocker()); discoveredDockerServices = cleanServiceGroups(await servicesFromDocker());
if (discoveredDockerServices?.length === 0) {
console.debug("No containers were found with homepage labels.");
}
} catch (e) { } catch (e) {
console.error("Failed to discover services, please check docker.yaml for errors or remove example entries."); console.error("Failed to discover services, please check docker.yaml for errors or remove example entries.");
if (e) console.error(e); if (e) console.error(e.toString());
discoveredServices = []; discoveredDockerServices = [];
}
try {
discoveredKubernetesServices = cleanServiceGroups(await servicesFromKubernetes());
} catch (e) {
console.error("Failed to discover services, please check kubernetes.yaml for errors or remove example entries.");
if (e) console.error(e.toString());
discoveredKubernetesServices = [];
} }
try { try {
configuredServices = cleanServiceGroups(await servicesFromConfig()); configuredServices = cleanServiceGroups(await servicesFromConfig());
} catch (e) { } catch (e) {
console.error("Failed to load services.yaml, please check for errors"); console.error("Failed to load services.yaml, please check for errors");
if (e) console.error(e); if (e) console.error(e.toString());
configuredServices = []; configuredServices = [];
} }
@@ -68,12 +85,16 @@ export async function servicesResponse() {
initialSettings = await getSettings(); initialSettings = await getSettings();
} catch (e) { } catch (e) {
console.error("Failed to load settings.yaml, please check for errors"); console.error("Failed to load settings.yaml, please check for errors");
if (e) console.error(e); if (e) console.error(e.toString());
initialSettings = {}; initialSettings = {};
} }
const mergedGroupsNames = [ const mergedGroupsNames = [
...new Set([discoveredServices.map((group) => group.name), configuredServices.map((group) => group.name)].flat()), ...new Set([
discoveredDockerServices.map((group) => group.name),
discoveredKubernetesServices.map((group) => group.name),
configuredServices.map((group) => group.name),
].flat()),
]; ];
const sortedGroups = []; const sortedGroups = [];
@@ -81,12 +102,17 @@ export async function servicesResponse() {
const definedLayouts = initialSettings.layout ? Object.keys(initialSettings.layout) : null; const definedLayouts = initialSettings.layout ? Object.keys(initialSettings.layout) : null;
mergedGroupsNames.forEach((groupName) => { mergedGroupsNames.forEach((groupName) => {
const discoveredGroup = discoveredServices.find((group) => group.name === groupName) || { services: [] }; const discoveredDockerGroup = discoveredDockerServices.find((group) => group.name === groupName) || { services: [] };
const discoveredKubernetesGroup = discoveredKubernetesServices.find((group) => group.name === groupName) || { services: [] };
const configuredGroup = configuredServices.find((group) => group.name === groupName) || { services: [] }; const configuredGroup = configuredServices.find((group) => group.name === groupName) || { services: [] };
const mergedGroup = { const mergedGroup = {
name: groupName, name: groupName,
services: [...discoveredGroup.services, ...configuredGroup.services].filter((service) => service), services: [
...discoveredDockerGroup.services,
...discoveredKubernetesGroup.services,
...configuredGroup.services
].filter((service) => service),
}; };
if (definedLayouts) { if (definedLayouts) {

View File

@@ -1,6 +1,6 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import { join } from "path"; import { join } from "path";
import { existsSync, copyFile, readFileSync } from "fs"; import { existsSync, copyFile, readFileSync, statSync } from "fs";
import yaml from "js-yaml"; import yaml from "js-yaml";
@@ -32,5 +32,18 @@ export function getSettings() {
const settingsYaml = join(process.cwd(), "config", "settings.yaml"); const settingsYaml = join(process.cwd(), "config", "settings.yaml");
const fileContents = readFileSync(settingsYaml, "utf8"); const fileContents = readFileSync(settingsYaml, "utf8");
return yaml.load(fileContents) ?? {};
let stats;
try {
stats = statSync(settingsYaml);
} catch (e) {
stats = {};
}
const yamlLoaded = yaml.load(fileContents) ?? {};
return {
...yamlLoaded,
isValid: fileContents !== "-\n" && stats.size !== 2 // see https://github.com/benphelps/homepage/pull/609
};
} }

View File

@@ -0,0 +1,30 @@
import path from "path";
import { readFileSync } from "fs";
import yaml from "js-yaml";
import { KubeConfig } from "@kubernetes/client-node";
import checkAndCopyConfig from "utils/config/config";
export default function getKubeConfig() {
checkAndCopyConfig("kubernetes.yaml");
const configFile = path.join(process.cwd(), "config", "kubernetes.yaml");
const configData = readFileSync(configFile, "utf8");
const config = yaml.load(configData);
const kc = new KubeConfig();
switch (config?.mode) {
case 'cluster':
kc.loadFromCluster();
break;
case 'default':
kc.loadFromDefault();
break;
case 'disabled':
default:
return null;
}
return kc;
}

View File

@@ -4,9 +4,14 @@ import path from "path";
import yaml from "js-yaml"; import yaml from "js-yaml";
import Docker from "dockerode"; import Docker from "dockerode";
import * as shvl from "shvl"; import * as shvl from "shvl";
import { NetworkingV1Api } from "@kubernetes/client-node";
import createLogger from "utils/logger";
import checkAndCopyConfig from "utils/config/config"; import checkAndCopyConfig from "utils/config/config";
import getDockerArguments from "utils/config/docker"; import getDockerArguments from "utils/config/docker";
import getKubeConfig from "utils/config/kubernetes";
const logger = createLogger("service-helpers");
export async function servicesFromConfig() { export async function servicesFromConfig() {
checkAndCopyConfig("services.yaml"); checkAndCopyConfig("services.yaml");
@@ -44,36 +49,41 @@ export async function servicesFromDocker() {
const serviceServers = await Promise.all( const serviceServers = await Promise.all(
Object.keys(servers).map(async (serverName) => { Object.keys(servers).map(async (serverName) => {
const docker = new Docker(getDockerArguments(serverName).conn); try {
const containers = await docker.listContainers({ const docker = new Docker(getDockerArguments(serverName).conn);
all: true, const containers = await docker.listContainers({
}); all: true,
// bad docker connections can result in a <Buffer ...> object?
// in any case, this ensures the result is the expected array
if (!Array.isArray(containers)) {
return [];
}
const discovered = containers.map((container) => {
let constructedService = null;
Object.keys(container.Labels).forEach((label) => {
if (label.startsWith("homepage.")) {
if (!constructedService) {
constructedService = {
container: container.Names[0].replace(/^\//, ""),
server: serverName,
};
}
shvl.set(constructedService, label.replace("homepage.", ""), container.Labels[label]);
}
}); });
return constructedService; // bad docker connections can result in a <Buffer ...> object?
}); // in any case, this ensures the result is the expected array
if (!Array.isArray(containers)) {
return [];
}
return { server: serverName, services: discovered.filter((filteredService) => filteredService) }; const discovered = containers.map((container) => {
let constructedService = null;
Object.keys(container.Labels).forEach((label) => {
if (label.startsWith("homepage.")) {
if (!constructedService) {
constructedService = {
container: container.Names[0].replace(/^\//, ""),
server: serverName,
};
}
shvl.set(constructedService, label.replace("homepage.", ""), container.Labels[label]);
}
});
return constructedService;
});
return { server: serverName, services: discovered.filter((filteredService) => filteredService) };
} catch (e) {
// a server failed, but others may succeed
return { server: serverName, services: [] };
}
}) })
); );
@@ -103,6 +113,89 @@ export async function servicesFromDocker() {
return mappedServiceGroups; return mappedServiceGroups;
} }
function getUrlFromIngress(ingress) {
const urlHost = ingress.spec.rules[0].host;
const urlPath = ingress.spec.rules[0].http.paths[0].path;
const urlSchema = ingress.spec.tls ? 'https' : 'http';
return `${urlSchema}://${urlHost}${urlPath}`;
}
export async function servicesFromKubernetes() {
const ANNOTATION_BASE = 'gethomepage.dev';
const ANNOTATION_WIDGET_BASE = `${ANNOTATION_BASE}/widget.`;
const ANNOTATION_POD_SELECTOR = `${ANNOTATION_BASE}/pod-selector`;
checkAndCopyConfig("kubernetes.yaml");
try {
const kc = getKubeConfig();
if (!kc) {
return [];
}
const networking = kc.makeApiClient(NetworkingV1Api);
const ingressList = await networking.listIngressForAllNamespaces(null, null, null, null)
.then((response) => response.body)
.catch((error) => {
logger.error("Error getting ingresses: %d %s %s", error.statusCode, error.body, error.response);
return null;
});
if (!ingressList) {
return [];
}
const services = ingressList.items
.filter((ingress) => ingress.metadata.annotations && ingress.metadata.annotations[`${ANNOTATION_BASE}/enabled`] === 'true')
.map((ingress) => {
const constructedService = {
app: ingress.metadata.name,
namespace: ingress.metadata.namespace,
href: ingress.metadata.annotations[`${ANNOTATION_BASE}/href`] || getUrlFromIngress(ingress),
name: ingress.metadata.annotations[`${ANNOTATION_BASE}/name`] || ingress.metadata.name,
group: ingress.metadata.annotations[`${ANNOTATION_BASE}/group`] || "Kubernetes",
icon: ingress.metadata.annotations[`${ANNOTATION_BASE}/icon`] || '',
description: ingress.metadata.annotations[`${ANNOTATION_BASE}/description`] || '',
};
if (ingress.metadata.annotations[ANNOTATION_POD_SELECTOR]) {
constructedService.podSelector = ingress.metadata.annotations[ANNOTATION_POD_SELECTOR];
}
Object.keys(ingress.metadata.annotations).forEach((annotation) => {
if (annotation.startsWith(ANNOTATION_WIDGET_BASE)) {
shvl.set(constructedService, annotation.replace(`${ANNOTATION_BASE}/`, ""), ingress.metadata.annotations[annotation]);
}
});
return constructedService;
});
const mappedServiceGroups = [];
services.forEach((serverService) => {
let serverGroup = mappedServiceGroups.find((searchedGroup) => searchedGroup.name === serverService.group);
if (!serverGroup) {
mappedServiceGroups.push({
name: serverService.group,
services: [],
});
serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1];
}
const { name: serviceName, group: serverServiceGroup, ...pushedService } = serverService;
const result = {
name: serviceName,
...pushedService,
};
serverGroup.services.push(result);
});
return mappedServiceGroups;
} catch (e) {
logger.error(e);
throw e;
}
}
export function cleanServiceGroups(groups) { export function cleanServiceGroups(groups) {
return groups.map((serviceGroup) => ({ return groups.map((serviceGroup) => ({
name: serviceGroup.name, name: serviceGroup.name,
@@ -118,7 +211,10 @@ export function cleanServiceGroups(groups) {
container, container,
currency, // coinmarketcap widget currency, // coinmarketcap widget
symbols, symbols,
defaultinterval defaultinterval,
namespace, // kubernetes widget
app,
podSelector
} = cleanedService.widget; } = cleanedService.widget;
cleanedService.widget = { cleanedService.widget = {
@@ -136,6 +232,11 @@ export function cleanServiceGroups(groups) {
if (server) cleanedService.widget.server = server; if (server) cleanedService.widget.server = server;
if (container) cleanedService.widget.container = container; if (container) cleanedService.widget.container = container;
} }
if (type === "kubernetes") {
if (namespace) cleanedService.widget.namespace = namespace;
if (app) cleanedService.widget.app = app;
if (podSelector) cleanedService.widget.podSelector = podSelector;
}
} }
return cleanedService; return cleanedService;
@@ -166,5 +267,15 @@ export default async function getServiceWidget(group, service) {
} }
} }
const kubernetesServices = await servicesFromKubernetes();
const kubernetesServiceGroup = kubernetesServices.find((g) => g.name === group);
if (kubernetesServiceGroup) {
const kubernetesServiceEntry = kubernetesServiceGroup.services.find((s) => s.name === service);
if (kubernetesServiceEntry) {
const { widget } = kubernetesServiceEntry;
return widget;
}
}
return false; return false;
} }

View File

@@ -0,0 +1,45 @@
export function parseCpu(cpuStr) {
const unitLength = 1;
const base = Number.parseInt(cpuStr, 10);
const units = cpuStr.substring(cpuStr.length - unitLength);
if (Number.isNaN(Number(units))) {
switch (units) {
case 'n':
return base / 1000000000;
case 'u':
return base / 1000000;
case 'm':
return base / 1000;
default:
return base;
}
} else {
return Number.parseInt(cpuStr, 10);
}
}
export function parseMemory(memStr) {
const unitLength = (memStr.substring(memStr.length - 1) === 'i' ? 2 : 1);
const base = Number.parseInt(memStr, 10);
const units = memStr.substring(memStr.length - unitLength);
if (Number.isNaN(Number(units))) {
switch (units) {
case 'Ki':
return base * 1000;
case 'K':
return base * 1024;
case 'Mi':
return base * 1000000;
case 'M':
return base * 1024 * 1024;
case 'Gi':
return base * 1000000000;
case 'G':
return base * 1024 * 1024 * 1024;
default:
return base;
}
} else {
return Number.parseInt(memStr, 10);
}
}

View File

@@ -30,6 +30,8 @@ export default async function credentialedProxyHandler(req, res, map) {
headers["X-gotify-Key"] = `${widget.key}`; headers["X-gotify-Key"] = `${widget.key}`;
} else if (widget.type === "authentik") { } else if (widget.type === "authentik") {
headers.Authorization = `Bearer ${widget.key}`; headers.Authorization = `Bearer ${widget.key}`;
} else if (widget.type === "truenas") {
headers.Authorization = `Bearer ${widget.key}`;
} else if (widget.type === "proxmox") { } else if (widget.type === "proxmox") {
headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`; headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`;
} else if (widget.type === "autobrr") { } else if (widget.type === "autobrr") {

View File

@@ -4,8 +4,8 @@ import { formatProxyUrl } from "./api-helpers";
export default function useWidgetAPI(widget, ...options) { export default function useWidgetAPI(widget, ...options) {
const config = {}; const config = {};
if (options?.refreshInterval) { if (options && options[1]?.refreshInterval) {
config.refreshInterval = options.refreshInterval; config.refreshInterval = options[1].refreshInterval;
} }
const { data, error } = useSWR(formatProxyUrl(widget, ...options), config); const { data, error } = useSWR(formatProxyUrl(widget, ...options), config);
// make the data error the top-level error // make the data error the top-level error

View File

@@ -10,6 +10,7 @@ const components = {
deluge: dynamic(() => import("./deluge/component")), deluge: dynamic(() => import("./deluge/component")),
downloadstation: dynamic(() => import("./downloadstation/component")), downloadstation: dynamic(() => import("./downloadstation/component")),
docker: dynamic(() => import("./docker/component")), docker: dynamic(() => import("./docker/component")),
kubernetes: dynamic(() => import("./kubernetes/component")),
emby: dynamic(() => import("./emby/component")), emby: dynamic(() => import("./emby/component")),
flood: dynamic(() => import("./flood/component")), flood: dynamic(() => import("./flood/component")),
gluetun: dynamic(() => import("./gluetun/component")), gluetun: dynamic(() => import("./gluetun/component")),
@@ -21,12 +22,15 @@ const components = {
jellyseerr: dynamic(() => import("./jellyseerr/component")), jellyseerr: dynamic(() => import("./jellyseerr/component")),
lidarr: dynamic(() => import("./lidarr/component")), lidarr: dynamic(() => import("./lidarr/component")),
mastodon: dynamic(() => import("./mastodon/component")), mastodon: dynamic(() => import("./mastodon/component")),
medusa: dynamic(() => import("./medusa/component")),
miniflux: dynamic(() => import("./miniflux/component")), miniflux: dynamic(() => import("./miniflux/component")),
mikrotik: dynamic(() => import("./mikrotik/component")), mikrotik: dynamic(() => import("./mikrotik/component")),
moonraker: dynamic(() => import("./moonraker/component")),
navidrome: dynamic(() => import("./navidrome/component")), navidrome: dynamic(() => import("./navidrome/component")),
nextdns: dynamic(() => import("./nextdns/component")), nextdns: dynamic(() => import("./nextdns/component")),
npm: dynamic(() => import("./npm/component")), npm: dynamic(() => import("./npm/component")),
nzbget: dynamic(() => import("./nzbget/component")), nzbget: dynamic(() => import("./nzbget/component")),
octoPrint: dynamic(() => import("./octoPrint/component")),
omada: dynamic(() => import("./omada/component")), omada: dynamic(() => import("./omada/component")),
ombi: dynamic(() => import("./ombi/component")), ombi: dynamic(() => import("./ombi/component")),
opnsense: dynamic(() => import("./opnsense/component")), opnsense: dynamic(() => import("./opnsense/component")),

View File

@@ -5,10 +5,8 @@ import widgets from "widgets/widgets";
import getServiceWidget from "utils/config/service-helpers"; import getServiceWidget from "utils/config/service-helpers";
const logger = createLogger("downloadstationProxyHandler"); const logger = createLogger("downloadstationProxyHandler");
const authApi = "{url}/webapi/auth.cgi?api=SYNO.API.Auth&version=2&method=login&account={username}&passwd={password}&session=DownloadStation&format=cookie"
async function login(widget) { async function login(loginUrl) {
const loginUrl = formatApiCall(authApi, widget);
const [status, contentType, data] = await httpProxy(loginUrl); const [status, contentType, data] = await httpProxy(loginUrl);
if (status !== 200) { if (status !== 200) {
return [status, contentType, data]; return [status, contentType, data];
@@ -56,8 +54,28 @@ export default async function downloadstationProxyHandler(req, res) {
const json = JSON.parse(data.toString()); const json = JSON.parse(data.toString());
if (json?.success !== true) { if (json?.success !== true) {
logger.debug("Logging in to DownloadStation"); logger.debug("Attempting login to DownloadStation");
[status, contentType, data] = await login(widget);
const apiInfoUrl = formatApiCall("{url}/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query", widget);
let path = "entry.cgi";
let maxVersion = 7;
[status, contentType, data] = await httpProxy(apiInfoUrl);
if (status === 200) {
try {
const apiAuthInfo = JSON.parse(data.toString()).data['SYNO.API.Auth'];
if (apiAuthInfo) {
path = apiAuthInfo.path;
maxVersion = apiAuthInfo.maxVersion;
logger.debug(`Deteceted Downloadstation auth API path: ${path} and maxVersion: ${maxVersion}`);
}
} catch {
logger.debug(`Error ${status} obtaining DownloadStation API info`);
}
}
const authApi = `{url}/webapi/${path}?api=SYNO.API.Auth&version=${maxVersion}&method=login&account={username}&passwd={password}&session=DownloadStation&format=cookie`
const loginUrl = formatApiCall(authApi, widget);
[status, contentType, data] = await login(loginUrl);
if (status !== 200) { if (status !== 200) {
return res.status(status).end(data) return res.status(status).end(data)
} }

View File

@@ -0,0 +1,50 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const podSelectorString = widget.podSelector !== undefined ? `podSelector=${widget.podSelector}` : "";
const { data: statusData, error: statusError } = useSWR(
`/api/kubernetes/status/${widget.namespace}/${widget.app}?${podSelectorString}`);
const { data: statsData, error: statsError } = useSWR(
`/api/kubernetes/stats/${widget.namespace}/${widget.app}?${podSelectorString}`);
if (statsError || statusError) {
return <Container error={t("widget.api_error")} />;
}
if (statusData && statusData.status !== "running") {
return (
<Container>
<Block label={t("widget.status")} value={t("docker.offline")} />
</Container>
);
}
if (!statsData || !statusData) {
return (
<Container service={service}>
<Block label="docker.cpu" />
<Block label="docker.mem" />
</Container>
);
}
return (
<Container service={service}>
{statsData.stats.cpuLimit && (
<Block label="docker.cpu" value={t("common.percent", { value: statsData.stats.cpuUsage })} />
) || (
<Block label="docker.cpu" value={t("common.number", { value: statsData.stats.cpu, maximumFractionDigits: 4 })}
/>
)}
<Block label="docker.mem" value={t("common.bytes", { value: statsData.stats.mem })} />
</Container>
);
}

View File

@@ -0,0 +1,39 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const { data: statsData, error: statsError } = useWidgetAPI(widget, "stats");
const { data: futureData, error: futureError } = useWidgetAPI(widget, "future");
if (statsError || futureError) {
const finalError = statsError ?? futureError;
return <Container error={finalError} />;
}
if (!statsData || !futureData) {
return (
<Container service={service}>
<Block label="medusa.wanted" />
<Block label="medusa.queued" />
<Block label="medusa.series" />
</Container>
);
}
const { later, missed, soon, today } = futureData.data;
const future = later.length + missed.length + soon.length + today.length;
return (
<Container service={service}>
<Block label="medusa.wanted" value={t("common.number", { value: future })} />
<Block label="medusa.queued" value={t("common.number", { value: statsData.data.ep_snatched })} />
<Block label="medusa.series" value={t("common.number", { value: statsData.data.shows_active })} />
</Container>
);
}

View File

@@ -0,0 +1,23 @@
import genericProxyHandler from "utils/proxy/handlers/generic";
const widget = {
api: "{url}/api/v1/{key}/{endpoint}/",
proxyHandler: genericProxyHandler,
mappings: {
stats: {
endpoint: "?cmd=shows.stats",
validate: [
"data"
]
},
future: {
endpoint: "?cmd=future",
validate: [
"data"
]
}
}
};
export default widget;

View File

@@ -0,0 +1,51 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const { data: printStats, error: printStatsError } = useWidgetAPI(widget, "print_stats");
const { data: displayStatus, error: displayStatsError } = useWidgetAPI(widget, "display_status");
const { data: webHooks, error: webHooksError } = useWidgetAPI(widget, "webhooks");
if (printStatsError || displayStatsError || webHooksError) {
const finalError = printStatsError ?? displayStatsError ?? webHooksError;
return <Container error={finalError} />;
}
if (!printStats || !displayStatus || !webHooks) {
return (
<Container service={service}>
<Block label="moonraker.printer_state" />
</Container>
);
}
if (webHooks.result.status.webhooks.state === "shutdown") {
return (
<Container service={service}>
<Block label="moonraker.printer_state" value={webHooks.result.status.webhooks.state} />
</Container>
);
}
let currentLayer = "-";
let totalLayer = "-";
if (printStats.result.status.print_stats.info.total_layer !== null) {
currentLayer = printStats.result.status.print_stats.info.current_layer;
totalLayer = printStats.result.status.print_stats.info.total_layer;
}
return (
<Container service={service}>
<Block label="moonraker.layers" value={`${currentLayer} / ${totalLayer}`} />
<Block label="moonraker.print_progress" value={t("common.percent", { value: (displayStatus.result.status.display_status.progress * 100) })} />
<Block label="moonraker.print_status" value={printStats.result.status.print_stats.state} />
</Container>
);
}

View File

@@ -0,0 +1,20 @@
import genericProxyHandler from "utils/proxy/handlers/generic";
const widget = {
api: "{url}/printer/objects/query?{endpoint}",
proxyHandler: genericProxyHandler,
mappings: {
print_stats: {
endpoint: "print_stats",
},
display_status: {
endpoint: "display_status",
},
webhooks: {
endpoint: "webhooks",
},
},
};
export default widget;

View File

@@ -0,0 +1,64 @@
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { widget } = service;
const { data: printerStats, error: printerStatsError } = useWidgetAPI(widget, "printer_stats");
const { data: jobStats, error: jobStatsError } = useWidgetAPI(widget, "job_stats");
if (printerStatsError) {
return <Container error={printerStatsError} />;
}
if (jobStatsError) {
return <Container error={jobStatsError} />;
}
const state = printerStats?.state?.text;
const tempTool = printerStats?.temperature?.tool0?.actual;
const tempBed = printerStats?.temperature?.bed?.actual;
if (!printerStats || !state || !tempTool || !tempBed) {
return (
<Container service={service}>
<Block label="octoPrint.printer_state" />
</Container>
);
}
const printingStateFalgs = ["Printing", "Paused", "Pausing", "Resuming"];
if (printingStateFalgs.includes(state)) {
const { completion } = jobStats.progress;
if (!jobStats || !completion) {
return (
<Container service={service}>
<Block label="octoPrint.printer_state" />
<Block label="octoPrint.temp_tool" />
<Block label="octoPrint.temp_bed" />
<Block label="octoPrint.job_completion" />
</Container>
);
}
return (
<Container service={service}>
<Block label="octoPrint.printer_state" value={printerStats.state.text} />
<Block label="octoPrint.temp_tool" value={`${printerStats.temperature.tool0.actual} °C`} />
<Block label="octoPrint.temp_bed" value={`${printerStats.temperature.bed.actual} °C`} />
<Block label="octoPrint.job_completion" value={`${completion.toFixed(2)}%`} />
</Container>
);
}
return (
<Container service={service}>
<Block label="octoPrint.printer_state" value={printerStats.state.text} />
<Block label="octoPrint.temp_tool" value={`${printerStats.temperature.tool0.actual} °C`} />
<Block label="octoPrint.temp_bed" value={`${printerStats.temperature.bed.actual} °C`} />
</Container>
);
}

View File

@@ -0,0 +1,17 @@
import genericProxyHandler from "utils/proxy/handlers/generic";
const widget = {
api: "{url}/api/{endpoint}?apikey={key}",
proxyHandler: genericProxyHandler,
mappings: {
printer_stats: {
endpoint: "printer",
},
job_stats: {
endpoint: "job",
},
},
};
export default widget;

View File

@@ -42,9 +42,9 @@ export default async function omadaProxyHandler(req, res) {
if (widget) { if (widget) {
const {url} = widget; const { url } = widget;
const controllerInfoURL = `${widget.url}/api/info`; const controllerInfoURL = `${url}/api/info`;
let [status, contentType, data] = await httpProxy(controllerInfoURL, { let [status, contentType, data] = await httpProxy(controllerInfoURL, {
headers: { headers: {
@@ -77,13 +77,13 @@ export default async function omadaProxyHandler(req, res) {
switch (controllerVersionMajor) { switch (controllerVersionMajor) {
case 3: case 3:
loginUrl = `${widget.url}/api/user/login?ajax`; loginUrl = `${url}/api/user/login?ajax`;
break; break;
case 4: case 4:
loginUrl = `${widget.url}/api/v2/login`; loginUrl = `${url}/api/v2/login`;
break; break;
case 5: case 5:
loginUrl = `${widget.url}/${cId}/api/v2/login`; loginUrl = `${url}/${cId}/api/v2/login`;
break; break;
default: default:
break; break;
@@ -105,7 +105,7 @@ export default async function omadaProxyHandler(req, res) {
switch (controllerVersionMajor) { switch (controllerVersionMajor) {
case 3: case 3:
sitesUrl = `${widget.url}/web/v1/controller?ajax=&token=${token}`; sitesUrl = `${url}/web/v1/controller?ajax=&token=${token}`;
body = { body = {
"method": "getUserSites", "method": "getUserSites",
"params": { "params": {
@@ -115,10 +115,10 @@ export default async function omadaProxyHandler(req, res) {
method = "POST"; method = "POST";
break; break;
case 4: case 4:
sitesUrl = `${widget.url}/api/v2/sites?token=${token}&currentPage=1&currentPageSize=1000`; sitesUrl = `${url}/api/v2/sites?token=${token}&currentPage=1&currentPageSize=1000`;
break; break;
case 5: case 5:
sitesUrl = `${widget.url}/${cId}/api/v2/sites?token=${token}&currentPage=1&currentPageSize=1000`; sitesUrl = `${url}/${cId}/api/v2/sites?token=${token}&currentPage=1&currentPageSize=1000`;
break; break;
default: default:
break; break;
@@ -133,7 +133,7 @@ export default async function omadaProxyHandler(req, res) {
const sitesResponseData = JSON.parse(data); const sitesResponseData = JSON.parse(data);
if (sitesResponseData.errorCode > 0) { if (status !== 200 || sitesResponseData.errorCode > 0) {
logger.debug(`HTTTP ${status} getting sites list: ${sitesResponseData.msg}`); logger.debug(`HTTTP ${status} getting sites list: ${sitesResponseData.msg}`);
return res.status(status).json({error: {message: "Error getting sites list", url, data: sitesResponseData}}); return res.status(status).json({error: {message: "Error getting sites list", url, data: sitesResponseData}});
} }
@@ -143,7 +143,7 @@ export default async function omadaProxyHandler(req, res) {
sitesResponseData.result.data.find(s => s.name === widget.site); sitesResponseData.result.data.find(s => s.name === widget.site);
if (!site) { if (!site) {
return res.status(status).json({error: {message: `Site ${widget.site} is not found`, url, data}}); return res.status(status).json({error: {message: `Site ${widget.site} is not found`, url: sitesUrl, data}});
} }
let siteResponseData; let siteResponseData;
@@ -156,7 +156,7 @@ export default async function omadaProxyHandler(req, res) {
if (controllerVersionMajor === 3) { if (controllerVersionMajor === 3) {
// Omada v3 controller requires switching site // Omada v3 controller requires switching site
const switchUrl = `${widget.url}/web/v1/controller?ajax=&token=${token}`; const switchUrl = `${url}/web/v1/controller?ajax=&token=${token}`;
method = "POST"; method = "POST";
body = { body = {
method: "switchSite", method: "switchSite",
@@ -181,7 +181,7 @@ export default async function omadaProxyHandler(req, res) {
return res.status(status).json({error: {message: "Error switching site", url: switchUrl, data}}); return res.status(status).json({error: {message: "Error switching site", url: switchUrl, data}});
} }
const statsUrl = `${widget.url}/web/v1/controller?getGlobalStat=&token=${token}`; const statsUrl = `${url}/web/v1/controller?getGlobalStat=&token=${token}`;
[status, contentType, data] = await httpProxy(statsUrl, { [status, contentType, data] = await httpProxy(statsUrl, {
method, method,
params, params,

View File

@@ -84,9 +84,9 @@ export default async function pyloadProxyHandler(req, res) {
if (data?.error || status !== 200) { if (data?.error || status !== 200) {
try { try {
return res.status(status).send({error: {message: "HTTP error communicating with Plex API", data: Buffer.from(data).toString()}}); return res.status(status).send({error: {message: "HTTP error communicating with Pyload API", data: Buffer.from(data).toString()}});
} catch (e) { } catch (e) {
return res.status(status).send({error: {message: "HTTP error communicating with Plex API", data}}); return res.status(status).send({error: {message: "HTTP error communicating with Pyload API", data}});
} }
} }
@@ -95,7 +95,7 @@ export default async function pyloadProxyHandler(req, res) {
} }
} catch (e) { } catch (e) {
logger.error(e); logger.error(e);
return res.status(500).send({error: {message: `Error communicating with Plex API: ${e.toString()}`}}); return res.status(500).send({error: {message: `Error communicating with Pyload API: ${e.toString()}`}});
} }
return res.status(400).json({ error: 'Invalid proxy service type' }); return res.status(400).json({ error: 'Invalid proxy service type' });

View File

@@ -1,9 +1,31 @@
import { jsonArrayFilter } from "utils/proxy/api-helpers"; import { jsonArrayFilter } from "utils/proxy/api-helpers";
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
import genericProxyHandler from "utils/proxy/handlers/generic"; import genericProxyHandler from "utils/proxy/handlers/generic";
import getServiceWidget from "utils/config/service-helpers";
const widget = { const widget = {
api: "{url}/api/v2.0/{endpoint}", api: "{url}/api/v2.0/{endpoint}",
proxyHandler: genericProxyHandler, proxyHandler: async (req, res, map) => { // choose proxy handler based on widget settings
const { group, service } = req.query;
if (group && service) {
const widgetOpts = await getServiceWidget(group, service);
let handler;
if (widgetOpts.username && widgetOpts.password) {
handler = genericProxyHandler;
} else if (widgetOpts.key) {
handler = credentialedProxyHandler;
}
if (handler) {
return handler(req, res, map);
}
return res.status(500).json({ error: "Username / password or API key required" });
}
return res.status(500).json({ error: "Error parsing widget request" });
},
mappings: { mappings: {
alerts: { alerts: {

View File

@@ -16,12 +16,15 @@ import jackett from "./jackett/widget";
import jellyseerr from "./jellyseerr/widget"; import jellyseerr from "./jellyseerr/widget";
import lidarr from "./lidarr/widget"; import lidarr from "./lidarr/widget";
import mastodon from "./mastodon/widget"; import mastodon from "./mastodon/widget";
import medusa from "./medusa/widget";
import miniflux from "./miniflux/widget"; import miniflux from "./miniflux/widget";
import mikrotik from "./mikrotik/widget"; import mikrotik from "./mikrotik/widget";
import moonraker from "./moonraker/widget";
import navidrome from "./navidrome/widget"; import navidrome from "./navidrome/widget";
import nextdns from "./nextdns/widget"; import nextdns from "./nextdns/widget";
import npm from "./npm/widget"; import npm from "./npm/widget";
import nzbget from "./nzbget/widget"; import nzbget from "./nzbget/widget";
import octoPrint from "./octoPrint/widget";
import omada from "./omada/widget"; import omada from "./omada/widget";
import ombi from "./ombi/widget"; import ombi from "./ombi/widget";
import opnsense from "./opnsense/widget"; import opnsense from "./opnsense/widget";
@@ -49,8 +52,8 @@ import transmission from "./transmission/widget";
import tubearchivist from "./tubearchivist/widget"; import tubearchivist from "./tubearchivist/widget";
import truenas from "./truenas/widget"; import truenas from "./truenas/widget";
import unifi from "./unifi/widget"; import unifi from "./unifi/widget";
import watchtower from './watchtower/widget' import watchtower from "./watchtower/widget";
import xteve from './xteve/widget' import xteve from "./xteve/widget";
const widgets = { const widgets = {
adguard, adguard,
@@ -73,12 +76,15 @@ const widgets = {
jellyseerr, jellyseerr,
lidarr, lidarr,
mastodon, mastodon,
medusa,
miniflux, miniflux,
mikrotik, mikrotik,
moonraker,
navidrome, navidrome,
nextdns, nextdns,
npm, npm,
nzbget, nzbget,
octoPrint,
omada, omada,
ombi, ombi,
opnsense, opnsense,