mirror of
https://github.com/henrygd/beszel.git
synced 2026-03-22 05:36:15 +01:00
Compare commits
844 Commits
v0.10.2
...
87329a68bd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87329a68bd | ||
|
|
1c7caaf59a | ||
|
|
4c14877f33 | ||
|
|
5941c5e449 | ||
|
|
d2991bdc88 | ||
|
|
b58d0dd16a | ||
|
|
01e75c19ba | ||
|
|
3aea19d66e | ||
|
|
2ba3c87b07 | ||
|
|
1565812bd7 | ||
|
|
406b74d70f | ||
|
|
35e254f84b | ||
|
|
c96d9d9cdf | ||
|
|
4acb763ac5 | ||
|
|
ed027c9c37 | ||
|
|
c4e847fd1a | ||
|
|
6731b3b9f1 | ||
|
|
2229ff8a72 | ||
|
|
f2579602b0 | ||
|
|
f3b8be37fc | ||
|
|
87a802e85f | ||
|
|
088dbb9933 | ||
|
|
442c1b2922 | ||
|
|
b443c8d680 | ||
|
|
552eaf4240 | ||
|
|
125f63603d | ||
|
|
69e1c3608c | ||
|
|
e4c90c7855 | ||
|
|
03e2de874a | ||
|
|
9a0b666acc | ||
|
|
de2f96ef2e | ||
|
|
931eec842f | ||
|
|
f52cd6514e | ||
|
|
b38d424770 | ||
|
|
bd31c8f232 | ||
|
|
254e210d97 | ||
|
|
80cb847771 | ||
|
|
e09e906248 | ||
|
|
7845d90ce7 | ||
|
|
5989f18cfb | ||
|
|
5b675bddf8 | ||
|
|
ad97cce189 | ||
|
|
789c9f166b | ||
|
|
40c8696c0f | ||
|
|
59cd27a9ec | ||
|
|
a59a2bb408 | ||
|
|
1cabcc9ecb | ||
|
|
7f5a2be7fa | ||
|
|
ee34919525 | ||
|
|
d58c4bfbf3 | ||
|
|
c811cd2fd6 | ||
|
|
8cf2678c9a | ||
|
|
5775e2a7e0 | ||
|
|
cfc9ac437f | ||
|
|
813c622ebf | ||
|
|
9048d645d0 | ||
|
|
2e247312aa | ||
|
|
9e1932394b | ||
|
|
99f156d1d7 | ||
|
|
10bda5d42d | ||
|
|
5ec86f57b8 | ||
|
|
51fa959ccf | ||
|
|
9e50162063 | ||
|
|
6d13acd294 | ||
|
|
3570ee8313 | ||
|
|
c9e67ae7b8 | ||
|
|
832e08ac3b | ||
|
|
934e877616 | ||
|
|
e8a8bab2db | ||
|
|
69645f33d5 | ||
|
|
8af100796a | ||
|
|
eee6698e60 | ||
|
|
fed9084e07 | ||
|
|
56ce1309c9 | ||
|
|
ce7f096789 | ||
|
|
2656f6581a | ||
|
|
23055c2255 | ||
|
|
e493b72c0f | ||
|
|
4b1c20820e | ||
|
|
7c74922760 | ||
|
|
19fcce8952 | ||
|
|
3d74c23098 | ||
|
|
d433962a41 | ||
|
|
c1d94ac29f | ||
|
|
9f4e56c9cf | ||
|
|
a3ebfbf37f | ||
|
|
cb90e96ae5 | ||
|
|
25ed5d0d66 | ||
|
|
3e5b91056e | ||
|
|
dc79f24c06 | ||
|
|
f9f5258b22 | ||
|
|
0b611cda57 | ||
|
|
74635e5763 | ||
|
|
8ce9088d9d | ||
|
|
b3331c00f8 | ||
|
|
d0559065c1 | ||
|
|
78f6006bdc | ||
|
|
436b42f4d1 | ||
|
|
16f7b30624 | ||
|
|
9249256c9f | ||
|
|
34163b8595 | ||
|
|
a4731f9179 | ||
|
|
9c74eccaf0 | ||
|
|
4768adf440 | ||
|
|
11ffb422e8 | ||
|
|
bab02ad738 | ||
|
|
61faee2450 | ||
|
|
d0be54f47c | ||
|
|
cc2be97055 | ||
|
|
2fc1565b75 | ||
|
|
f5421eff3c | ||
|
|
fc01ca1cad | ||
|
|
e2923126d2 | ||
|
|
972ce62ff5 | ||
|
|
05d9297ca3 | ||
|
|
ffc35b3c51 | ||
|
|
a547de8bf0 | ||
|
|
d8d1a89256 | ||
|
|
c29ba1c353 | ||
|
|
474d860929 | ||
|
|
fb57a57e77 | ||
|
|
02e5a8e9fc | ||
|
|
c0f6f64aa7 | ||
|
|
3077ed045d | ||
|
|
f7b62a2868 | ||
|
|
5daa0d3576 | ||
|
|
a6b9fa2aa9 | ||
|
|
5195e6d675 | ||
|
|
93e71dcf30 | ||
|
|
826227f3af | ||
|
|
cfe8645c18 | ||
|
|
681184b444 | ||
|
|
6d759cbe9f | ||
|
|
75480f66fa | ||
|
|
416c237ef3 | ||
|
|
ff64ac7a37 | ||
|
|
555f668b54 | ||
|
|
0dedc634a7 | ||
|
|
5500e45951 | ||
|
|
e7574a927f | ||
|
|
83fbaa7a3f | ||
|
|
cf3efa1f9f | ||
|
|
24093e33a9 | ||
|
|
075fad1da4 | ||
|
|
a35631415a | ||
|
|
8e99d67174 | ||
|
|
cf37c9a93c | ||
|
|
402d1d9fec | ||
|
|
b4f2afa4b6 | ||
|
|
beff2eb43f | ||
|
|
2e0d12a02d | ||
|
|
bc2fd34ac5 | ||
|
|
333cfae109 | ||
|
|
8cf8dd492d | ||
|
|
9b664b6400 | ||
|
|
c30d2fbe39 | ||
|
|
f1a4fae659 | ||
|
|
32675e403f | ||
|
|
d92d67eece | ||
|
|
ed1fc63ce2 | ||
|
|
0e2b1675fa | ||
|
|
ee8f901918 | ||
|
|
7dc2a86b1e | ||
|
|
51699ddc12 | ||
|
|
e0675567b8 | ||
|
|
61b3102eda | ||
|
|
7cc8f2b933 | ||
|
|
d38e3eab9c | ||
|
|
4ceb06b0c5 | ||
|
|
b1a468a0ab | ||
|
|
c6755183a8 | ||
|
|
cdc9f11ac0 | ||
|
|
6ccaaee57e | ||
|
|
214ee4a75a | ||
|
|
a506d3c84a | ||
|
|
812e849769 | ||
|
|
774eef1f3f | ||
|
|
fc85c50f2f | ||
|
|
fad22eee61 | ||
|
|
e84dbd639b | ||
|
|
2dd59b4e11 | ||
|
|
bb649971dc | ||
|
|
3f82ee0330 | ||
|
|
a26fde66e6 | ||
|
|
ed9b576bde | ||
|
|
aea463f5da | ||
|
|
45e00c70ab | ||
|
|
7fc4655f13 | ||
|
|
7dcaeaa2b4 | ||
|
|
d07293bf1a | ||
|
|
38298bbeab | ||
|
|
0124ccfac1 | ||
|
|
5f62ebcd7b | ||
|
|
ac354e9d6b | ||
|
|
5572cad7f6 | ||
|
|
5fa6a7c4e4 | ||
|
|
0f9442eaf8 | ||
|
|
6094d8d92d | ||
|
|
1469710166 | ||
|
|
c1df7edddc | ||
|
|
e70f06285c | ||
|
|
c5efa9b20c | ||
|
|
29a948ece4 | ||
|
|
d9b587c67b | ||
|
|
f806ae58b6 | ||
|
|
8b5dd8dedd | ||
|
|
222e5addef | ||
|
|
21e7bae720 | ||
|
|
a13d90d794 | ||
|
|
6e900d0f26 | ||
|
|
112f1853ee | ||
|
|
7aa9e3a6d3 | ||
|
|
6e9bc6a53b | ||
|
|
12eb884b1e | ||
|
|
270afa1c00 | ||
|
|
35505f2d50 | ||
|
|
5a28ba3a74 | ||
|
|
08d9126883 | ||
|
|
e9829229b6 | ||
|
|
6d7bb7ceee | ||
|
|
60a8b06b72 | ||
|
|
c4a145836b | ||
|
|
ea37451c98 | ||
|
|
1faad84cc2 | ||
|
|
d0b6200c5b | ||
|
|
fb66760665 | ||
|
|
480f1596bb | ||
|
|
6c11e2954e | ||
|
|
6a5f6530ef | ||
|
|
a4ee88bf7f | ||
|
|
d9f1f06b15 | ||
|
|
4c00988a37 | ||
|
|
193fbe9d31 | ||
|
|
ca6b6394ef | ||
|
|
1600b94846 | ||
|
|
b5aa66224a | ||
|
|
5a14eafae5 | ||
|
|
0b11dcdb1b | ||
|
|
fc1c135e71 | ||
|
|
7cb6966335 | ||
|
|
c090cf9e3e | ||
|
|
224bce7616 | ||
|
|
7fc3afb82b | ||
|
|
affdd66065 | ||
|
|
466c5a237b | ||
|
|
827758c97f | ||
|
|
fb4a35b054 | ||
|
|
ba561ec34c | ||
|
|
a94f85794c | ||
|
|
aa408f82c6 | ||
|
|
e8045a3438 | ||
|
|
7afd678f54 | ||
|
|
77e2b98470 | ||
|
|
70e894caf4 | ||
|
|
433bd6dde1 | ||
|
|
f60ee6a839 | ||
|
|
56e6dbf0a8 | ||
|
|
7ae179764d | ||
|
|
e54cac2c7b | ||
|
|
6bc8878408 | ||
|
|
0f6d85f124 | ||
|
|
b6717c11ae | ||
|
|
3cff9ccff8 | ||
|
|
3fb5f065b8 | ||
|
|
73e397abbf | ||
|
|
38f63b02bd | ||
|
|
879e84bb34 | ||
|
|
79b709d53c | ||
|
|
97e188a619 | ||
|
|
9459b59b14 | ||
|
|
c281a0717f | ||
|
|
b274261d3e | ||
|
|
63a78f2829 | ||
|
|
31aa6df5b2 | ||
|
|
74d8f685bd | ||
|
|
43a32ef0ce | ||
|
|
4426b53f47 | ||
|
|
6902e90ca7 | ||
|
|
9aeb80ce88 | ||
|
|
60c557055f | ||
|
|
0a6020b6b8 | ||
|
|
7f85b8f2a9 | ||
|
|
5ca388d855 | ||
|
|
34d74b3bcd | ||
|
|
86ff86aa99 | ||
|
|
d9a463e465 | ||
|
|
a5d0690a81 | ||
|
|
eef4092b16 | ||
|
|
a4e89676df | ||
|
|
3f083686fe | ||
|
|
cf2ccc1eb4 | ||
|
|
43c44a085b | ||
|
|
e90dfde12e | ||
|
|
a1bb77f4f2 | ||
|
|
ef582ec1ef | ||
|
|
2c30bdb2e4 | ||
|
|
5bfbc0420a | ||
|
|
b7a3222d31 | ||
|
|
d4955af3ba | ||
|
|
bde88dda26 | ||
|
|
3f51bd5ec6 | ||
|
|
092e8c9948 | ||
|
|
c35762de98 | ||
|
|
7c43e9e27c | ||
|
|
ee07a0d181 | ||
|
|
3178587f20 | ||
|
|
b07a791d6a | ||
|
|
8b6918b4a5 | ||
|
|
c7733146b7 | ||
|
|
8f23bbd436 | ||
|
|
7ca3cca15d | ||
|
|
dd553ec7b6 | ||
|
|
1a8dd0ab32 | ||
|
|
48e0c1efbf | ||
|
|
8cdddc9f5e | ||
|
|
756c5eab3e | ||
|
|
cf8102d547 | ||
|
|
156a54f26c | ||
|
|
ad1e7772af | ||
|
|
62edf55a37 | ||
|
|
223b627619 | ||
|
|
d3bc1a6764 | ||
|
|
5157144504 | ||
|
|
cdb396408f | ||
|
|
ca7c68140a | ||
|
|
5af7afb970 | ||
|
|
fd053fc8e5 | ||
|
|
f1f01657c0 | ||
|
|
1c9f03c848 | ||
|
|
82b5ee0424 | ||
|
|
0885bf2ba4 | ||
|
|
d541b42bef | ||
|
|
29599cd59c | ||
|
|
5fff9bd3ac | ||
|
|
81b6198ee7 | ||
|
|
01f58a328e | ||
|
|
6ffef3c33b | ||
|
|
3d50d0cbba | ||
|
|
a8ec54f5a5 | ||
|
|
3c44f51671 | ||
|
|
449642fdd2 | ||
|
|
bb324258d6 | ||
|
|
693117724a | ||
|
|
008dd9d184 | ||
|
|
f171ec9932 | ||
|
|
9e6e1771d1 | ||
|
|
bde6264d11 | ||
|
|
ae61acbedd | ||
|
|
af392c8084 | ||
|
|
ce8d206004 | ||
|
|
5a15e7c048 | ||
|
|
3a360f3ede | ||
|
|
7cf2493af7 | ||
|
|
d71a0083bb | ||
|
|
6f6aeeb315 | ||
|
|
7845d25c83 | ||
|
|
3320707567 | ||
|
|
e0df2a1e60 | ||
|
|
881c0cd137 | ||
|
|
5bde9500b6 | ||
|
|
b43541ea60 | ||
|
|
339e443bca | ||
|
|
8643fb2fd5 | ||
|
|
8dcf03fb15 | ||
|
|
53c3b0c359 | ||
|
|
1701947b26 | ||
|
|
c8cb041855 | ||
|
|
032d06601e | ||
|
|
1507825c16 | ||
|
|
073fc308bb | ||
|
|
9d5aaaf989 | ||
|
|
0f6063ebe5 | ||
|
|
742c217b5f | ||
|
|
85589e1e07 | ||
|
|
6ceb58254b | ||
|
|
10e21993ce | ||
|
|
ccff653ef1 | ||
|
|
323705aced | ||
|
|
774ddaa726 | ||
|
|
e75ada4483 | ||
|
|
14e8b28b85 | ||
|
|
1f7f764fca | ||
|
|
2757e51040 | ||
|
|
1233e6bee6 | ||
|
|
e4619b303e | ||
|
|
3abb7a2a29 | ||
|
|
045c3cfdf8 | ||
|
|
4b5e1cc5fa | ||
|
|
7600a47d08 | ||
|
|
47827c09f6 | ||
|
|
c8c84ca0ad | ||
|
|
309860f9d0 | ||
|
|
2a76cf4a1f | ||
|
|
6d6b6891e1 | ||
|
|
bdd24b95d2 | ||
|
|
9ae2bee9e3 | ||
|
|
b2396de0d9 | ||
|
|
d85e3bc26f | ||
|
|
2a3220be5a | ||
|
|
92910faca0 | ||
|
|
d596474426 | ||
|
|
db471ea619 | ||
|
|
f6e30b1c9f | ||
|
|
dcc013330e | ||
|
|
d6feda8a91 | ||
|
|
310892d401 | ||
|
|
302e951bb9 | ||
|
|
6810270f51 | ||
|
|
1403f75781 | ||
|
|
660a7967f8 | ||
|
|
5ad420a6bc | ||
|
|
7403f67109 | ||
|
|
626b865c3b | ||
|
|
ebbddef0d9 | ||
|
|
a528ddfea3 | ||
|
|
9c6a4873b2 | ||
|
|
82e976ff0b | ||
|
|
5342f2cbbc | ||
|
|
c7838f744f | ||
|
|
74e41851cf | ||
|
|
f1342a305c | ||
|
|
7f926c687b | ||
|
|
496cc67390 | ||
|
|
e4b300bc71 | ||
|
|
cee20d701a | ||
|
|
0cd5f3696d | ||
|
|
3686df0f9d | ||
|
|
f58f555367 | ||
|
|
adfa14ccbe | ||
|
|
26a147e2e5 | ||
|
|
b9a74e1284 | ||
|
|
21d2b3ec7b | ||
|
|
69d94b0bf9 | ||
|
|
5e49fca60e | ||
|
|
9babff17d1 | ||
|
|
be86983f00 | ||
|
|
907bb4dc52 | ||
|
|
9a34a3700d | ||
|
|
fdb468abf4 | ||
|
|
0de0326778 | ||
|
|
30db58b94f | ||
|
|
8e40b1013b | ||
|
|
aa96521696 | ||
|
|
17f40d58ac | ||
|
|
bdcdda4e9c | ||
|
|
c36d57f962 | ||
|
|
542ac4bfc0 | ||
|
|
68a684f3d6 | ||
|
|
b9bcb372f7 | ||
|
|
3d94451124 | ||
|
|
0af952d66c | ||
|
|
e46bc1ee36 | ||
|
|
5d297be871 | ||
|
|
6c0bc90f96 | ||
|
|
db0b6f77e3 | ||
|
|
7f42ab68d2 | ||
|
|
c4f6e81c56 | ||
|
|
3bf595959b | ||
|
|
5af1e058b0 | ||
|
|
ec62d1597b | ||
|
|
fa06a2935b | ||
|
|
2cdd521a10 | ||
|
|
90ac853e4f | ||
|
|
007fe0c0af | ||
|
|
f3afcd351a | ||
|
|
8eb161171e | ||
|
|
413f829107 | ||
|
|
7f09474f33 | ||
|
|
28386c58db | ||
|
|
e79aae7925 | ||
|
|
fabadf998b | ||
|
|
2f0d158ed8 | ||
|
|
b5f08d4e4c | ||
|
|
fce10da7f6 | ||
|
|
d59937dba7 | ||
|
|
0eb2bfab12 | ||
|
|
bb4111671f | ||
|
|
5e50d791fd | ||
|
|
cfaf0712d6 | ||
|
|
9cb2d694fe | ||
|
|
9f4c6b30d8 | ||
|
|
b9055a5d22 | ||
|
|
aa0d1e7f61 | ||
|
|
35a8cb1d36 | ||
|
|
92ba8a0ca3 | ||
|
|
acbc02162f | ||
|
|
8da777b6f4 | ||
|
|
e62ec1d993 | ||
|
|
4fa11b4c79 | ||
|
|
c9dba873ee | ||
|
|
3e2e897f34 | ||
|
|
9658fba5aa | ||
|
|
1c00c39eac | ||
|
|
2d3f186c18 | ||
|
|
983a471e6f | ||
|
|
7a228f553c | ||
|
|
007dfa9519 | ||
|
|
f3a74b1f46 | ||
|
|
4a76b620e7 | ||
|
|
25210d031d | ||
|
|
87b55fd4cf | ||
|
|
b4430ac76f | ||
|
|
5f9aa78b72 | ||
|
|
7537f6bd5c | ||
|
|
83dee5e554 | ||
|
|
036b4495e6 | ||
|
|
31cd36fcc1 | ||
|
|
0a2aaf3260 | ||
|
|
6e2e90120a | ||
|
|
23f95d6ebd | ||
|
|
56dc1096d9 | ||
|
|
9dd203f85a | ||
|
|
adac9cf79d | ||
|
|
efd2ba04c5 | ||
|
|
a9055e216d | ||
|
|
f64130029b | ||
|
|
6d172bac82 | ||
|
|
354cba5690 | ||
|
|
e65cde9675 | ||
|
|
fbd2fbb6a6 | ||
|
|
01bf64083a | ||
|
|
103856121d | ||
|
|
8a798c7e3f | ||
|
|
beeec5c39e | ||
|
|
6d43045d79 | ||
|
|
88ea94f5b0 | ||
|
|
3b8d333f8e | ||
|
|
3a06982502 | ||
|
|
b820b46042 | ||
|
|
fab799f177 | ||
|
|
5eaf9b9157 | ||
|
|
1eed3c53c8 | ||
|
|
90729a7a95 | ||
|
|
d450f6df10 | ||
|
|
7aa2bcf761 | ||
|
|
a7a86f46c3 | ||
|
|
17e30aff60 | ||
|
|
66008e47f3 | ||
|
|
56788b1e5b | ||
|
|
b72371487a | ||
|
|
7656b4189e | ||
|
|
8e6731c102 | ||
|
|
e86fa40fe4 | ||
|
|
f0e728a1ed | ||
|
|
bb076eb439 | ||
|
|
2f0b16367a | ||
|
|
aa33124e18 | ||
|
|
42f404c80a | ||
|
|
5056fddd40 | ||
|
|
2296202ea1 | ||
|
|
c034e9b0fa | ||
|
|
2d45119a98 | ||
|
|
63be4f1ab5 | ||
|
|
6d2259100e | ||
|
|
142af6e7b6 | ||
|
|
5c1e009188 | ||
|
|
27b2cb84d6 | ||
|
|
8db87e5497 | ||
|
|
e601a0d564 | ||
|
|
07491108cd | ||
|
|
42ab17de1f | ||
|
|
2d14174f61 | ||
|
|
a19ccc9263 | ||
|
|
956880aa59 | ||
|
|
b2b54db409 | ||
|
|
32d5188eef | ||
|
|
46dab7f531 | ||
|
|
c898a9ebbc | ||
|
|
8a13b05c20 | ||
|
|
86ea23fe39 | ||
|
|
a284dd74dd | ||
|
|
6a0075291c | ||
|
|
f542bc70a1 | ||
|
|
270e59d9ea | ||
|
|
0d97a604f8 | ||
|
|
f6078fc232 | ||
|
|
6f5d95031c | ||
|
|
4e26defdca | ||
|
|
cda8fa7efd | ||
|
|
fd050f2a8f | ||
|
|
e53d41dcec | ||
|
|
a1eb15dabb | ||
|
|
eb4bdafbea | ||
|
|
fea2330534 | ||
|
|
5e37469ea9 | ||
|
|
e027479bb1 | ||
|
|
1597e869c1 | ||
|
|
862399d8ec | ||
|
|
f6f85f8f9d | ||
|
|
e22d7ca801 | ||
|
|
c382c1d5f6 | ||
|
|
f7618ed6b0 | ||
|
|
d1295b7c50 | ||
|
|
a162a54a58 | ||
|
|
794db0ac6a | ||
|
|
e9fb9b856f | ||
|
|
66bca11d36 | ||
|
|
86e87f0d47 | ||
|
|
fadfc5d81d | ||
|
|
fc39ff1e4d | ||
|
|
82ccfc66e0 | ||
|
|
890bad1c39 | ||
|
|
9c458885f1 | ||
|
|
d2aed0dc72 | ||
|
|
3dbcb5d7da | ||
|
|
57a1a8b39e | ||
|
|
ab81c04569 | ||
|
|
0c32be3bea | ||
|
|
81d43fbf6e | ||
|
|
96f441de40 | ||
|
|
0e95caaee9 | ||
|
|
7697a12b42 | ||
|
|
94245a9ba4 | ||
|
|
b084814aea | ||
|
|
cce74246ee | ||
|
|
a3420b8c67 | ||
|
|
e1bb17ee9e | ||
|
|
52983f60b7 | ||
|
|
1f053fd85d | ||
|
|
a989d121d3 | ||
|
|
50d2406423 | ||
|
|
059d2d0a5b | ||
|
|
621bef30b5 | ||
|
|
5f4d3dc730 | ||
|
|
8fa9aece63 | ||
|
|
2f1a022e2a | ||
|
|
4815cd29bc | ||
|
|
e49bfaf5d7 | ||
|
|
b13915b76f | ||
|
|
e2a57dc43b | ||
|
|
7222224b40 | ||
|
|
02ff475b84 | ||
|
|
09cd8d0db9 | ||
|
|
36f1a0c53b | ||
|
|
0b0e94e045 | ||
|
|
20ca6edf81 | ||
|
|
1990f8c6df | ||
|
|
6e9dbf863f | ||
|
|
fa921d77f1 | ||
|
|
ff854d481d | ||
|
|
4ce491fe48 | ||
|
|
493bae7eb6 | ||
|
|
ae5532aa36 | ||
|
|
a1eae6413a | ||
|
|
ee52bf1fbf | ||
|
|
2ff0bd6b44 | ||
|
|
a385233b7d | ||
|
|
f5648a415d | ||
|
|
556fb18953 | ||
|
|
a482f78739 | ||
|
|
4a580ce972 | ||
|
|
e07558237f | ||
|
|
fb3c70a1bc | ||
|
|
cba4d60895 | ||
|
|
8b655ef2b9 | ||
|
|
0188418055 | ||
|
|
72334c42d0 | ||
|
|
0638ff3c21 | ||
|
|
b64318d9e8 | ||
|
|
0f5b1b5157 | ||
|
|
3c4ae46f50 | ||
|
|
c158b1aeeb | ||
|
|
684d92c497 | ||
|
|
bbd9595ec0 | ||
|
|
bbebb3e301 | ||
|
|
9d25181d1d | ||
|
|
7ba1f366ba | ||
|
|
37c6b920f9 | ||
|
|
49db81dac8 | ||
|
|
a9e90ec19c | ||
|
|
2ad60507b7 | ||
|
|
12059ee3db | ||
|
|
de56544ca3 | ||
|
|
065c7facb6 | ||
|
|
630c92c139 | ||
|
|
e11d452d91 | ||
|
|
99c7f7bd8a | ||
|
|
8af3a0eb5b | ||
|
|
5f7950b474 | ||
|
|
df9e2dec28 | ||
|
|
a0f271545a | ||
|
|
aa2bc9f118 | ||
|
|
b22ae87022 | ||
|
|
79e79079bc | ||
|
|
1811ebdee4 | ||
|
|
137f3f3e24 | ||
|
|
ed1d1e77c0 | ||
|
|
8c36dd1caa | ||
|
|
57bfe72486 | ||
|
|
75f66b0246 | ||
|
|
ce93d54aa7 | ||
|
|
39dbe0eac5 | ||
|
|
7282044f80 | ||
|
|
d77c37c0b0 | ||
|
|
e362cbbca5 | ||
|
|
118544926b | ||
|
|
d4bb0a0a30 | ||
|
|
fe5e35d1a9 | ||
|
|
60a6ae2caa | ||
|
|
80338d36aa | ||
|
|
f0d2c242e8 | ||
|
|
559f83d99c | ||
|
|
d3a751ee6c | ||
|
|
fb70a166fa | ||
|
|
c12457b707 | ||
|
|
3e53d73d56 | ||
|
|
80338c5e98 | ||
|
|
249cd8ad19 | ||
|
|
ccdff46370 | ||
|
|
91679b5cc0 | ||
|
|
6953edf59e | ||
|
|
b91c77ec92 | ||
|
|
3ac0b185d1 | ||
|
|
1e675cabb5 | ||
|
|
5f44965c2c | ||
|
|
f080929296 | ||
|
|
f055658eba | ||
|
|
e430c747fe | ||
|
|
ca62b1db36 | ||
|
|
38569b7057 | ||
|
|
203244090f | ||
|
|
2bed722045 | ||
|
|
13f3a52760 | ||
|
|
16b9827c70 | ||
|
|
0fc352d7fc | ||
|
|
8a2bee11d4 | ||
|
|
485f7d16ff | ||
|
|
46fdc94cb8 | ||
|
|
261f7fb76c | ||
|
|
18d9258907 | ||
|
|
9d7fb8ab80 | ||
|
|
3730a78e5a | ||
|
|
7cdd0907e8 | ||
|
|
3586f73f30 | ||
|
|
752ccc6beb | ||
|
|
f577476c81 | ||
|
|
49ae424698 | ||
|
|
d4fd19522b | ||
|
|
5c047e4afd | ||
|
|
6576141f54 | ||
|
|
926e807020 | ||
|
|
d91847c6c5 | ||
|
|
0abd88270c | ||
|
|
806c4e51c5 | ||
|
|
6520783fe9 | ||
|
|
48c8a3a4a5 | ||
|
|
e0c839f78c | ||
|
|
1ba362bafe | ||
|
|
b5d55ead4a | ||
|
|
4f879ccc66 | ||
|
|
cd9e0f7b5b | ||
|
|
780644eeae | ||
|
|
71f081da20 | ||
|
|
11c61bcf42 | ||
|
|
402a1584d7 | ||
|
|
99d61a0193 | ||
|
|
5ddb200a75 | ||
|
|
faa247dbda | ||
|
|
6d1cec3c42 | ||
|
|
529df84273 | ||
|
|
e0e21eedd6 | ||
|
|
4356ffbe9b | ||
|
|
be1366b785 | ||
|
|
3dc7e02ed0 | ||
|
|
d67d638a6b | ||
|
|
7b36036455 | ||
|
|
1b58560acf | ||
|
|
1627c41f84 | ||
|
|
4395520a28 | ||
|
|
8c52f30a71 | ||
|
|
46316ebffa | ||
|
|
0b04f60b6c | ||
|
|
20b822d072 | ||
|
|
ca7642cc91 | ||
|
|
68009c85a5 | ||
|
|
1c7c64c4aa | ||
|
|
b05966d30b | ||
|
|
ea90f6a596 | ||
|
|
f1e43b2593 | ||
|
|
748d18321d | ||
|
|
ae84919c39 | ||
|
|
b23221702e | ||
|
|
4d5b096230 | ||
|
|
7caf7d1b31 | ||
|
|
6107f52d07 | ||
|
|
f4fb7a89e5 | ||
|
|
5439066f4d | ||
|
|
7c18f3d8b4 | ||
|
|
63af81666b | ||
|
|
c0a6153a43 | ||
|
|
df334caca6 | ||
|
|
ffb3ec0477 | ||
|
|
3a97edd0d5 | ||
|
|
ab1d1c1273 | ||
|
|
0fb39edae4 | ||
|
|
3a977a8e1f | ||
|
|
081979de24 | ||
|
|
23fe189797 | ||
|
|
e9d429b9b8 | ||
|
|
99202c85b6 | ||
|
|
d5c3d8f84e | ||
|
|
8f442992e6 | ||
|
|
39820c8ac1 | ||
|
|
0c8b10af99 | ||
|
|
8e072492b7 | ||
|
|
88d6307ce0 | ||
|
|
2cc516f9e5 | ||
|
|
ab6ea71695 | ||
|
|
6280323cb1 | ||
|
|
17c8e7e1bd | ||
|
|
f60fb6f8a9 | ||
|
|
3eebbce2d4 | ||
|
|
e92a94a24d | ||
|
|
7c7c073ae4 | ||
|
|
c009a40749 | ||
|
|
5e85b803e0 | ||
|
|
256d3c5ba1 | ||
|
|
bd048a8989 | ||
|
|
f6b4231500 | ||
|
|
bda06f30b3 | ||
|
|
38f2ba3984 | ||
|
|
1a7d897bdc | ||
|
|
c74e7430ef | ||
|
|
2467bbc0f0 | ||
|
|
ea665e02da | ||
|
|
358e05d544 | ||
|
|
aab5725d82 | ||
|
|
e94a1cd421 | ||
|
|
73c1a1b208 | ||
|
|
0526c88ce0 | ||
|
|
a2e9056a00 | ||
|
|
fd4ac60908 | ||
|
|
330e4c67f3 | ||
|
|
5d840bd473 | ||
|
|
54e3f3eba1 | ||
|
|
d79111fce4 | ||
|
|
93c3c7b9d8 | ||
|
|
410d236f89 | ||
|
|
9a8071c314 | ||
|
|
80df0efccd | ||
|
|
3f1f4c7596 | ||
|
|
04ac688be4 | ||
|
|
ace83172ff | ||
|
|
e8b864b515 |
48
.dockerignore
Normal file
48
.dockerignore
Normal file
@@ -0,0 +1,48 @@
|
||||
# Node.js dependencies
|
||||
node_modules
|
||||
internalsite/node_modules
|
||||
|
||||
# Go build artifacts and binaries
|
||||
build
|
||||
dist
|
||||
*.exe
|
||||
beszel-agent
|
||||
beszel_data*
|
||||
pb_data
|
||||
data
|
||||
temp
|
||||
|
||||
# Development and IDE files
|
||||
.vscode
|
||||
.idea*
|
||||
*.swc
|
||||
__debug_*
|
||||
|
||||
# Git and version control
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Documentation and supplemental files
|
||||
*.md
|
||||
supplemental
|
||||
freebsd-port
|
||||
|
||||
# Test files (exclude from production builds)
|
||||
*_test.go
|
||||
coverage
|
||||
|
||||
# Docker files
|
||||
dockerfile_*
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.bak
|
||||
*.log
|
||||
|
||||
# OS specific files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# .NET build artifacts
|
||||
agent/lhm/obj
|
||||
agent/lhm/bin
|
||||
47
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
47
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,8 +1,19 @@
|
||||
name: 🐛 Bug report
|
||||
description: Report a new bug or issue.
|
||||
title: '[Bug]: '
|
||||
labels: ['bug']
|
||||
labels: ['bug', "needs confirmation"]
|
||||
body:
|
||||
- type: dropdown
|
||||
id: component
|
||||
attributes:
|
||||
label: Component
|
||||
description: Which part of Beszel is this about?
|
||||
options:
|
||||
- Hub
|
||||
- Agent
|
||||
- Hub & Agent
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
@@ -43,6 +54,39 @@ body:
|
||||
3. Pour it into a cup.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: category
|
||||
attributes:
|
||||
label: Category
|
||||
description: Which category does this relate to most?
|
||||
options:
|
||||
- Metrics
|
||||
- Charts & Visualization
|
||||
- Settings & Configuration
|
||||
- Notifications & Alerts
|
||||
- Authentication
|
||||
- Installation
|
||||
- Performance
|
||||
- UI / UX
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: metrics
|
||||
attributes:
|
||||
label: Affected Metrics
|
||||
description: If applicable, which specific metric does this relate to most?
|
||||
options:
|
||||
- CPU
|
||||
- Memory
|
||||
- Storage
|
||||
- Network
|
||||
- Containers
|
||||
- GPU
|
||||
- Sensors
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: system
|
||||
attributes:
|
||||
@@ -61,7 +105,6 @@ body:
|
||||
id: install-method
|
||||
attributes:
|
||||
label: Installation method
|
||||
default: 0
|
||||
options:
|
||||
- Docker
|
||||
- Binary
|
||||
|
||||
60
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
60
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,8 +1,19 @@
|
||||
name: 🚀 Feature request
|
||||
description: Request a new feature or change.
|
||||
title: "[Feature]: "
|
||||
labels: ["enhancement"]
|
||||
labels: ["enhancement", "needs review"]
|
||||
body:
|
||||
- type: dropdown
|
||||
id: component
|
||||
attributes:
|
||||
label: Component
|
||||
description: Which part of Beszel is this about?
|
||||
options:
|
||||
- Hub
|
||||
- Agent
|
||||
- Hub & Agent
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Before submitting, please search existing [issues](https://github.com/henrygd/beszel/issues) and [discussions](https://github.com/henrygd/beszel/discussions) (including closed).
|
||||
@@ -11,8 +22,55 @@ body:
|
||||
label: Describe the feature you would like to see
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: Motivation / Use Case
|
||||
description: Why do you want this feature? What problem does it solve?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe how you would like to see this feature implemented
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: Please attach any relevant screenshots, such as images from your current solution or similar implementations.
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: category
|
||||
attributes:
|
||||
label: Category
|
||||
description: Which category does this relate to most?
|
||||
options:
|
||||
- Metrics
|
||||
- Charts & Visualization
|
||||
- Settings & Configuration
|
||||
- Notifications & Alerts
|
||||
- Authentication
|
||||
- Installation
|
||||
- Performance
|
||||
- UI / UX
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: metrics
|
||||
attributes:
|
||||
label: Affected Metrics
|
||||
description: If applicable, which specific metric does this relate to most?
|
||||
options:
|
||||
- CPU
|
||||
- Memory
|
||||
- Storage
|
||||
- Network
|
||||
- Containers
|
||||
- GPU
|
||||
- Sensors
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
33
.github/pull_request_template.md
vendored
Normal file
33
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
## 📃 Description
|
||||
|
||||
A short description of the pull request changes should go here and the sections below should list in detail all changes. You can remove the sections you don't need.
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
Add a link to the PR for [documentation](https://github.com/henrygd/beszel-docs) changes.
|
||||
|
||||
## 🪵 Changelog
|
||||
|
||||
### ➕ Added
|
||||
|
||||
- one
|
||||
- two
|
||||
|
||||
### ✏️ Changed
|
||||
|
||||
- one
|
||||
- two
|
||||
|
||||
### 🔧 Fixed
|
||||
|
||||
- one
|
||||
- two
|
||||
|
||||
### 🗑️ Removed
|
||||
|
||||
- one
|
||||
- two
|
||||
|
||||
## 📷 Screenshots
|
||||
|
||||
If this PR has any UI/UX changes it's strongly suggested you add screenshots here.
|
||||
53
.github/workflows/docker-images.yml
vendored
53
.github/workflows/docker-images.yml
vendored
@@ -3,7 +3,7 @@ name: Make docker images
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -13,29 +13,49 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- image: henrygd/beszel
|
||||
context: ./beszel
|
||||
dockerfile: ./beszel/dockerfile_Hub
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_hub
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
|
||||
- image: henrygd/beszel-agent
|
||||
context: ./beszel
|
||||
dockerfile: ./beszel/dockerfile_Agent
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
|
||||
- image: henrygd/beszel-agent-nvidia
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent_nvidia
|
||||
platforms: linux/amd64
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
|
||||
- image: ghcr.io/${{ github.repository }}/beszel
|
||||
context: ./beszel
|
||||
dockerfile: ./beszel/dockerfile_Hub
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_hub
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
|
||||
- image: ghcr.io/${{ github.repository }}/beszel-agent
|
||||
context: ./beszel
|
||||
dockerfile: ./beszel/dockerfile_Agent
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
|
||||
- image: ghcr.io/${{ github.repository }}/beszel-agent-nvidia
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent_nvidia
|
||||
platforms: linux/amd64
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -48,10 +68,10 @@ jobs:
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --no-save --cwd ./beszel/site
|
||||
run: bun install --no-save --cwd ./internal/site
|
||||
|
||||
- name: Build site
|
||||
run: bun run --cwd ./beszel/site build
|
||||
run: bun run --cwd ./internal/site build
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
@@ -65,6 +85,7 @@ jobs:
|
||||
with:
|
||||
images: ${{ matrix.image }}
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
@@ -72,7 +93,9 @@ jobs:
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
password_secret_exists: ${{ secrets[matrix.password_secret] != '' && 'true' || 'false' }}
|
||||
if: github.event_name != 'pull_request' && env.password_secret_exists == 'true'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ matrix.username || secrets[matrix.username_secret] }}
|
||||
@@ -84,9 +107,9 @@ jobs:
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: '${{ matrix.context }}'
|
||||
context: "${{ matrix.context }}"
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: ${{ github.ref_type == 'tag' }}
|
||||
platforms: ${{ matrix.platforms || 'linux/amd64,linux/arm64,linux/arm/v7' }}
|
||||
push: ${{ github.ref_type == 'tag' && secrets[matrix.password_secret] != '' }}
|
||||
tags: ${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
|
||||
43
.github/workflows/inactivity-actions.yml
vendored
Normal file
43
.github/workflows/inactivity-actions.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: 'Issue and PR Maintenance'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # runs at midnight UTC
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
close-stale:
|
||||
name: Close Stale Issues
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Close Stale Issues
|
||||
uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Messaging
|
||||
stale-issue-message: >
|
||||
👋 This issue has been automatically marked as stale due to inactivity.
|
||||
If this issue is still relevant, please comment to keep it open.
|
||||
Without activity, it will be closed in 7 days.
|
||||
|
||||
close-issue-message: >
|
||||
🔒 This issue has been automatically closed due to prolonged inactivity.
|
||||
Feel free to open a new issue if you have further questions or concerns.
|
||||
|
||||
# Timing
|
||||
days-before-issue-stale: 14
|
||||
days-before-issue-close: 7
|
||||
|
||||
# Labels
|
||||
stale-issue-label: 'stale'
|
||||
remove-stale-when-updated: true
|
||||
only-issue-labels: 'awaiting-requester'
|
||||
|
||||
# Exemptions
|
||||
exempt-assignees: true
|
||||
exempt-milestones: true
|
||||
82
.github/workflows/label-from-dropdown.yml
vendored
Normal file
82
.github/workflows/label-from-dropdown.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
name: Label issues from dropdowns
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
label_from_dropdown:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: Apply labels based on dropdown choices
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
|
||||
const issueNumber = context.issue.number;
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
// Get the issue body
|
||||
const body = context.payload.issue.body;
|
||||
|
||||
// Helper to find dropdown value in the body (assuming markdown format)
|
||||
function extractSectionValue(heading) {
|
||||
const regex = new RegExp(`### ${heading}\\s+([\\s\\S]*?)(?:\\n###|$)`, 'i');
|
||||
const match = body.match(regex);
|
||||
if (match) {
|
||||
// Get the first non-empty line after the heading
|
||||
const lines = match[1].split('\n').map(l => l.trim()).filter(Boolean);
|
||||
return lines[0] || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract dropdown selections
|
||||
const category = extractSectionValue('Category');
|
||||
const metrics = extractSectionValue('Affected Metrics');
|
||||
const component = extractSectionValue('Component');
|
||||
|
||||
// Build labels to add
|
||||
let labelsToAdd = [];
|
||||
if (category) labelsToAdd.push(category);
|
||||
if (metrics) labelsToAdd.push(metrics);
|
||||
if (component) labelsToAdd.push(component);
|
||||
|
||||
// Get existing labels in the repo
|
||||
const { data: existingLabels } = await github.rest.issues.listLabelsForRepo({
|
||||
owner,
|
||||
repo,
|
||||
per_page: 100
|
||||
});
|
||||
const existingLabelNames = existingLabels.map(l => l.name);
|
||||
|
||||
// Find labels that need to be created
|
||||
const labelsToCreate = labelsToAdd.filter(label => !existingLabelNames.includes(label));
|
||||
|
||||
// Create missing labels (with a default color)
|
||||
for (const label of labelsToCreate) {
|
||||
try {
|
||||
await github.rest.issues.createLabel({
|
||||
owner,
|
||||
repo,
|
||||
name: label,
|
||||
color: 'ededed' // light gray, you can pick any hex color
|
||||
});
|
||||
} catch (e) {
|
||||
// Ignore if label already exists (race condition), otherwise rethrow
|
||||
if (!e || e.status !== 422) throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Now apply all labels (they all exist now)
|
||||
if (labelsToAdd.length > 0) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
labels: labelsToAdd
|
||||
});
|
||||
}
|
||||
24
.github/workflows/release.yml
vendored
24
.github/workflows/release.yml
vendored
@@ -3,7 +3,7 @@ name: Make release and binaries
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
- "v*"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -21,22 +21,34 @@ jobs:
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --no-save --cwd ./beszel/site
|
||||
run: bun install --no-save --cwd ./internal/site
|
||||
|
||||
- name: Build site
|
||||
run: bun run --cwd ./beszel/site build
|
||||
run: bun run --cwd ./internal/site build
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '^1.22.1'
|
||||
go-version: "^1.22.1"
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: "9.0.x"
|
||||
|
||||
- name: Build .NET LHM executable for Windows sensors
|
||||
run: |
|
||||
dotnet build -c Release ./agent/lhm/beszel_lhm.csproj
|
||||
shell: bash
|
||||
|
||||
- name: GoReleaser beszel
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
workdir: ./beszel
|
||||
workdir: ./
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN || secrets.GITHUB_TOKEN }}
|
||||
WINGET_TOKEN: ${{ secrets.WINGET_TOKEN }}
|
||||
IS_FORK: ${{ github.repository_owner != 'henrygd' }}
|
||||
|
||||
33
.github/workflows/vulncheck.yml
vendored
Normal file
33
.github/workflows/vulncheck.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# https://github.com/minio/minio/blob/master/.github/workflows/vulncheck.yml
|
||||
|
||||
name: VulnCheck
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
vulncheck:
|
||||
name: VulnCheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.25.x
|
||||
# cached: false
|
||||
- name: Get official govulncheck
|
||||
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
shell: bash
|
||||
- name: Run govulncheck
|
||||
run: govulncheck -show verbose ./...
|
||||
shell: bash
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -8,12 +8,15 @@ beszel_data
|
||||
beszel_data*
|
||||
dist
|
||||
*.exe
|
||||
beszel/cmd/hub/hub
|
||||
beszel/cmd/agent/agent
|
||||
internal/cmd/hub/hub
|
||||
internal/cmd/agent/agent
|
||||
node_modules
|
||||
beszel/build
|
||||
build
|
||||
*timestamp*
|
||||
.swc
|
||||
beszel/site/src/locales/**/*.ts
|
||||
internal/site/src/locales/**/*.ts
|
||||
*.bak
|
||||
__debug_*
|
||||
agent/lhm/obj
|
||||
agent/lhm/bin
|
||||
dockerfile_agent_dev
|
||||
|
||||
237
.goreleaser.yml
Normal file
237
.goreleaser.yml
Normal file
@@ -0,0 +1,237 @@
|
||||
version: 2
|
||||
|
||||
project_name: beszel
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
||||
builds:
|
||||
- id: beszel
|
||||
binary: beszel
|
||||
main: internal/cmd/hub/hub.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
- arm
|
||||
|
||||
- id: beszel-agent
|
||||
binary: beszel-agent
|
||||
main: internal/cmd/agent/agent.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- freebsd
|
||||
- openbsd
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
- arm
|
||||
- mips64
|
||||
- riscv64
|
||||
- mipsle
|
||||
- mips
|
||||
- ppc64le
|
||||
gomips:
|
||||
- hardfloat
|
||||
- softfloat
|
||||
ignore:
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
- goos: openbsd
|
||||
goarch: arm
|
||||
- goos: linux
|
||||
goarch: mips64
|
||||
gomips: softfloat
|
||||
- goos: linux
|
||||
goarch: mipsle
|
||||
gomips: hardfloat
|
||||
- goos: linux
|
||||
goarch: mips
|
||||
gomips: hardfloat
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: darwin
|
||||
goarch: riscv64
|
||||
- goos: windows
|
||||
goarch: riscv64
|
||||
|
||||
archives:
|
||||
- id: beszel-agent
|
||||
formats: [tar.gz]
|
||||
ids:
|
||||
- beszel-agent
|
||||
name_template: >-
|
||||
{{ .Binary }}_
|
||||
{{- .Os }}_
|
||||
{{- .Arch }}
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
formats: [zip]
|
||||
|
||||
- id: beszel
|
||||
formats: [tar.gz]
|
||||
ids:
|
||||
- beszel
|
||||
name_template: >-
|
||||
{{ .Binary }}_
|
||||
{{- .Os }}_
|
||||
{{- .Arch }}
|
||||
|
||||
nfpms:
|
||||
- id: beszel-agent
|
||||
package_name: beszel-agent
|
||||
description: |-
|
||||
Agent for Beszel
|
||||
Beszel is a lightweight server monitoring platform that includes Docker
|
||||
statistics, historical data, and alert functions. It has a friendly web
|
||||
interface, simple configuration, and is ready to use out of the box.
|
||||
It supports automatic backup, multi-user, OAuth authentication, and
|
||||
API access.
|
||||
maintainer: henrygd <hank@henrygd.me>
|
||||
section: net
|
||||
ids:
|
||||
- beszel-agent
|
||||
formats:
|
||||
- deb
|
||||
contents:
|
||||
- src: ./supplemental/debian/beszel-agent.service
|
||||
dst: lib/systemd/system/beszel-agent.service
|
||||
packager: deb
|
||||
- src: ./supplemental/debian/copyright
|
||||
dst: usr/share/doc/beszel-agent/copyright
|
||||
packager: deb
|
||||
- src: ./supplemental/debian/lintian-overrides
|
||||
dst: usr/share/lintian/overrides/beszel-agent
|
||||
packager: deb
|
||||
scripts:
|
||||
postinstall: ./supplemental/debian/postinstall.sh
|
||||
preremove: ./supplemental/debian/prerm.sh
|
||||
postremove: ./supplemental/debian/postrm.sh
|
||||
deb:
|
||||
predepends:
|
||||
- adduser
|
||||
- debconf
|
||||
scripts:
|
||||
templates: ./supplemental/debian/templates
|
||||
# Currently broken due to a bug in goreleaser
|
||||
# https://github.com/goreleaser/goreleaser/issues/5487
|
||||
#config: ./supplemental/debian/config.sh
|
||||
|
||||
scoops:
|
||||
- ids: [beszel-agent]
|
||||
name: beszel-agent
|
||||
repository:
|
||||
owner: henrygd
|
||||
name: beszel-scoops
|
||||
homepage: "https://beszel.dev"
|
||||
description: "Agent for Beszel, a lightweight server monitoring platform."
|
||||
license: MIT
|
||||
skip_upload: '{{ if eq (tolower .Env.IS_FORK) "true" }}true{{ else }}auto{{ end }}'
|
||||
|
||||
# # Needs choco installed, so doesn't build on linux / default gh workflow :(
|
||||
# chocolateys:
|
||||
# - title: Beszel Agent
|
||||
# ids: [beszel-agent]
|
||||
# package_source_url: https://github.com/henrygd/beszel-chocolatey
|
||||
# owners: henrygd
|
||||
# authors: henrygd
|
||||
# summary: 'Agent for Beszel, a lightweight server monitoring platform.'
|
||||
# description: |
|
||||
# Beszel is a lightweight server monitoring platform that includes Docker statistics, historical data, and alert functions.
|
||||
|
||||
# It has a friendly web interface, simple configuration, and is ready to use out of the box. It supports automatic backup, multi-user, OAuth authentication, and API access.
|
||||
# license_url: https://github.com/henrygd/beszel/blob/main/LICENSE
|
||||
# project_url: https://beszel.dev
|
||||
# project_source_url: https://github.com/henrygd/beszel
|
||||
# docs_url: https://beszel.dev/guide/getting-started
|
||||
# icon_url: https://cdn.jsdelivr.net/gh/selfhst/icons/png/beszel.png
|
||||
# bug_tracker_url: https://github.com/henrygd/beszel/issues
|
||||
# copyright: 2025 henrygd
|
||||
# tags: foss cross-platform admin monitoring
|
||||
# require_license_acceptance: false
|
||||
# release_notes: 'https://github.com/henrygd/beszel/releases/tag/v{{ .Version }}'
|
||||
|
||||
brews:
|
||||
- ids: [beszel-agent]
|
||||
name: beszel-agent
|
||||
repository:
|
||||
owner: henrygd
|
||||
name: homebrew-beszel
|
||||
homepage: "https://beszel.dev"
|
||||
description: "Agent for Beszel, a lightweight server monitoring platform."
|
||||
license: MIT
|
||||
skip_upload: '{{ if eq (tolower .Env.IS_FORK) "true" }}true{{ else }}auto{{ end }}'
|
||||
extra_install: |
|
||||
(bin/"beszel-agent-launcher").write <<~EOS
|
||||
#!/bin/bash
|
||||
set -a
|
||||
if [ -f "$HOME/.config/beszel/beszel-agent.env" ]; then
|
||||
source "$HOME/.config/beszel/beszel-agent.env"
|
||||
fi
|
||||
set +a
|
||||
exec #{bin}/beszel-agent "$@"
|
||||
EOS
|
||||
(bin/"beszel-agent-launcher").chmod 0755
|
||||
service: |
|
||||
run ["#{bin}/beszel-agent-launcher"]
|
||||
log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
|
||||
error_log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
|
||||
keep_alive true
|
||||
restart_delay 5
|
||||
process_type :background
|
||||
|
||||
winget:
|
||||
- ids: [beszel-agent]
|
||||
name: beszel-agent
|
||||
package_identifier: henrygd.beszel-agent
|
||||
publisher: henrygd
|
||||
license: MIT
|
||||
license_url: "https://github.com/henrygd/beszel/blob/main/LICENSE"
|
||||
copyright: "2025 henrygd"
|
||||
homepage: "https://beszel.dev"
|
||||
release_notes_url: "https://github.com/henrygd/beszel/releases/tag/v{{ .Version }}"
|
||||
publisher_support_url: "https://github.com/henrygd/beszel/issues"
|
||||
short_description: "Agent for Beszel, a lightweight server monitoring platform."
|
||||
skip_upload: '{{ if eq (tolower .Env.IS_FORK) "true" }}true{{ else }}auto{{ end }}'
|
||||
description: |
|
||||
Beszel is a lightweight server monitoring platform that includes Docker
|
||||
statistics, historical data, and alert functions. It has a friendly web
|
||||
interface, simple configuration, and is ready to use out of the box.
|
||||
It supports automatic backup, multi-user, OAuth authentication, and
|
||||
API access.
|
||||
tags:
|
||||
- homelab
|
||||
- monitoring
|
||||
- self-hosted
|
||||
repository:
|
||||
owner: henrygd
|
||||
name: beszel-winget
|
||||
branch: henrygd.beszel-agent-{{ .Version }}
|
||||
token: "{{ .Env.WINGET_TOKEN }}"
|
||||
# pull_request:
|
||||
# enabled: true
|
||||
# draft: false
|
||||
# base:
|
||||
# owner: microsoft
|
||||
# name: winget-pkgs
|
||||
# branch: master
|
||||
|
||||
release:
|
||||
draft: true
|
||||
|
||||
changelog:
|
||||
disable: true
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
102
Makefile
Normal file
102
Makefile
Normal file
@@ -0,0 +1,102 @@
|
||||
# Default OS/ARCH values
|
||||
OS ?= $(shell go env GOOS)
|
||||
ARCH ?= $(shell go env GOARCH)
|
||||
# Skip building the web UI if true
|
||||
SKIP_WEB ?= false
|
||||
|
||||
# Set executable extension based on target OS
|
||||
EXE_EXT := $(if $(filter windows,$(OS)),.exe,)
|
||||
|
||||
.PHONY: tidy build-agent build-hub build-hub-dev build clean lint dev-server dev-agent dev-hub dev generate-locales
|
||||
.DEFAULT_GOAL := build
|
||||
|
||||
clean:
|
||||
go clean
|
||||
rm -rf ./build
|
||||
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
test: export GOEXPERIMENT=synctest
|
||||
test:
|
||||
go test -tags=testing ./...
|
||||
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
build-web-ui:
|
||||
@if command -v bun >/dev/null 2>&1; then \
|
||||
bun install --cwd ./internal/site && \
|
||||
bun run --cwd ./internal/site build; \
|
||||
else \
|
||||
npm install --prefix ./internal/site && \
|
||||
npm run --prefix ./internal/site build; \
|
||||
fi
|
||||
|
||||
# Conditional .NET build - only for Windows
|
||||
build-dotnet-conditional:
|
||||
@if [ "$(OS)" = "windows" ]; then \
|
||||
echo "Building .NET executable for Windows..."; \
|
||||
if command -v dotnet >/dev/null 2>&1; then \
|
||||
rm -rf ./agent/lhm/bin; \
|
||||
dotnet build -c Release ./agent/lhm/beszel_lhm.csproj; \
|
||||
else \
|
||||
echo "Error: dotnet not found. Install .NET SDK to build Windows agent."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
# Update build-agent to include conditional .NET build
|
||||
build-agent: tidy build-dotnet-conditional
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel-agent_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" ./internal/cmd/agent
|
||||
|
||||
build-hub: tidy $(if $(filter false,$(SKIP_WEB)),build-web-ui)
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" ./internal/cmd/hub
|
||||
|
||||
build-hub-dev: tidy
|
||||
mkdir -p ./internal/site/dist && touch ./internal/site/dist/index.html
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -tags development -o ./build/beszel-dev_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" ./internal/cmd/hub
|
||||
|
||||
build: build-agent build-hub
|
||||
|
||||
generate-locales:
|
||||
@if [ ! -f ./internal/site/src/locales/en/en.ts ]; then \
|
||||
echo "Generating locales..."; \
|
||||
command -v bun >/dev/null 2>&1 && cd ./internal/site && bun install && bun run sync || cd ./internal/site && npm install && npm run sync; \
|
||||
fi
|
||||
|
||||
dev-server: generate-locales
|
||||
cd ./internal/site
|
||||
@if command -v bun >/dev/null 2>&1; then \
|
||||
cd ./internal/site && bun run dev --host 0.0.0.0; \
|
||||
else \
|
||||
cd ./internal/site && npm run dev --host 0.0.0.0; \
|
||||
fi
|
||||
|
||||
dev-hub: export ENV=dev
|
||||
dev-hub:
|
||||
mkdir -p ./internal/site/dist && touch ./internal/site/dist/index.html
|
||||
@if command -v entr >/dev/null 2>&1; then \
|
||||
find ./internal/cmd/hub/*.go ./internal/{alerts,hub,records,users}/*.go | entr -r -s "cd ./internal/cmd/hub && go run -tags development . serve --http 0.0.0.0:8090"; \
|
||||
else \
|
||||
cd ./internal/cmd/hub && go run -tags development . serve --http 0.0.0.0:8090; \
|
||||
fi
|
||||
|
||||
dev-agent:
|
||||
@if command -v entr >/dev/null 2>&1; then \
|
||||
find ./internal/cmd/agent/*.go ./agent/*.go | entr -r go run github.com/henrygd/beszel/internal/cmd/agent; \
|
||||
else \
|
||||
go run github.com/henrygd/beszel/internal/cmd/agent; \
|
||||
fi
|
||||
|
||||
build-dotnet:
|
||||
@if command -v dotnet >/dev/null 2>&1; then \
|
||||
rm -rf ./agent/lhm/bin; \
|
||||
dotnet build -c Release ./agent/lhm/beszel_lhm.csproj; \
|
||||
else \
|
||||
echo "dotnet not found"; \
|
||||
fi
|
||||
|
||||
|
||||
# KEY="..." make -j dev
|
||||
dev: dev-server dev-hub dev-agent
|
||||
185
agent/agent.go
Normal file
185
agent/agent.go
Normal file
@@ -0,0 +1,185 @@
|
||||
// Package agent implements the Beszel monitoring agent that collects and serves system metrics.
|
||||
//
|
||||
// The agent runs on monitored systems and communicates collected data
|
||||
// to the Beszel hub for centralized monitoring and alerting.
|
||||
package agent
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gliderlabs/ssh"
|
||||
"github.com/henrygd/beszel"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/shirou/gopsutil/v4/host"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type Agent struct {
|
||||
sync.Mutex // Used to lock agent while collecting data
|
||||
debug bool // true if LOG_LEVEL is set to debug
|
||||
zfs bool // true if system has arcstats
|
||||
memCalc string // Memory calculation formula
|
||||
fsNames []string // List of filesystem device names being monitored
|
||||
fsStats map[string]*system.FsStats // Keeps track of disk stats for each filesystem
|
||||
netInterfaces map[string]struct{} // Stores all valid network interfaces
|
||||
netIoStats system.NetIoStats // Keeps track of bandwidth usage
|
||||
dockerManager *dockerManager // Manages Docker API requests
|
||||
sensorConfig *SensorConfig // Sensors config
|
||||
systemInfo system.Info // Host system info
|
||||
gpuManager *GPUManager // Manages GPU data
|
||||
cache *SessionCache // Cache for system stats based on primary session ID
|
||||
connectionManager *ConnectionManager // Channel to signal connection events
|
||||
server *ssh.Server // SSH server
|
||||
dataDir string // Directory for persisting data
|
||||
keys []gossh.PublicKey // SSH public keys
|
||||
}
|
||||
|
||||
// NewAgent creates a new agent with the given data directory for persisting data.
|
||||
// If the data directory is not set, it will attempt to find the optimal directory.
|
||||
func NewAgent(dataDir ...string) (agent *Agent, err error) {
|
||||
agent = &Agent{
|
||||
fsStats: make(map[string]*system.FsStats),
|
||||
cache: NewSessionCache(69 * time.Second),
|
||||
}
|
||||
|
||||
agent.dataDir, err = getDataDir(dataDir...)
|
||||
if err != nil {
|
||||
slog.Warn("Data directory not found")
|
||||
} else {
|
||||
slog.Info("Data directory", "path", agent.dataDir)
|
||||
}
|
||||
|
||||
agent.memCalc, _ = GetEnv("MEM_CALC")
|
||||
agent.sensorConfig = agent.newSensorConfig()
|
||||
// Set up slog with a log level determined by the LOG_LEVEL env var
|
||||
if logLevelStr, exists := GetEnv("LOG_LEVEL"); exists {
|
||||
switch strings.ToLower(logLevelStr) {
|
||||
case "debug":
|
||||
agent.debug = true
|
||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||
case "warn":
|
||||
slog.SetLogLoggerLevel(slog.LevelWarn)
|
||||
case "error":
|
||||
slog.SetLogLoggerLevel(slog.LevelError)
|
||||
}
|
||||
}
|
||||
|
||||
slog.Debug(beszel.Version)
|
||||
|
||||
// initialize system info
|
||||
agent.initializeSystemInfo()
|
||||
|
||||
// initialize connection manager
|
||||
agent.connectionManager = newConnectionManager(agent)
|
||||
|
||||
// initialize disk info
|
||||
agent.initializeDiskInfo()
|
||||
|
||||
// initialize net io stats
|
||||
agent.initializeNetIoStats()
|
||||
|
||||
// initialize docker manager
|
||||
agent.dockerManager = newDockerManager(agent)
|
||||
|
||||
// initialize GPU manager
|
||||
if gm, err := NewGPUManager(); err != nil {
|
||||
slog.Debug("GPU", "err", err)
|
||||
} else {
|
||||
agent.gpuManager = gm
|
||||
}
|
||||
|
||||
// if debugging, print stats
|
||||
if agent.debug {
|
||||
slog.Debug("Stats", "data", agent.gatherStats(""))
|
||||
}
|
||||
|
||||
return agent, nil
|
||||
}
|
||||
|
||||
// GetEnv retrieves an environment variable with a "BESZEL_AGENT_" prefix, or falls back to the unprefixed key.
|
||||
func GetEnv(key string) (value string, exists bool) {
|
||||
if value, exists = os.LookupEnv("BESZEL_AGENT_" + key); exists {
|
||||
return value, exists
|
||||
}
|
||||
// Fallback to the old unprefixed key
|
||||
return os.LookupEnv(key)
|
||||
}
|
||||
|
||||
func (a *Agent) gatherStats(sessionID string) *system.CombinedData {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
data, isCached := a.cache.Get(sessionID)
|
||||
if isCached {
|
||||
slog.Debug("Cached data", "session", sessionID)
|
||||
return data
|
||||
}
|
||||
|
||||
*data = system.CombinedData{
|
||||
Stats: a.getSystemStats(),
|
||||
Info: a.systemInfo,
|
||||
}
|
||||
slog.Debug("System data", "data", data)
|
||||
|
||||
if a.dockerManager != nil {
|
||||
if containerStats, err := a.dockerManager.getDockerStats(); err == nil {
|
||||
data.Containers = containerStats
|
||||
slog.Debug("Containers", "data", data.Containers)
|
||||
} else {
|
||||
slog.Debug("Containers", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
data.Stats.ExtraFs = make(map[string]*system.FsStats)
|
||||
for name, stats := range a.fsStats {
|
||||
if !stats.Root && stats.DiskTotal > 0 {
|
||||
data.Stats.ExtraFs[name] = stats
|
||||
}
|
||||
}
|
||||
slog.Debug("Extra FS", "data", data.Stats.ExtraFs)
|
||||
|
||||
a.cache.Set(sessionID, data)
|
||||
return data
|
||||
}
|
||||
|
||||
// StartAgent initializes and starts the agent with optional WebSocket connection
|
||||
func (a *Agent) Start(serverOptions ServerOptions) error {
|
||||
a.keys = serverOptions.Keys
|
||||
return a.connectionManager.Start(serverOptions)
|
||||
}
|
||||
|
||||
func (a *Agent) getFingerprint() string {
|
||||
// first look for a fingerprint in the data directory
|
||||
if a.dataDir != "" {
|
||||
if fp, err := os.ReadFile(filepath.Join(a.dataDir, "fingerprint")); err == nil {
|
||||
return string(fp)
|
||||
}
|
||||
}
|
||||
|
||||
// if no fingerprint is found, generate one
|
||||
fingerprint, err := host.HostID()
|
||||
if err != nil || fingerprint == "" {
|
||||
fingerprint = a.systemInfo.Hostname + a.systemInfo.CpuModel
|
||||
}
|
||||
|
||||
// hash fingerprint
|
||||
sum := sha256.Sum256([]byte(fingerprint))
|
||||
fingerprint = hex.EncodeToString(sum[:24])
|
||||
|
||||
// save fingerprint to data directory
|
||||
if a.dataDir != "" {
|
||||
err = os.WriteFile(filepath.Join(a.dataDir, "fingerprint"), []byte(fingerprint), 0644)
|
||||
if err != nil {
|
||||
slog.Warn("Failed to save fingerprint", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
return fingerprint
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/system"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
)
|
||||
|
||||
// Not thread safe since we only access from gatherStats which is already locked
|
||||
@@ -1,17 +1,21 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/system"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSessionCache_GetSet(t *testing.T) {
|
||||
synctest.Run(func() {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
cache := NewSessionCache(69 * time.Second)
|
||||
|
||||
testData := &system.CombinedData{
|
||||
9
agent/agent_test_helpers.go
Normal file
9
agent/agent_test_helpers.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent
|
||||
|
||||
// TESTING ONLY: GetConnectionManager is a helper function to get the connection manager for testing.
|
||||
func (a *Agent) GetConnectionManager() *ConnectionManager {
|
||||
return a.connectionManager
|
||||
}
|
||||
53
agent/battery/battery.go
Normal file
53
agent/battery/battery.go
Normal file
@@ -0,0 +1,53 @@
|
||||
//go:build !freebsd
|
||||
|
||||
// Package battery provides functions to check if the system has a battery and to get the battery stats.
|
||||
package battery
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
|
||||
"github.com/distatus/battery"
|
||||
)
|
||||
|
||||
var systemHasBattery = false
|
||||
var haveCheckedBattery = false
|
||||
|
||||
// HasReadableBattery checks if the system has a battery and returns true if it does.
|
||||
func HasReadableBattery() bool {
|
||||
if haveCheckedBattery {
|
||||
return systemHasBattery
|
||||
}
|
||||
haveCheckedBattery = true
|
||||
bat, err := battery.Get(0)
|
||||
if err == nil && bat != nil {
|
||||
systemHasBattery = true
|
||||
} else {
|
||||
slog.Debug("No battery found", "err", err)
|
||||
}
|
||||
return systemHasBattery
|
||||
}
|
||||
|
||||
// GetBatteryStats returns the current battery percent and charge state
|
||||
func GetBatteryStats() (batteryPercent uint8, batteryState uint8, err error) {
|
||||
if !systemHasBattery {
|
||||
return batteryPercent, batteryState, errors.ErrUnsupported
|
||||
}
|
||||
batteries, err := battery.GetAll()
|
||||
if err != nil || len(batteries) == 0 {
|
||||
return batteryPercent, batteryState, err
|
||||
}
|
||||
totalCapacity := float64(0)
|
||||
totalCharge := float64(0)
|
||||
for _, bat := range batteries {
|
||||
if bat.Design != 0 {
|
||||
totalCapacity += bat.Design
|
||||
} else {
|
||||
totalCapacity += bat.Full
|
||||
}
|
||||
totalCharge += bat.Current
|
||||
}
|
||||
batteryPercent = uint8(totalCharge / totalCapacity * 100)
|
||||
batteryState = uint8(batteries[0].State.Raw)
|
||||
return batteryPercent, batteryState, nil
|
||||
}
|
||||
13
agent/battery/battery_freebsd.go
Normal file
13
agent/battery/battery_freebsd.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build freebsd
|
||||
|
||||
package battery
|
||||
|
||||
import "errors"
|
||||
|
||||
func HasReadableBattery() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func GetBatteryStats() (uint8, uint8, error) {
|
||||
return 0, 0, errors.ErrUnsupported
|
||||
}
|
||||
266
agent/client.go
Normal file
266
agent/client.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel"
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/lxzan/gws"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const (
|
||||
wsDeadline = 70 * time.Second
|
||||
)
|
||||
|
||||
// WebSocketClient manages the WebSocket connection between the agent and hub.
|
||||
// It handles authentication, message routing, and connection lifecycle management.
|
||||
type WebSocketClient struct {
|
||||
gws.BuiltinEventHandler
|
||||
options *gws.ClientOption // WebSocket client configuration options
|
||||
agent *Agent // Reference to the parent agent
|
||||
Conn *gws.Conn // Active WebSocket connection
|
||||
hubURL *url.URL // Parsed hub URL for connection
|
||||
token string // Authentication token for hub registration
|
||||
fingerprint string // System fingerprint for identification
|
||||
hubRequest *common.HubRequest[cbor.RawMessage] // Reusable request structure for message parsing
|
||||
lastConnectAttempt time.Time // Timestamp of last connection attempt
|
||||
hubVerified bool // Whether the hub has been cryptographically verified
|
||||
}
|
||||
|
||||
// newWebSocketClient creates a new WebSocket client for the given agent.
|
||||
// It reads configuration from environment variables and validates the hub URL.
|
||||
func newWebSocketClient(agent *Agent) (client *WebSocketClient, err error) {
|
||||
hubURLStr, exists := GetEnv("HUB_URL")
|
||||
if !exists {
|
||||
return nil, errors.New("HUB_URL environment variable not set")
|
||||
}
|
||||
|
||||
client = &WebSocketClient{}
|
||||
|
||||
client.hubURL, err = url.Parse(hubURLStr)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid hub URL")
|
||||
}
|
||||
// get registration token
|
||||
client.token, err = getToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.agent = agent
|
||||
client.hubRequest = &common.HubRequest[cbor.RawMessage]{}
|
||||
client.fingerprint = agent.getFingerprint()
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// getToken returns the token for the WebSocket client.
|
||||
// It first checks the TOKEN environment variable, then the TOKEN_FILE environment variable.
|
||||
// If neither is set, it returns an error.
|
||||
func getToken() (string, error) {
|
||||
// get token from env var
|
||||
token, _ := GetEnv("TOKEN")
|
||||
if token != "" {
|
||||
return token, nil
|
||||
}
|
||||
// get token from file
|
||||
tokenFile, _ := GetEnv("TOKEN_FILE")
|
||||
if tokenFile == "" {
|
||||
return "", errors.New("must set TOKEN or TOKEN_FILE")
|
||||
}
|
||||
tokenBytes, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(tokenBytes), nil
|
||||
}
|
||||
|
||||
// getOptions returns the WebSocket client options, creating them if necessary.
|
||||
// It configures the connection URL, TLS settings, and authentication headers.
|
||||
func (client *WebSocketClient) getOptions() *gws.ClientOption {
|
||||
if client.options != nil {
|
||||
return client.options
|
||||
}
|
||||
|
||||
// update the hub url to use websocket scheme and api path
|
||||
if client.hubURL.Scheme == "https" {
|
||||
client.hubURL.Scheme = "wss"
|
||||
} else {
|
||||
client.hubURL.Scheme = "ws"
|
||||
}
|
||||
client.hubURL.Path = path.Join(client.hubURL.Path, "api/beszel/agent-connect")
|
||||
|
||||
client.options = &gws.ClientOption{
|
||||
Addr: client.hubURL.String(),
|
||||
TlsConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
RequestHeader: http.Header{
|
||||
"User-Agent": []string{getUserAgent()},
|
||||
"X-Token": []string{client.token},
|
||||
"X-Beszel": []string{beszel.Version},
|
||||
},
|
||||
}
|
||||
return client.options
|
||||
}
|
||||
|
||||
// Connect establishes a WebSocket connection to the hub.
|
||||
// It closes any existing connection before attempting to reconnect.
|
||||
func (client *WebSocketClient) Connect() (err error) {
|
||||
client.lastConnectAttempt = time.Now()
|
||||
|
||||
// make sure previous connection is closed
|
||||
client.Close()
|
||||
|
||||
client.Conn, _, err = gws.NewClient(client, client.getOptions())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go client.Conn.ReadLoop()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnOpen handles WebSocket connection establishment.
|
||||
// It sets a deadline for the connection to prevent hanging.
|
||||
func (client *WebSocketClient) OnOpen(conn *gws.Conn) {
|
||||
conn.SetDeadline(time.Now().Add(wsDeadline))
|
||||
}
|
||||
|
||||
// OnClose handles WebSocket connection closure.
|
||||
// It logs the closure reason and notifies the connection manager.
|
||||
func (client *WebSocketClient) OnClose(conn *gws.Conn, err error) {
|
||||
slog.Warn("Connection closed", "err", strings.TrimPrefix(err.Error(), "gws: "))
|
||||
client.agent.connectionManager.eventChan <- WebSocketDisconnect
|
||||
}
|
||||
|
||||
// OnMessage handles incoming WebSocket messages from the hub.
|
||||
// It decodes CBOR messages and routes them to appropriate handlers.
|
||||
func (client *WebSocketClient) OnMessage(conn *gws.Conn, message *gws.Message) {
|
||||
defer message.Close()
|
||||
conn.SetDeadline(time.Now().Add(wsDeadline))
|
||||
|
||||
if message.Opcode != gws.OpcodeBinary {
|
||||
return
|
||||
}
|
||||
|
||||
if err := cbor.NewDecoder(message.Data).Decode(client.hubRequest); err != nil {
|
||||
slog.Error("Error parsing message", "err", err)
|
||||
return
|
||||
}
|
||||
if err := client.handleHubRequest(client.hubRequest); err != nil {
|
||||
slog.Error("Error handling message", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// OnPing handles WebSocket ping frames.
|
||||
// It responds with a pong and updates the connection deadline.
|
||||
func (client *WebSocketClient) OnPing(conn *gws.Conn, message []byte) {
|
||||
conn.SetDeadline(time.Now().Add(wsDeadline))
|
||||
conn.WritePong(message)
|
||||
}
|
||||
|
||||
// handleAuthChallenge verifies the authenticity of the hub and returns the system's fingerprint.
|
||||
func (client *WebSocketClient) handleAuthChallenge(msg *common.HubRequest[cbor.RawMessage]) (err error) {
|
||||
var authRequest common.FingerprintRequest
|
||||
if err := cbor.Unmarshal(msg.Data, &authRequest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := client.verifySignature(authRequest.Signature); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client.hubVerified = true
|
||||
client.agent.connectionManager.eventChan <- WebSocketConnect
|
||||
|
||||
response := &common.FingerprintResponse{
|
||||
Fingerprint: client.fingerprint,
|
||||
}
|
||||
|
||||
if authRequest.NeedSysInfo {
|
||||
response.Hostname = client.agent.systemInfo.Hostname
|
||||
serverAddr := client.agent.connectionManager.serverOptions.Addr
|
||||
_, response.Port, _ = net.SplitHostPort(serverAddr)
|
||||
}
|
||||
|
||||
return client.sendMessage(response)
|
||||
}
|
||||
|
||||
// verifySignature verifies the signature of the token using the public keys.
|
||||
func (client *WebSocketClient) verifySignature(signature []byte) (err error) {
|
||||
for _, pubKey := range client.agent.keys {
|
||||
sig := ssh.Signature{
|
||||
Format: pubKey.Type(),
|
||||
Blob: signature,
|
||||
}
|
||||
if err = pubKey.Verify([]byte(client.token), &sig); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("invalid signature - check KEY value")
|
||||
}
|
||||
|
||||
// Close closes the WebSocket connection gracefully.
|
||||
// This method is safe to call multiple times.
|
||||
func (client *WebSocketClient) Close() {
|
||||
if client.Conn != nil {
|
||||
_ = client.Conn.WriteClose(1000, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// handleHubRequest routes the request to the appropriate handler.
|
||||
// It ensures the hub is verified before processing most requests.
|
||||
func (client *WebSocketClient) handleHubRequest(msg *common.HubRequest[cbor.RawMessage]) error {
|
||||
if !client.hubVerified && msg.Action != common.CheckFingerprint {
|
||||
return errors.New("hub not verified")
|
||||
}
|
||||
switch msg.Action {
|
||||
case common.GetData:
|
||||
return client.sendSystemData()
|
||||
case common.CheckFingerprint:
|
||||
return client.handleAuthChallenge(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendSystemData gathers and sends current system statistics to the hub.
|
||||
func (client *WebSocketClient) sendSystemData() error {
|
||||
sysStats := client.agent.gatherStats(client.token)
|
||||
return client.sendMessage(sysStats)
|
||||
}
|
||||
|
||||
// sendMessage encodes the given data to CBOR and sends it as a binary message over the WebSocket connection to the hub.
|
||||
func (client *WebSocketClient) sendMessage(data any) error {
|
||||
bytes, err := cbor.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.Conn.WriteMessage(gws.OpcodeBinary, bytes)
|
||||
}
|
||||
|
||||
// getUserAgent returns one of two User-Agent strings based on current time.
|
||||
// This is used to avoid being blocked by Cloudflare or other anti-bot measures.
|
||||
func getUserAgent() string {
|
||||
const (
|
||||
uaBase = "Mozilla/5.0 (%s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
|
||||
uaWindows = "Windows NT 11.0; Win64; x64"
|
||||
uaMac = "Macintosh; Intel Mac OS X 14_0_0"
|
||||
)
|
||||
if time.Now().UnixNano()%2 == 0 {
|
||||
return fmt.Sprintf(uaBase, uaWindows)
|
||||
}
|
||||
return fmt.Sprintf(uaBase, uaMac)
|
||||
}
|
||||
540
agent/client_test.go
Normal file
540
agent/client_test.go
Normal file
@@ -0,0 +1,540 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel"
|
||||
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// TestNewWebSocketClient tests WebSocket client creation
|
||||
func TestNewWebSocketClient(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
hubURL string
|
||||
token string
|
||||
expectError bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "valid configuration",
|
||||
hubURL: "http://localhost:8080",
|
||||
token: "test-token-123",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "valid https URL",
|
||||
hubURL: "https://hub.example.com",
|
||||
token: "secure-token",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "missing hub URL",
|
||||
hubURL: "",
|
||||
token: "test-token",
|
||||
expectError: true,
|
||||
errorMsg: "HUB_URL environment variable not set",
|
||||
},
|
||||
{
|
||||
name: "invalid URL",
|
||||
hubURL: "ht\ttp://invalid",
|
||||
token: "test-token",
|
||||
expectError: true,
|
||||
errorMsg: "invalid hub URL",
|
||||
},
|
||||
{
|
||||
name: "missing token",
|
||||
hubURL: "http://localhost:8080",
|
||||
token: "",
|
||||
expectError: true,
|
||||
errorMsg: "must set TOKEN or TOKEN_FILE",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Set up environment
|
||||
if tc.hubURL != "" {
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", tc.hubURL)
|
||||
} else {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
}
|
||||
if tc.token != "" {
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", tc.token)
|
||||
} else {
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
|
||||
if tc.expectError {
|
||||
assert.Error(t, err)
|
||||
if err != nil && tc.errorMsg != "" {
|
||||
assert.Contains(t, err.Error(), tc.errorMsg)
|
||||
}
|
||||
assert.Nil(t, client)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, client)
|
||||
assert.Equal(t, agent, client.agent)
|
||||
assert.Equal(t, tc.token, client.token)
|
||||
assert.Equal(t, tc.hubURL, client.hubURL.String())
|
||||
assert.NotEmpty(t, client.fingerprint)
|
||||
assert.NotNil(t, client.hubRequest)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWebSocketClient_GetOptions tests WebSocket client options configuration
|
||||
func TestWebSocketClient_GetOptions(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
inputURL string
|
||||
expectedScheme string
|
||||
expectedPath string
|
||||
}{
|
||||
{
|
||||
name: "http to ws conversion",
|
||||
inputURL: "http://localhost:8080",
|
||||
expectedScheme: "ws",
|
||||
expectedPath: "/api/beszel/agent-connect",
|
||||
},
|
||||
{
|
||||
name: "https to wss conversion",
|
||||
inputURL: "https://hub.example.com",
|
||||
expectedScheme: "wss",
|
||||
expectedPath: "/api/beszel/agent-connect",
|
||||
},
|
||||
{
|
||||
name: "existing path preservation",
|
||||
inputURL: "http://localhost:8080/custom/path",
|
||||
expectedScheme: "ws",
|
||||
expectedPath: "/custom/path/api/beszel/agent-connect",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", tc.inputURL)
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
|
||||
options := client.getOptions()
|
||||
|
||||
// Parse the WebSocket URL
|
||||
wsURL, err := url.Parse(options.Addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tc.expectedScheme, wsURL.Scheme)
|
||||
assert.Equal(t, tc.expectedPath, wsURL.Path)
|
||||
|
||||
// Check headers
|
||||
assert.Equal(t, "test-token", options.RequestHeader.Get("X-Token"))
|
||||
assert.Equal(t, beszel.Version, options.RequestHeader.Get("X-Beszel"))
|
||||
assert.Contains(t, options.RequestHeader.Get("User-Agent"), "Mozilla/5.0")
|
||||
|
||||
// Test options caching
|
||||
options2 := client.getOptions()
|
||||
assert.Same(t, options, options2, "Options should be cached")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWebSocketClient_VerifySignature tests signature verification
|
||||
func TestWebSocketClient_VerifySignature(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
// Generate test key pairs
|
||||
_, goodPrivKey, err := ed25519.GenerateKey(nil)
|
||||
require.NoError(t, err)
|
||||
goodPubKey, err := ssh.NewPublicKey(goodPrivKey.Public().(ed25519.PublicKey))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, badPrivKey, err := ed25519.GenerateKey(nil)
|
||||
require.NoError(t, err)
|
||||
badPubKey, err := ssh.NewPublicKey(badPrivKey.Public().(ed25519.PublicKey))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
keys []ssh.PublicKey
|
||||
token string
|
||||
signWith ed25519.PrivateKey
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "valid signature with correct key",
|
||||
keys: []ssh.PublicKey{goodPubKey},
|
||||
token: "test-token",
|
||||
signWith: goodPrivKey,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "invalid signature with wrong key",
|
||||
keys: []ssh.PublicKey{goodPubKey},
|
||||
token: "test-token",
|
||||
signWith: badPrivKey,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "valid signature with multiple keys",
|
||||
keys: []ssh.PublicKey{badPubKey, goodPubKey},
|
||||
token: "test-token",
|
||||
signWith: goodPrivKey,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "no valid keys",
|
||||
keys: []ssh.PublicKey{badPubKey},
|
||||
token: "test-token",
|
||||
signWith: goodPrivKey,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Set up agent with test keys
|
||||
agent.keys = tc.keys
|
||||
client.token = tc.token
|
||||
|
||||
// Create signature
|
||||
signature := ed25519.Sign(tc.signWith, []byte(tc.token))
|
||||
|
||||
err := client.verifySignature(signature)
|
||||
|
||||
if tc.expectError {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "invalid signature")
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWebSocketClient_HandleHubRequest tests hub request routing (basic verification logic)
|
||||
func TestWebSocketClient_HandleHubRequest(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
action common.WebSocketAction
|
||||
hubVerified bool
|
||||
expectError bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "CheckFingerprint without verification",
|
||||
action: common.CheckFingerprint,
|
||||
hubVerified: false,
|
||||
expectError: false, // CheckFingerprint is allowed without verification
|
||||
},
|
||||
{
|
||||
name: "GetData without verification",
|
||||
action: common.GetData,
|
||||
hubVerified: false,
|
||||
expectError: true,
|
||||
errorMsg: "hub not verified",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client.hubVerified = tc.hubVerified
|
||||
|
||||
// Create minimal request
|
||||
hubRequest := &common.HubRequest[cbor.RawMessage]{
|
||||
Action: tc.action,
|
||||
Data: cbor.RawMessage{},
|
||||
}
|
||||
|
||||
err := client.handleHubRequest(hubRequest)
|
||||
|
||||
if tc.expectError {
|
||||
assert.Error(t, err)
|
||||
if tc.errorMsg != "" {
|
||||
assert.Contains(t, err.Error(), tc.errorMsg)
|
||||
}
|
||||
} else {
|
||||
// For CheckFingerprint, we expect a decode error since we're not providing valid data,
|
||||
// but it shouldn't be the "hub not verified" error
|
||||
if err != nil && tc.errorMsg != "" {
|
||||
assert.NotContains(t, err.Error(), tc.errorMsg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWebSocketClient_GetUserAgent tests user agent generation
|
||||
func TestGetUserAgent(t *testing.T) {
|
||||
// Run multiple times to check both variants
|
||||
userAgents := make(map[string]bool)
|
||||
|
||||
for range 20 {
|
||||
ua := getUserAgent()
|
||||
userAgents[ua] = true
|
||||
|
||||
// Check that it's a valid Mozilla user agent
|
||||
assert.Contains(t, ua, "Mozilla/5.0")
|
||||
assert.Contains(t, ua, "AppleWebKit/537.36")
|
||||
assert.Contains(t, ua, "Chrome/124.0.0.0")
|
||||
assert.Contains(t, ua, "Safari/537.36")
|
||||
|
||||
// Should contain either Windows or Mac
|
||||
isWindows := strings.Contains(ua, "Windows NT 11.0")
|
||||
isMac := strings.Contains(ua, "Macintosh; Intel Mac OS X 14_0_0")
|
||||
assert.True(t, isWindows || isMac, "User agent should contain either Windows or Mac identifier")
|
||||
}
|
||||
|
||||
// With enough iterations, we should see both variants
|
||||
// though this might occasionally fail
|
||||
if len(userAgents) == 1 {
|
||||
t.Log("Note: Only one user agent variant was generated in this test run")
|
||||
}
|
||||
}
|
||||
|
||||
// TestWebSocketClient_Close tests connection closing
|
||||
func TestWebSocketClient_Close(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test closing with nil connection (should not panic)
|
||||
assert.NotPanics(t, func() {
|
||||
client.Close()
|
||||
})
|
||||
}
|
||||
|
||||
// TestWebSocketClient_ConnectRateLimit tests connection rate limiting
|
||||
func TestWebSocketClient_ConnectRateLimit(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set recent connection attempt
|
||||
client.lastConnectAttempt = time.Now()
|
||||
|
||||
// Test that connection fails quickly due to rate limiting
|
||||
// This won't actually connect but should fail fast
|
||||
err = client.Connect()
|
||||
assert.Error(t, err, "Connection should fail but not hang")
|
||||
}
|
||||
|
||||
// TestGetToken tests the getToken function with various scenarios
|
||||
func TestGetToken(t *testing.T) {
|
||||
unsetEnvVars := func() {
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
os.Unsetenv("TOKEN")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN_FILE")
|
||||
os.Unsetenv("TOKEN_FILE")
|
||||
}
|
||||
|
||||
t.Run("token from TOKEN environment variable", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Set TOKEN env var
|
||||
expectedToken := "test-token-from-env"
|
||||
os.Setenv("TOKEN", expectedToken)
|
||||
defer os.Unsetenv("TOKEN")
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedToken, token)
|
||||
})
|
||||
|
||||
t.Run("token from BESZEL_AGENT_TOKEN environment variable", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Set BESZEL_AGENT_TOKEN env var (should take precedence)
|
||||
expectedToken := "test-token-from-beszel-env"
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", expectedToken)
|
||||
defer os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedToken, token)
|
||||
})
|
||||
|
||||
t.Run("token from TOKEN_FILE", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create a temporary token file
|
||||
expectedToken := "test-token-from-file"
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tokenFile.Name())
|
||||
|
||||
_, err = tokenFile.WriteString(expectedToken)
|
||||
require.NoError(t, err)
|
||||
tokenFile.Close()
|
||||
|
||||
// Set TOKEN_FILE env var
|
||||
os.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
defer os.Unsetenv("TOKEN_FILE")
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedToken, token)
|
||||
})
|
||||
|
||||
t.Run("token from BESZEL_AGENT_TOKEN_FILE", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create a temporary token file
|
||||
expectedToken := "test-token-from-beszel-file"
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tokenFile.Name())
|
||||
|
||||
_, err = tokenFile.WriteString(expectedToken)
|
||||
require.NoError(t, err)
|
||||
tokenFile.Close()
|
||||
|
||||
// Set BESZEL_AGENT_TOKEN_FILE env var (should take precedence)
|
||||
os.Setenv("BESZEL_AGENT_TOKEN_FILE", tokenFile.Name())
|
||||
defer os.Unsetenv("BESZEL_AGENT_TOKEN_FILE")
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedToken, token)
|
||||
})
|
||||
|
||||
t.Run("TOKEN takes precedence over TOKEN_FILE", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create a temporary token file
|
||||
fileToken := "token-from-file"
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tokenFile.Name())
|
||||
|
||||
_, err = tokenFile.WriteString(fileToken)
|
||||
require.NoError(t, err)
|
||||
tokenFile.Close()
|
||||
|
||||
// Set both TOKEN and TOKEN_FILE
|
||||
envToken := "token-from-env"
|
||||
os.Setenv("TOKEN", envToken)
|
||||
os.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
defer func() {
|
||||
os.Unsetenv("TOKEN")
|
||||
os.Unsetenv("TOKEN_FILE")
|
||||
}()
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, envToken, token, "TOKEN should take precedence over TOKEN_FILE")
|
||||
})
|
||||
|
||||
t.Run("error when neither TOKEN nor TOKEN_FILE is set", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
token, err := getToken()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "", token)
|
||||
assert.Contains(t, err.Error(), "must set TOKEN or TOKEN_FILE")
|
||||
})
|
||||
|
||||
t.Run("error when TOKEN_FILE points to non-existent file", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Set TOKEN_FILE to a non-existent file
|
||||
os.Setenv("TOKEN_FILE", "/non/existent/file.txt")
|
||||
defer os.Unsetenv("TOKEN_FILE")
|
||||
|
||||
token, err := getToken()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "", token)
|
||||
assert.Contains(t, err.Error(), "no such file or directory")
|
||||
})
|
||||
|
||||
t.Run("handles empty token file", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create an empty token file
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tokenFile.Name())
|
||||
tokenFile.Close()
|
||||
|
||||
// Set TOKEN_FILE env var
|
||||
os.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
defer os.Unsetenv("TOKEN_FILE")
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", token, "Empty file should return empty string")
|
||||
})
|
||||
}
|
||||
221
agent/connection_manager.go
Normal file
221
agent/connection_manager.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/agent/health"
|
||||
)
|
||||
|
||||
// ConnectionManager manages the connection state and events for the agent.
|
||||
// It handles both WebSocket and SSH connections, automatically switching between
|
||||
// them based on availability and managing reconnection attempts.
|
||||
type ConnectionManager struct {
|
||||
agent *Agent // Reference to the parent agent
|
||||
State ConnectionState // Current connection state
|
||||
eventChan chan ConnectionEvent // Channel for connection events
|
||||
wsClient *WebSocketClient // WebSocket client for hub communication
|
||||
serverOptions ServerOptions // Configuration for SSH server
|
||||
wsTicker *time.Ticker // Ticker for WebSocket connection attempts
|
||||
isConnecting bool // Prevents multiple simultaneous reconnection attempts
|
||||
}
|
||||
|
||||
// ConnectionState represents the current connection state of the agent.
|
||||
type ConnectionState uint8
|
||||
|
||||
// ConnectionEvent represents connection-related events that can occur.
|
||||
type ConnectionEvent uint8
|
||||
|
||||
// Connection states
|
||||
const (
|
||||
Disconnected ConnectionState = iota // No active connection
|
||||
WebSocketConnected // Connected via WebSocket
|
||||
SSHConnected // Connected via SSH
|
||||
)
|
||||
|
||||
// Connection events
|
||||
const (
|
||||
WebSocketConnect ConnectionEvent = iota // WebSocket connection established
|
||||
WebSocketDisconnect // WebSocket connection lost
|
||||
SSHConnect // SSH connection established
|
||||
SSHDisconnect // SSH connection lost
|
||||
)
|
||||
|
||||
const wsTickerInterval = 10 * time.Second
|
||||
|
||||
// newConnectionManager creates a new connection manager for the given agent.
|
||||
func newConnectionManager(agent *Agent) *ConnectionManager {
|
||||
cm := &ConnectionManager{
|
||||
agent: agent,
|
||||
State: Disconnected,
|
||||
}
|
||||
return cm
|
||||
}
|
||||
|
||||
// startWsTicker starts or resets the WebSocket connection attempt ticker.
|
||||
func (c *ConnectionManager) startWsTicker() {
|
||||
if c.wsTicker == nil {
|
||||
c.wsTicker = time.NewTicker(wsTickerInterval)
|
||||
} else {
|
||||
c.wsTicker.Reset(wsTickerInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// stopWsTicker stops the WebSocket connection attempt ticker.
|
||||
func (c *ConnectionManager) stopWsTicker() {
|
||||
if c.wsTicker != nil {
|
||||
c.wsTicker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
// Start begins connection attempts and enters the main event loop.
|
||||
// It handles connection events, periodic health updates, and graceful shutdown.
|
||||
func (c *ConnectionManager) Start(serverOptions ServerOptions) error {
|
||||
if c.eventChan != nil {
|
||||
return errors.New("already started")
|
||||
}
|
||||
|
||||
wsClient, err := newWebSocketClient(c.agent)
|
||||
if err != nil {
|
||||
slog.Warn("Error creating WebSocket client", "err", err)
|
||||
}
|
||||
c.wsClient = wsClient
|
||||
|
||||
c.serverOptions = serverOptions
|
||||
c.eventChan = make(chan ConnectionEvent, 1)
|
||||
|
||||
// signal handling for shutdown
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
c.startWsTicker()
|
||||
c.connect()
|
||||
|
||||
// update health status immediately and every 90 seconds
|
||||
_ = health.Update()
|
||||
healthTicker := time.Tick(90 * time.Second)
|
||||
|
||||
for {
|
||||
select {
|
||||
case connectionEvent := <-c.eventChan:
|
||||
c.handleEvent(connectionEvent)
|
||||
case <-c.wsTicker.C:
|
||||
_ = c.startWebSocketConnection()
|
||||
case <-healthTicker:
|
||||
_ = health.Update()
|
||||
case <-sigChan:
|
||||
slog.Info("Shutting down")
|
||||
_ = c.agent.StopServer()
|
||||
c.closeWebSocket()
|
||||
return health.CleanUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleEvent processes connection events and updates the connection state accordingly.
|
||||
func (c *ConnectionManager) handleEvent(event ConnectionEvent) {
|
||||
switch event {
|
||||
case WebSocketConnect:
|
||||
c.handleStateChange(WebSocketConnected)
|
||||
case SSHConnect:
|
||||
c.handleStateChange(SSHConnected)
|
||||
case WebSocketDisconnect:
|
||||
if c.State == WebSocketConnected {
|
||||
c.handleStateChange(Disconnected)
|
||||
}
|
||||
case SSHDisconnect:
|
||||
if c.State == SSHConnected {
|
||||
c.handleStateChange(Disconnected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleStateChange updates the connection state and performs necessary actions
|
||||
// based on the new state, including stopping services and initiating reconnections.
|
||||
func (c *ConnectionManager) handleStateChange(newState ConnectionState) {
|
||||
if c.State == newState {
|
||||
return
|
||||
}
|
||||
c.State = newState
|
||||
switch newState {
|
||||
case WebSocketConnected:
|
||||
slog.Info("WebSocket connected", "host", c.wsClient.hubURL.Host)
|
||||
c.stopWsTicker()
|
||||
_ = c.agent.StopServer()
|
||||
c.isConnecting = false
|
||||
case SSHConnected:
|
||||
// stop new ws connection attempts
|
||||
slog.Info("SSH connection established")
|
||||
c.stopWsTicker()
|
||||
c.isConnecting = false
|
||||
case Disconnected:
|
||||
if c.isConnecting {
|
||||
// Already handling reconnection, avoid duplicate attempts
|
||||
return
|
||||
}
|
||||
c.isConnecting = true
|
||||
slog.Warn("Disconnected from hub")
|
||||
// make sure old ws connection is closed
|
||||
c.closeWebSocket()
|
||||
// reconnect
|
||||
go c.connect()
|
||||
}
|
||||
}
|
||||
|
||||
// connect handles the connection logic with proper delays and priority.
|
||||
// It attempts WebSocket connection first, falling back to SSH server if needed.
|
||||
func (c *ConnectionManager) connect() {
|
||||
c.isConnecting = true
|
||||
defer func() {
|
||||
c.isConnecting = false
|
||||
}()
|
||||
|
||||
if c.wsClient != nil && time.Since(c.wsClient.lastConnectAttempt) < 5*time.Second {
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
// Try WebSocket first, if it fails, start SSH server
|
||||
err := c.startWebSocketConnection()
|
||||
if err != nil && c.State == Disconnected {
|
||||
c.startSSHServer()
|
||||
c.startWsTicker()
|
||||
}
|
||||
}
|
||||
|
||||
// startWebSocketConnection attempts to establish a WebSocket connection to the hub.
|
||||
func (c *ConnectionManager) startWebSocketConnection() error {
|
||||
if c.State != Disconnected {
|
||||
return errors.New("already connected")
|
||||
}
|
||||
if c.wsClient == nil {
|
||||
return errors.New("WebSocket client not initialized")
|
||||
}
|
||||
if time.Since(c.wsClient.lastConnectAttempt) < 5*time.Second {
|
||||
return errors.New("already connecting")
|
||||
}
|
||||
|
||||
err := c.wsClient.Connect()
|
||||
if err != nil {
|
||||
slog.Warn("WebSocket connection failed", "err", err)
|
||||
c.closeWebSocket()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// startSSHServer starts the SSH server if the agent is currently disconnected.
|
||||
func (c *ConnectionManager) startSSHServer() {
|
||||
if c.State == Disconnected {
|
||||
go c.agent.StartServer(c.serverOptions)
|
||||
}
|
||||
}
|
||||
|
||||
// closeWebSocket closes the WebSocket connection if it exists.
|
||||
func (c *ConnectionManager) closeWebSocket() {
|
||||
if c.wsClient != nil {
|
||||
c.wsClient.Close()
|
||||
}
|
||||
}
|
||||
315
agent/connection_manager_test.go
Normal file
315
agent/connection_manager_test.go
Normal file
@@ -0,0 +1,315 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func createTestAgent(t *testing.T) *Agent {
|
||||
dataDir := t.TempDir()
|
||||
agent, err := NewAgent(dataDir)
|
||||
require.NoError(t, err)
|
||||
return agent
|
||||
}
|
||||
|
||||
func createTestServerOptions(t *testing.T) ServerOptions {
|
||||
// Generate test key pair
|
||||
_, privKey, err := ed25519.GenerateKey(nil)
|
||||
require.NoError(t, err)
|
||||
sshPubKey, err := ssh.NewPublicKey(privKey.Public().(ed25519.PublicKey))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Find available port
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
port := listener.Addr().(*net.TCPAddr).Port
|
||||
listener.Close()
|
||||
|
||||
return ServerOptions{
|
||||
Network: "tcp",
|
||||
Addr: fmt.Sprintf("127.0.0.1:%d", port),
|
||||
Keys: []ssh.PublicKey{sshPubKey},
|
||||
}
|
||||
}
|
||||
|
||||
// TestConnectionManager_NewConnectionManager tests connection manager creation
|
||||
func TestConnectionManager_NewConnectionManager(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := newConnectionManager(agent)
|
||||
|
||||
assert.NotNil(t, cm, "Connection manager should not be nil")
|
||||
assert.Equal(t, agent, cm.agent, "Agent reference should be set")
|
||||
assert.Equal(t, Disconnected, cm.State, "Initial state should be Disconnected")
|
||||
assert.Nil(t, cm.eventChan, "Event channel should be nil initially")
|
||||
assert.Nil(t, cm.wsClient, "WebSocket client should be nil initially")
|
||||
assert.Nil(t, cm.wsTicker, "WebSocket ticker should be nil initially")
|
||||
assert.False(t, cm.isConnecting, "isConnecting should be false initially")
|
||||
}
|
||||
|
||||
// TestConnectionManager_StateTransitions tests basic state transitions
|
||||
func TestConnectionManager_StateTransitions(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
initialState := cm.State
|
||||
cm.wsClient = &WebSocketClient{
|
||||
hubURL: &url.URL{
|
||||
Host: "localhost:8080",
|
||||
},
|
||||
}
|
||||
assert.NotNil(t, cm, "Connection manager should not be nil")
|
||||
assert.Equal(t, Disconnected, initialState, "Initial state should be Disconnected")
|
||||
|
||||
// Test state transitions
|
||||
cm.handleStateChange(WebSocketConnected)
|
||||
assert.Equal(t, WebSocketConnected, cm.State, "State should change to WebSocketConnected")
|
||||
|
||||
cm.handleStateChange(SSHConnected)
|
||||
assert.Equal(t, SSHConnected, cm.State, "State should change to SSHConnected")
|
||||
|
||||
cm.handleStateChange(Disconnected)
|
||||
assert.Equal(t, Disconnected, cm.State, "State should change to Disconnected")
|
||||
|
||||
// Test that same state doesn't trigger changes
|
||||
cm.State = WebSocketConnected
|
||||
cm.handleStateChange(WebSocketConnected)
|
||||
assert.Equal(t, WebSocketConnected, cm.State, "Same state should not trigger change")
|
||||
}
|
||||
|
||||
// TestConnectionManager_EventHandling tests event handling logic
|
||||
func TestConnectionManager_EventHandling(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
cm.wsClient = &WebSocketClient{
|
||||
hubURL: &url.URL{
|
||||
Host: "localhost:8080",
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
initialState ConnectionState
|
||||
event ConnectionEvent
|
||||
expectedState ConnectionState
|
||||
}{
|
||||
{
|
||||
name: "WebSocket connect from disconnected",
|
||||
initialState: Disconnected,
|
||||
event: WebSocketConnect,
|
||||
expectedState: WebSocketConnected,
|
||||
},
|
||||
{
|
||||
name: "SSH connect from disconnected",
|
||||
initialState: Disconnected,
|
||||
event: SSHConnect,
|
||||
expectedState: SSHConnected,
|
||||
},
|
||||
{
|
||||
name: "WebSocket disconnect from connected",
|
||||
initialState: WebSocketConnected,
|
||||
event: WebSocketDisconnect,
|
||||
expectedState: Disconnected,
|
||||
},
|
||||
{
|
||||
name: "SSH disconnect from connected",
|
||||
initialState: SSHConnected,
|
||||
event: SSHDisconnect,
|
||||
expectedState: Disconnected,
|
||||
},
|
||||
{
|
||||
name: "WebSocket disconnect from SSH connected (no change)",
|
||||
initialState: SSHConnected,
|
||||
event: WebSocketDisconnect,
|
||||
expectedState: SSHConnected,
|
||||
},
|
||||
{
|
||||
name: "SSH disconnect from WebSocket connected (no change)",
|
||||
initialState: WebSocketConnected,
|
||||
event: SSHDisconnect,
|
||||
expectedState: WebSocketConnected,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cm.State = tc.initialState
|
||||
cm.handleEvent(tc.event)
|
||||
assert.Equal(t, tc.expectedState, cm.State, "State should match expected after event")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConnectionManager_TickerManagement tests WebSocket ticker management
|
||||
func TestConnectionManager_TickerManagement(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
|
||||
// Test starting ticker
|
||||
cm.startWsTicker()
|
||||
assert.NotNil(t, cm.wsTicker, "Ticker should be created")
|
||||
|
||||
// Test stopping ticker (should not panic)
|
||||
assert.NotPanics(t, func() {
|
||||
cm.stopWsTicker()
|
||||
}, "Stopping ticker should not panic")
|
||||
|
||||
// Test stopping nil ticker (should not panic)
|
||||
cm.wsTicker = nil
|
||||
assert.NotPanics(t, func() {
|
||||
cm.stopWsTicker()
|
||||
}, "Stopping nil ticker should not panic")
|
||||
|
||||
// Test restarting ticker
|
||||
cm.startWsTicker()
|
||||
assert.NotNil(t, cm.wsTicker, "Ticker should be recreated")
|
||||
|
||||
// Test resetting existing ticker
|
||||
firstTicker := cm.wsTicker
|
||||
cm.startWsTicker()
|
||||
assert.Equal(t, firstTicker, cm.wsTicker, "Same ticker instance should be reused")
|
||||
|
||||
cm.stopWsTicker()
|
||||
}
|
||||
|
||||
// TestConnectionManager_WebSocketConnectionFlow tests WebSocket connection logic
|
||||
func TestConnectionManager_WebSocketConnectionFlow(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping WebSocket connection test in short mode")
|
||||
}
|
||||
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
|
||||
// Test WebSocket connection without proper environment
|
||||
err := cm.startWebSocketConnection()
|
||||
assert.Error(t, err, "WebSocket connection should fail without proper environment")
|
||||
assert.Equal(t, Disconnected, cm.State, "State should remain Disconnected after failed connection")
|
||||
|
||||
// Test with invalid URL
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "invalid-url")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
// Test with missing token
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
|
||||
_, err2 := newWebSocketClient(agent)
|
||||
assert.Error(t, err2, "WebSocket client creation should fail without token")
|
||||
}
|
||||
|
||||
// TestConnectionManager_ReconnectionLogic tests reconnection prevention logic
|
||||
func TestConnectionManager_ReconnectionLogic(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
cm.eventChan = make(chan ConnectionEvent, 1)
|
||||
|
||||
// Test that isConnecting flag prevents duplicate reconnection attempts
|
||||
// Start from connected state, then simulate disconnect
|
||||
cm.State = WebSocketConnected
|
||||
cm.isConnecting = false
|
||||
|
||||
// First disconnect should trigger reconnection logic
|
||||
cm.handleStateChange(Disconnected)
|
||||
assert.Equal(t, Disconnected, cm.State, "Should change to disconnected")
|
||||
assert.True(t, cm.isConnecting, "Should set isConnecting flag")
|
||||
}
|
||||
|
||||
// TestConnectionManager_ConnectWithRateLimit tests connection rate limiting
|
||||
func TestConnectionManager_ConnectWithRateLimit(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
|
||||
// Set up environment for WebSocket client creation
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "ws://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
// Create WebSocket client
|
||||
wsClient, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
cm.wsClient = wsClient
|
||||
|
||||
// Set recent connection attempt
|
||||
cm.wsClient.lastConnectAttempt = time.Now()
|
||||
|
||||
// Test that connection is rate limited
|
||||
err = cm.startWebSocketConnection()
|
||||
assert.Error(t, err, "Should error due to rate limiting")
|
||||
assert.Contains(t, err.Error(), "already connecting", "Error should indicate rate limiting")
|
||||
|
||||
// Test connection after rate limit expires
|
||||
cm.wsClient.lastConnectAttempt = time.Now().Add(-10 * time.Second)
|
||||
err = cm.startWebSocketConnection()
|
||||
// This will fail due to no actual server, but should not be rate limited
|
||||
assert.Error(t, err, "Connection should fail but not due to rate limiting")
|
||||
assert.NotContains(t, err.Error(), "already connecting", "Error should not indicate rate limiting")
|
||||
}
|
||||
|
||||
// TestConnectionManager_StartWithInvalidConfig tests starting with invalid configuration
|
||||
func TestConnectionManager_StartWithInvalidConfig(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
serverOptions := createTestServerOptions(t)
|
||||
|
||||
// Test starting when already started
|
||||
cm.eventChan = make(chan ConnectionEvent, 5)
|
||||
err := cm.Start(serverOptions)
|
||||
assert.Error(t, err, "Should error when starting already started connection manager")
|
||||
}
|
||||
|
||||
// TestConnectionManager_CloseWebSocket tests WebSocket closing
|
||||
func TestConnectionManager_CloseWebSocket(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
|
||||
// Test closing when no WebSocket client exists
|
||||
assert.NotPanics(t, func() {
|
||||
cm.closeWebSocket()
|
||||
}, "Should not panic when closing nil WebSocket client")
|
||||
|
||||
// Set up environment and create WebSocket client
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "ws://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
wsClient, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
cm.wsClient = wsClient
|
||||
|
||||
// Test closing when WebSocket client exists
|
||||
assert.NotPanics(t, func() {
|
||||
cm.closeWebSocket()
|
||||
}, "Should not panic when closing WebSocket client")
|
||||
}
|
||||
|
||||
// TestConnectionManager_ConnectFlow tests the connect method
|
||||
func TestConnectionManager_ConnectFlow(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
|
||||
// Test connect without WebSocket client
|
||||
assert.NotPanics(t, func() {
|
||||
cm.connect()
|
||||
}, "Connect should not panic without WebSocket client")
|
||||
}
|
||||
117
agent/data_dir.go
Normal file
117
agent/data_dir.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// getDataDir returns the path to the data directory for the agent and an error
|
||||
// if the directory is not valid. Attempts to find the optimal data directory if
|
||||
// no data directories are provided.
|
||||
func getDataDir(dataDirs ...string) (string, error) {
|
||||
if len(dataDirs) > 0 {
|
||||
return testDataDirs(dataDirs)
|
||||
}
|
||||
|
||||
dataDir, _ := GetEnv("DATA_DIR")
|
||||
if dataDir != "" {
|
||||
dataDirs = append(dataDirs, dataDir)
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
dataDirs = append(dataDirs,
|
||||
filepath.Join(os.Getenv("APPDATA"), "beszel-agent"),
|
||||
filepath.Join(os.Getenv("LOCALAPPDATA"), "beszel-agent"),
|
||||
)
|
||||
} else {
|
||||
dataDirs = append(dataDirs, "/var/lib/beszel-agent")
|
||||
if homeDir, err := os.UserHomeDir(); err == nil {
|
||||
dataDirs = append(dataDirs, filepath.Join(homeDir, ".config", "beszel"))
|
||||
}
|
||||
}
|
||||
return testDataDirs(dataDirs)
|
||||
}
|
||||
|
||||
func testDataDirs(paths []string) (string, error) {
|
||||
// first check if the directory exists and is writable
|
||||
for _, path := range paths {
|
||||
if valid, _ := isValidDataDir(path, false); valid {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
// if the directory doesn't exist, try to create it
|
||||
for _, path := range paths {
|
||||
exists, _ := directoryExists(path)
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Verify the created directory is actually writable
|
||||
writable, _ := directoryIsWritable(path)
|
||||
if !writable {
|
||||
continue
|
||||
}
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
return "", errors.New("data directory not found")
|
||||
}
|
||||
|
||||
func isValidDataDir(path string, createIfNotExists bool) (bool, error) {
|
||||
exists, err := directoryExists(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
if !createIfNotExists {
|
||||
return false, nil
|
||||
}
|
||||
if err = os.MkdirAll(path, 0755); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Always check if the directory is writable
|
||||
writable, err := directoryIsWritable(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return writable, nil
|
||||
}
|
||||
|
||||
// directoryExists checks if a directory exists
|
||||
func directoryExists(path string) (bool, error) {
|
||||
// Check if directory exists
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if !stat.IsDir() {
|
||||
return false, fmt.Errorf("%s is not a directory", path)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// directoryIsWritable tests if a directory is writable by creating and removing a temporary file
|
||||
func directoryIsWritable(path string) (bool, error) {
|
||||
testFile := filepath.Join(path, ".write-test")
|
||||
file, err := os.Create(testFile)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer file.Close()
|
||||
defer os.Remove(testFile)
|
||||
return true, nil
|
||||
}
|
||||
263
agent/data_dir_test.go
Normal file
263
agent/data_dir_test.go
Normal file
@@ -0,0 +1,263 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetDataDir(t *testing.T) {
|
||||
// Test with explicit dataDir parameter
|
||||
t.Run("explicit data dir", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
result, err := getDataDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tempDir, result)
|
||||
})
|
||||
|
||||
// Test with explicit non-existent dataDir that can be created
|
||||
t.Run("explicit data dir - create new", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
newDir := filepath.Join(tempDir, "new-data-dir")
|
||||
result, err := getDataDir(newDir)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newDir, result)
|
||||
|
||||
// Verify directory was created
|
||||
stat, err := os.Stat(newDir)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, stat.IsDir())
|
||||
})
|
||||
|
||||
// Test with DATA_DIR environment variable
|
||||
t.Run("DATA_DIR environment variable", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
|
||||
// Set environment variable
|
||||
oldValue := os.Getenv("DATA_DIR")
|
||||
defer func() {
|
||||
if oldValue == "" {
|
||||
os.Unsetenv("BESZEL_AGENT_DATA_DIR")
|
||||
} else {
|
||||
os.Setenv("BESZEL_AGENT_DATA_DIR", oldValue)
|
||||
}
|
||||
}()
|
||||
|
||||
os.Setenv("BESZEL_AGENT_DATA_DIR", tempDir)
|
||||
|
||||
result, err := getDataDir()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tempDir, result)
|
||||
})
|
||||
|
||||
// Test with invalid explicit dataDir
|
||||
t.Run("invalid explicit data dir", func(t *testing.T) {
|
||||
invalidPath := "/invalid/path/that/cannot/be/created"
|
||||
_, err := getDataDir(invalidPath)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
// Test fallback behavior (empty dataDir, no env var)
|
||||
t.Run("fallback to default directories", func(t *testing.T) {
|
||||
// Clear DATA_DIR environment variable
|
||||
oldValue := os.Getenv("DATA_DIR")
|
||||
defer func() {
|
||||
if oldValue == "" {
|
||||
os.Unsetenv("DATA_DIR")
|
||||
} else {
|
||||
os.Setenv("DATA_DIR", oldValue)
|
||||
}
|
||||
}()
|
||||
os.Unsetenv("DATA_DIR")
|
||||
|
||||
// This will try platform-specific defaults, which may or may not work
|
||||
// We're mainly testing that it doesn't panic and returns some result
|
||||
result, err := getDataDir()
|
||||
// We don't assert success/failure here since it depends on system permissions
|
||||
// Just verify we get a string result if no error
|
||||
if err == nil {
|
||||
assert.NotEmpty(t, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestTestDataDirs(t *testing.T) {
|
||||
// Test with existing valid directory
|
||||
t.Run("existing valid directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
result, err := testDataDirs([]string{tempDir})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tempDir, result)
|
||||
})
|
||||
|
||||
// Test with multiple directories, first one valid
|
||||
t.Run("multiple dirs - first valid", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
invalidDir := "/invalid/path"
|
||||
result, err := testDataDirs([]string{tempDir, invalidDir})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tempDir, result)
|
||||
})
|
||||
|
||||
// Test with multiple directories, second one valid
|
||||
t.Run("multiple dirs - second valid", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
invalidDir := "/invalid/path"
|
||||
result, err := testDataDirs([]string{invalidDir, tempDir})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tempDir, result)
|
||||
})
|
||||
|
||||
// Test with non-existing directory that can be created
|
||||
t.Run("create new directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
newDir := filepath.Join(tempDir, "new-dir")
|
||||
result, err := testDataDirs([]string{newDir})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newDir, result)
|
||||
|
||||
// Verify directory was created
|
||||
stat, err := os.Stat(newDir)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, stat.IsDir())
|
||||
})
|
||||
|
||||
// Test with no valid directories
|
||||
t.Run("no valid directories", func(t *testing.T) {
|
||||
invalidPaths := []string{"/invalid/path1", "/invalid/path2"}
|
||||
_, err := testDataDirs(invalidPaths)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "data directory not found")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsValidDataDir(t *testing.T) {
|
||||
// Test with existing directory
|
||||
t.Run("existing directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
valid, err := isValidDataDir(tempDir, false)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, valid)
|
||||
})
|
||||
|
||||
// Test with non-existing directory, createIfNotExists=false
|
||||
t.Run("non-existing dir - no create", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
nonExistentDir := filepath.Join(tempDir, "does-not-exist")
|
||||
valid, err := isValidDataDir(nonExistentDir, false)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, valid)
|
||||
})
|
||||
|
||||
// Test with non-existing directory, createIfNotExists=true
|
||||
t.Run("non-existing dir - create", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
newDir := filepath.Join(tempDir, "new-dir")
|
||||
valid, err := isValidDataDir(newDir, true)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, valid)
|
||||
|
||||
// Verify directory was created
|
||||
stat, err := os.Stat(newDir)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, stat.IsDir())
|
||||
})
|
||||
|
||||
// Test with file instead of directory
|
||||
t.Run("file instead of directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
tempFile := filepath.Join(tempDir, "testfile")
|
||||
err := os.WriteFile(tempFile, []byte("test"), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
valid, err := isValidDataDir(tempFile, false)
|
||||
assert.Error(t, err)
|
||||
assert.False(t, valid)
|
||||
assert.Contains(t, err.Error(), "is not a directory")
|
||||
})
|
||||
}
|
||||
|
||||
func TestDirectoryExists(t *testing.T) {
|
||||
// Test with existing directory
|
||||
t.Run("existing directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
exists, err := directoryExists(tempDir)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, exists)
|
||||
})
|
||||
|
||||
// Test with non-existing directory
|
||||
t.Run("non-existing directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
nonExistentDir := filepath.Join(tempDir, "does-not-exist")
|
||||
exists, err := directoryExists(nonExistentDir)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, exists)
|
||||
})
|
||||
|
||||
// Test with file instead of directory
|
||||
t.Run("file instead of directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
tempFile := filepath.Join(tempDir, "testfile")
|
||||
err := os.WriteFile(tempFile, []byte("test"), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
exists, err := directoryExists(tempFile)
|
||||
assert.Error(t, err)
|
||||
assert.False(t, exists)
|
||||
assert.Contains(t, err.Error(), "is not a directory")
|
||||
})
|
||||
}
|
||||
|
||||
func TestDirectoryIsWritable(t *testing.T) {
|
||||
// Test with writable directory
|
||||
t.Run("writable directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
writable, err := directoryIsWritable(tempDir)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, writable)
|
||||
})
|
||||
|
||||
// Test with non-existing directory
|
||||
t.Run("non-existing directory", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
nonExistentDir := filepath.Join(tempDir, "does-not-exist")
|
||||
writable, err := directoryIsWritable(nonExistentDir)
|
||||
assert.Error(t, err)
|
||||
assert.False(t, writable)
|
||||
})
|
||||
|
||||
// Test with non-writable directory (Unix-like systems only)
|
||||
t.Run("non-writable directory", func(t *testing.T) {
|
||||
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
|
||||
t.Skip("Skipping non-writable directory test on", runtime.GOOS)
|
||||
}
|
||||
|
||||
tempDir := t.TempDir()
|
||||
readOnlyDir := filepath.Join(tempDir, "readonly")
|
||||
|
||||
// Create the directory
|
||||
err := os.Mkdir(readOnlyDir, 0755)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make it read-only
|
||||
err = os.Chmod(readOnlyDir, 0444)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Restore permissions after test for cleanup
|
||||
defer func() {
|
||||
os.Chmod(readOnlyDir, 0755)
|
||||
}()
|
||||
|
||||
writable, err := directoryIsWritable(readOnlyDir)
|
||||
assert.Error(t, err)
|
||||
assert.False(t, writable)
|
||||
})
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/system"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/disk"
|
||||
)
|
||||
|
||||
@@ -36,7 +38,12 @@ func (a *Agent) initializeDiskInfo() {
|
||||
|
||||
// Helper function to add a filesystem to fsStats if it doesn't exist
|
||||
addFsStat := func(device, mountpoint string, root bool) {
|
||||
key := filepath.Base(device)
|
||||
var key string
|
||||
if runtime.GOOS == "windows" {
|
||||
key = device
|
||||
} else {
|
||||
key = filepath.Base(device)
|
||||
}
|
||||
var ioMatch bool
|
||||
if _, exists := a.fsStats[key]; !exists {
|
||||
if root {
|
||||
@@ -1,7 +1,7 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/container"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/container"
|
||||
|
||||
"github.com/blang/semver"
|
||||
)
|
||||
|
||||
@@ -26,6 +28,10 @@ type dockerManager struct {
|
||||
containerStatsMap map[string]*container.Stats // Keeps track of container stats
|
||||
validIds map[string]struct{} // Map of valid container ids, used to prune invalid containers from containerStatsMap
|
||||
goodDockerVersion bool // Whether docker version is at least 25.0.0 (one-shot works correctly)
|
||||
isWindows bool // Whether the Docker Engine API is running on Windows
|
||||
buf *bytes.Buffer // Buffer to store and read response bodies
|
||||
decoder *json.Decoder // Reusable JSON decoder that reads from buf
|
||||
apiStats *container.ApiStats // Reusable API stats object
|
||||
}
|
||||
|
||||
// userAgentRoundTripper is a custom http.RoundTripper that adds a User-Agent header to all requests
|
||||
@@ -62,13 +68,14 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
dm.apiContainerList = dm.apiContainerList[:0]
|
||||
if err := json.NewDecoder(resp.Body).Decode(&dm.apiContainerList); err != nil {
|
||||
if err := dm.decode(resp, &dm.apiContainerList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dm.isWindows = strings.Contains(resp.Header.Get("Server"), "windows")
|
||||
|
||||
containersLength := len(dm.apiContainerList)
|
||||
|
||||
// store valid ids to clean up old container ids from map
|
||||
@@ -109,7 +116,8 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
|
||||
// retry failed containers separately so we can run them in parallel (docker 24 bug)
|
||||
if len(failedContainers) > 0 {
|
||||
slog.Debug("Retrying failed containers", "count", len(failedContainers))
|
||||
for _, ctr := range failedContainers {
|
||||
for i := range failedContainers {
|
||||
ctr := failedContainers[i]
|
||||
dm.queue()
|
||||
go func() {
|
||||
defer dm.dequeue()
|
||||
@@ -162,31 +170,45 @@ func (dm *dockerManager) updateContainerStats(ctr *container.ApiInfo) error {
|
||||
stats.NetworkRecv = 0
|
||||
|
||||
// docker host container stats response
|
||||
var res container.ApiStats
|
||||
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
||||
// res := dm.getApiStats()
|
||||
// defer dm.putApiStats(res)
|
||||
//
|
||||
|
||||
res := dm.apiStats
|
||||
res.Networks = nil
|
||||
if err := dm.decode(resp, res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if container has valid data, otherwise may be in restart loop (#103)
|
||||
if res.MemoryStats.Usage == 0 {
|
||||
return fmt.Errorf("%s - no memory stats - see https://github.com/henrygd/beszel/issues/144", name)
|
||||
// calculate cpu and memory stats
|
||||
var usedMemory uint64
|
||||
var cpuPct float64
|
||||
|
||||
// store current cpu stats
|
||||
prevCpuContainer, prevCpuSystem := stats.CpuContainer, stats.CpuSystem
|
||||
stats.CpuContainer = res.CPUStats.CPUUsage.TotalUsage
|
||||
stats.CpuSystem = res.CPUStats.SystemUsage
|
||||
|
||||
if dm.isWindows {
|
||||
usedMemory = res.MemoryStats.PrivateWorkingSet
|
||||
cpuPct = res.CalculateCpuPercentWindows(prevCpuContainer, stats.PrevReadTime)
|
||||
} else {
|
||||
// check if container has valid data, otherwise may be in restart loop (#103)
|
||||
if res.MemoryStats.Usage == 0 {
|
||||
return fmt.Errorf("%s - no memory stats - see https://github.com/henrygd/beszel/issues/144", name)
|
||||
}
|
||||
memCache := res.MemoryStats.Stats.InactiveFile
|
||||
if memCache == 0 {
|
||||
memCache = res.MemoryStats.Stats.Cache
|
||||
}
|
||||
usedMemory = res.MemoryStats.Usage - memCache
|
||||
|
||||
cpuPct = res.CalculateCpuPercentLinux(prevCpuContainer, prevCpuSystem)
|
||||
}
|
||||
|
||||
// memory (https://docs.docker.com/reference/cli/docker/container/stats/)
|
||||
memCache := res.MemoryStats.Stats.InactiveFile
|
||||
if memCache == 0 {
|
||||
memCache = res.MemoryStats.Stats.Cache
|
||||
}
|
||||
usedMemory := res.MemoryStats.Usage - memCache
|
||||
|
||||
// cpu
|
||||
cpuDelta := res.CPUStats.CPUUsage.TotalUsage - stats.PrevCpu[0]
|
||||
systemDelta := res.CPUStats.SystemUsage - stats.PrevCpu[1]
|
||||
cpuPct := float64(cpuDelta) / float64(systemDelta) * 100
|
||||
if cpuPct > 100 {
|
||||
return fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct)
|
||||
}
|
||||
stats.PrevCpu = [2]uint64{res.CPUStats.CPUUsage.TotalUsage, res.CPUStats.SystemUsage}
|
||||
|
||||
// network
|
||||
var total_sent, total_recv uint64
|
||||
@@ -194,21 +216,25 @@ func (dm *dockerManager) updateContainerStats(ctr *container.ApiInfo) error {
|
||||
total_sent += v.TxBytes
|
||||
total_recv += v.RxBytes
|
||||
}
|
||||
var sent_delta, recv_delta float64
|
||||
// prevent first run from sending all prev sent/recv bytes
|
||||
if initialized {
|
||||
secondsElapsed := time.Since(stats.PrevNet.Time).Seconds()
|
||||
sent_delta = float64(total_sent-stats.PrevNet.Sent) / secondsElapsed
|
||||
recv_delta = float64(total_recv-stats.PrevNet.Recv) / secondsElapsed
|
||||
var sent_delta, recv_delta uint64
|
||||
millisecondsElapsed := uint64(time.Since(stats.PrevReadTime).Milliseconds())
|
||||
if initialized && millisecondsElapsed > 0 {
|
||||
// get bytes per second
|
||||
sent_delta = (total_sent - stats.PrevNet.Sent) * 1000 / millisecondsElapsed
|
||||
recv_delta = (total_recv - stats.PrevNet.Recv) * 1000 / millisecondsElapsed
|
||||
// check for unrealistic network values (> 5GB/s)
|
||||
if sent_delta > 5e9 || recv_delta > 5e9 {
|
||||
slog.Warn("Bad network delta", "container", name)
|
||||
sent_delta, recv_delta = 0, 0
|
||||
}
|
||||
}
|
||||
stats.PrevNet.Sent = total_sent
|
||||
stats.PrevNet.Recv = total_recv
|
||||
stats.PrevNet.Time = time.Now()
|
||||
stats.PrevNet.Sent, stats.PrevNet.Recv = total_sent, total_recv
|
||||
|
||||
stats.Cpu = twoDecimals(cpuPct)
|
||||
stats.Mem = bytesToMegabytes(float64(usedMemory))
|
||||
stats.NetworkSent = bytesToMegabytes(sent_delta)
|
||||
stats.NetworkRecv = bytesToMegabytes(recv_delta)
|
||||
stats.NetworkSent = bytesToMegabytes(float64(sent_delta))
|
||||
stats.NetworkRecv = bytesToMegabytes(float64(recv_delta))
|
||||
stats.PrevReadTime = res.Read
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -224,14 +250,16 @@ func (dm *dockerManager) deleteContainerStatsSync(id string) {
|
||||
func newDockerManager(a *Agent) *dockerManager {
|
||||
dockerHost, exists := GetEnv("DOCKER_HOST")
|
||||
if exists {
|
||||
slog.Info("DOCKER_HOST", "host", dockerHost)
|
||||
// return nil if set to empty string
|
||||
if dockerHost == "" {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
dockerHost = getDockerHost()
|
||||
}
|
||||
|
||||
parsedURL, err := url.Parse(dockerHost)
|
||||
if err != nil {
|
||||
slog.Error("Error parsing DOCKER_HOST", "err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -279,6 +307,7 @@ func newDockerManager(a *Agent) *dockerManager {
|
||||
containerStatsMap: make(map[string]*container.Stats),
|
||||
sem: make(chan struct{}, 5),
|
||||
apiContainerList: []*container.ApiInfo{},
|
||||
apiStats: &container.ApiStats{},
|
||||
}
|
||||
|
||||
// If using podman, return client
|
||||
@@ -297,9 +326,8 @@ func newDockerManager(a *Agent) *dockerManager {
|
||||
if err != nil {
|
||||
return manager
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err := json.NewDecoder(resp.Body).Decode(&versionInfo); err != nil {
|
||||
if err := manager.decode(resp, &versionInfo); err != nil {
|
||||
return manager
|
||||
}
|
||||
|
||||
@@ -313,6 +341,22 @@ func newDockerManager(a *Agent) *dockerManager {
|
||||
return manager
|
||||
}
|
||||
|
||||
// Decodes Docker API JSON response using a reusable buffer and decoder. Not thread safe.
|
||||
func (dm *dockerManager) decode(resp *http.Response, d any) error {
|
||||
if dm.buf == nil {
|
||||
// initialize buffer with 256kb starting size
|
||||
dm.buf = bytes.NewBuffer(make([]byte, 0, 1024*256))
|
||||
dm.decoder = json.NewDecoder(dm.buf)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer dm.buf.Reset()
|
||||
_, err := dm.buf.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dm.decoder.Decode(d)
|
||||
}
|
||||
|
||||
// Test docker / podman sockets and return if one exists
|
||||
func getDockerHost() string {
|
||||
scheme := "unix://"
|
||||
@@ -1,7 +1,6 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/system"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
@@ -13,29 +12,31 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
const (
|
||||
// Commands
|
||||
nvidiaSmiCmd = "nvidia-smi"
|
||||
rocmSmiCmd = "rocm-smi"
|
||||
tegraStatsCmd = "tegrastats"
|
||||
nvidiaSmiCmd string = "nvidia-smi"
|
||||
rocmSmiCmd string = "rocm-smi"
|
||||
tegraStatsCmd string = "tegrastats"
|
||||
|
||||
// Polling intervals
|
||||
nvidiaSmiInterval = "4" // in seconds
|
||||
tegraStatsInterval = "3700" // in milliseconds
|
||||
rocmSmiInterval = 4300 * time.Millisecond
|
||||
nvidiaSmiInterval string = "4" // in seconds
|
||||
tegraStatsInterval string = "3700" // in milliseconds
|
||||
rocmSmiInterval time.Duration = 4300 * time.Millisecond
|
||||
|
||||
// Command retry and timeout constants
|
||||
retryWaitTime = 5 * time.Second
|
||||
maxFailureRetries = 5
|
||||
retryWaitTime time.Duration = 5 * time.Second
|
||||
maxFailureRetries int = 5
|
||||
|
||||
cmdBufferSize = 10 * 1024
|
||||
cmdBufferSize uint16 = 10 * 1024
|
||||
|
||||
// Unit Conversions
|
||||
mebibytesInAMegabyte = 1.024 // nvidia-smi reports memory in MiB
|
||||
milliwattsInAWatt = 1000.0 // tegrastats reports power in mW
|
||||
mebibytesInAMegabyte float64 = 1.024 // nvidia-smi reports memory in MiB
|
||||
milliwattsInAWatt float64 = 1000.0 // tegrastats reports power in mW
|
||||
)
|
||||
|
||||
// GPUManager manages data collection for GPUs (either Nvidia or AMD)
|
||||
@@ -125,14 +126,13 @@ func (gm *GPUManager) getJetsonParser() func(output []byte) bool {
|
||||
// TODO: Maybe use VDD_IN for Nano / NX and add a total system power chart
|
||||
powerPattern := regexp.MustCompile(`(GPU_SOC|CPU_GPU_CV) (\d+)mW`)
|
||||
|
||||
// jetson devices have only one gpu so we'll just initialize here
|
||||
gpuData := &system.GPUData{Name: "GPU"}
|
||||
gm.GpuDataMap["0"] = gpuData
|
||||
|
||||
return func(output []byte) bool {
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
// we get gpu name from the intitial run of nvidia-smi, so return if it hasn't been initialized
|
||||
gpuData, ok := gm.GpuDataMap["0"]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
// Parse RAM usage
|
||||
ramMatches := ramPattern.FindSubmatch(output)
|
||||
if ramMatches != nil {
|
||||
@@ -184,12 +184,6 @@ func (gm *GPUManager) parseNvidiaData(output []byte) bool {
|
||||
if _, ok := gm.GpuDataMap[id]; !ok {
|
||||
name := strings.TrimPrefix(fields[1], "NVIDIA ")
|
||||
gm.GpuDataMap[id] = &system.GPUData{Name: strings.TrimSuffix(name, " Laptop GPU")}
|
||||
// check if tegrastats is active - if so we will only use nvidia-smi to get gpu name
|
||||
// - nvidia-smi does not provide metrics for tegra / jetson devices
|
||||
// this will end the nvidia-smi collector
|
||||
if gm.tegrastats {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// update gpu data
|
||||
gpu := gm.GpuDataMap[id]
|
||||
@@ -250,21 +244,26 @@ func (gm *GPUManager) GetCurrentData() map[string]system.GPUData {
|
||||
// copy / reset the data
|
||||
gpuData := make(map[string]system.GPUData, len(gm.GpuDataMap))
|
||||
for id, gpu := range gm.GpuDataMap {
|
||||
// sum the data
|
||||
gpu.Temperature = twoDecimals(gpu.Temperature)
|
||||
gpu.MemoryUsed = twoDecimals(gpu.MemoryUsed)
|
||||
gpu.MemoryTotal = twoDecimals(gpu.MemoryTotal)
|
||||
gpu.Usage = twoDecimals(gpu.Usage / gpu.Count)
|
||||
gpu.Power = twoDecimals(gpu.Power / gpu.Count)
|
||||
// reset the count
|
||||
gpu.Count = 1
|
||||
// dereference to avoid overwriting anything else
|
||||
gpuCopy := *gpu
|
||||
gpuAvg := *gpu
|
||||
|
||||
gpuAvg.Temperature = twoDecimals(gpu.Temperature)
|
||||
gpuAvg.MemoryUsed = twoDecimals(gpu.MemoryUsed)
|
||||
gpuAvg.MemoryTotal = twoDecimals(gpu.MemoryTotal)
|
||||
|
||||
// avoid division by zero
|
||||
if gpu.Count > 0 {
|
||||
gpuAvg.Usage = twoDecimals(gpu.Usage / gpu.Count)
|
||||
gpuAvg.Power = twoDecimals(gpu.Power / gpu.Count)
|
||||
}
|
||||
|
||||
// reset accumulators in the original
|
||||
gpu.Usage, gpu.Power, gpu.Count = 0, 0, 0
|
||||
|
||||
// append id to the name if there are multiple GPUs with the same name
|
||||
if nameCounts[gpu.Name] > 1 {
|
||||
gpuCopy.Name = fmt.Sprintf("%s %s", gpu.Name, id)
|
||||
gpuAvg.Name = fmt.Sprintf("%s %s", gpu.Name, id)
|
||||
}
|
||||
gpuData[id] = gpuCopy
|
||||
gpuData[id] = gpuAvg
|
||||
}
|
||||
slog.Debug("GPU", "data", gpuData)
|
||||
return gpuData
|
||||
@@ -283,6 +282,7 @@ func (gm *GPUManager) detectGPUs() error {
|
||||
}
|
||||
if _, err := exec.LookPath(tegraStatsCmd); err == nil {
|
||||
gm.tegrastats = true
|
||||
gm.nvidiaSmi = false
|
||||
}
|
||||
if gm.nvidiaSmi || gm.rocmSmi || gm.tegrastats {
|
||||
return nil
|
||||
@@ -297,9 +297,11 @@ func (gm *GPUManager) startCollector(command string) {
|
||||
}
|
||||
switch command {
|
||||
case nvidiaSmiCmd:
|
||||
collector.cmdArgs = []string{"-l", nvidiaSmiInterval,
|
||||
collector.cmdArgs = []string{
|
||||
"-l", nvidiaSmiInterval,
|
||||
"--query-gpu=index,name,temperature.gpu,memory.used,memory.total,utilization.gpu,power.draw",
|
||||
"--format=csv,noheader,nounits"}
|
||||
"--format=csv,noheader,nounits",
|
||||
}
|
||||
collector.parse = gm.parseNvidiaData
|
||||
go collector.start()
|
||||
case tegraStatsCmd:
|
||||
@@ -4,12 +4,13 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/system"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -251,14 +252,13 @@ func TestParseJetsonData(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
gm *GPUManager
|
||||
wantMetrics *system.GPUData
|
||||
}{
|
||||
{
|
||||
name: "valid data",
|
||||
input: "11-14-2024 22:54:33 RAM 4300/30698MB GR3D_FREQ 45% tj@52.468C VDD_GPU_SOC 2171mW",
|
||||
wantMetrics: &system.GPUData{
|
||||
Name: "Jetson",
|
||||
Name: "GPU",
|
||||
MemoryUsed: 4300.0,
|
||||
MemoryTotal: 30698.0,
|
||||
Usage: 45.0,
|
||||
@@ -271,7 +271,7 @@ func TestParseJetsonData(t *testing.T) {
|
||||
name: "more valid data",
|
||||
input: "11-15-2024 08:38:09 RAM 6185/7620MB (lfb 8x2MB) SWAP 851/3810MB (cached 1MB) CPU [15%@729,11%@729,14%@729,13%@729,11%@729,8%@729] EMC_FREQ 43%@2133 GR3D_FREQ 63%@[621] NVDEC off NVJPG off NVJPG1 off VIC off OFA off APE 200 cpu@53.968C soc2@52.437C soc0@50.75C gpu@53.343C tj@53.968C soc1@51.656C VDD_IN 12479mW/12479mW VDD_CPU_GPU_CV 4667mW/4667mW VDD_SOC 2817mW/2817mW",
|
||||
wantMetrics: &system.GPUData{
|
||||
Name: "Jetson",
|
||||
Name: "GPU",
|
||||
MemoryUsed: 6185.0,
|
||||
MemoryTotal: 7620.0,
|
||||
Usage: 63.0,
|
||||
@@ -280,11 +280,24 @@ func TestParseJetsonData(t *testing.T) {
|
||||
Count: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "orin nano",
|
||||
input: "06-18-2025 11:25:24 RAM 3452/7620MB (lfb 25x4MB) SWAP 1518/16384MB (cached 174MB) CPU [1%@1420,2%@1420,0%@1420,2%@1420,2%@729,1%@729] GR3D_FREQ 0% cpu@50.031C soc2@49.031C soc0@50C gpu@49.031C tj@50.25C soc1@50.25C VDD_IN 4824mW/4824mW VDD_CPU_GPU_CV 518mW/518mW VDD_SOC 1475mW/1475mW",
|
||||
wantMetrics: &system.GPUData{
|
||||
Name: "GPU",
|
||||
MemoryUsed: 3452.0,
|
||||
MemoryTotal: 7620.0,
|
||||
Usage: 0.0,
|
||||
Temperature: 50.25,
|
||||
Power: 0.518,
|
||||
Count: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "missing temperature",
|
||||
input: "11-14-2024 22:54:33 RAM 4300/30698MB GR3D_FREQ 45% VDD_GPU_SOC 2171mW",
|
||||
wantMetrics: &system.GPUData{
|
||||
Name: "Jetson",
|
||||
Name: "GPU",
|
||||
MemoryUsed: 4300.0,
|
||||
MemoryTotal: 30698.0,
|
||||
Usage: 45.0,
|
||||
@@ -292,32 +305,18 @@ func TestParseJetsonData(t *testing.T) {
|
||||
Count: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no gpu defined by nvidia-smi",
|
||||
input: "11-14-2024 22:54:33 RAM 4300/30698MB GR3D_FREQ 45% VDD_GPU_SOC 2171mW",
|
||||
gm: &GPUManager{
|
||||
GpuDataMap: map[string]*system.GPUData{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.gm != nil {
|
||||
// should return if no gpu set by nvidia-smi
|
||||
assert.Empty(t, tt.gm.GpuDataMap)
|
||||
return
|
||||
gm := &GPUManager{
|
||||
GpuDataMap: make(map[string]*system.GPUData),
|
||||
}
|
||||
tt.gm = &GPUManager{
|
||||
GpuDataMap: map[string]*system.GPUData{
|
||||
"0": {Name: "Jetson"},
|
||||
},
|
||||
}
|
||||
parser := tt.gm.getJetsonParser()
|
||||
parser := gm.getJetsonParser()
|
||||
valid := parser([]byte(tt.input))
|
||||
assert.Equal(t, true, valid)
|
||||
|
||||
got := tt.gm.GpuDataMap["0"]
|
||||
got := gm.GpuDataMap["0"]
|
||||
require.NotNil(t, got)
|
||||
assert.Equal(t, tt.wantMetrics.Name, got.Name)
|
||||
assert.InDelta(t, tt.wantMetrics.MemoryUsed, got.MemoryUsed, 0.01)
|
||||
@@ -333,44 +332,85 @@ func TestParseJetsonData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetCurrentData(t *testing.T) {
|
||||
gm := &GPUManager{
|
||||
GpuDataMap: map[string]*system.GPUData{
|
||||
"0": {
|
||||
Name: "GPU1",
|
||||
Temperature: 50,
|
||||
MemoryUsed: 2048,
|
||||
MemoryTotal: 4096,
|
||||
Usage: 100, // 100 over 2 counts = 50 avg
|
||||
Power: 200, // 200 over 2 counts = 100 avg
|
||||
Count: 2,
|
||||
t.Run("calculates averages and resets accumulators", func(t *testing.T) {
|
||||
gm := &GPUManager{
|
||||
GpuDataMap: map[string]*system.GPUData{
|
||||
"0": {
|
||||
Name: "GPU1",
|
||||
Temperature: 50,
|
||||
MemoryUsed: 2048,
|
||||
MemoryTotal: 4096,
|
||||
Usage: 100, // 100 over 2 counts = 50 avg
|
||||
Power: 200, // 200 over 2 counts = 100 avg
|
||||
Count: 2,
|
||||
},
|
||||
"1": {
|
||||
Name: "GPU1",
|
||||
Temperature: 60,
|
||||
MemoryUsed: 3072,
|
||||
MemoryTotal: 8192,
|
||||
Usage: 30,
|
||||
Power: 60,
|
||||
Count: 1,
|
||||
},
|
||||
"2": {
|
||||
Name: "GPU 2",
|
||||
Temperature: 70,
|
||||
MemoryUsed: 4096,
|
||||
MemoryTotal: 8192,
|
||||
Usage: 200,
|
||||
Power: 400,
|
||||
Count: 1,
|
||||
},
|
||||
},
|
||||
"1": {
|
||||
Name: "GPU1",
|
||||
Temperature: 60,
|
||||
MemoryUsed: 3072,
|
||||
MemoryTotal: 8192,
|
||||
Usage: 30,
|
||||
Power: 60,
|
||||
Count: 1,
|
||||
}
|
||||
|
||||
result := gm.GetCurrentData()
|
||||
|
||||
// Verify name disambiguation
|
||||
assert.Equal(t, "GPU1 0", result["0"].Name)
|
||||
assert.Equal(t, "GPU1 1", result["1"].Name)
|
||||
assert.Equal(t, "GPU 2", result["2"].Name)
|
||||
|
||||
// Check averaged values in the result
|
||||
assert.InDelta(t, 50.0, result["0"].Usage, 0.01)
|
||||
assert.InDelta(t, 100.0, result["0"].Power, 0.01)
|
||||
assert.InDelta(t, 30.0, result["1"].Usage, 0.01)
|
||||
assert.InDelta(t, 60.0, result["1"].Power, 0.01)
|
||||
|
||||
// Verify that accumulators in the original map are reset
|
||||
assert.Equal(t, float64(0), gm.GpuDataMap["0"].Count, "GPU 0 Count should be reset")
|
||||
assert.Equal(t, float64(0), gm.GpuDataMap["0"].Usage, "GPU 0 Usage should be reset")
|
||||
assert.Equal(t, float64(0), gm.GpuDataMap["0"].Power, "GPU 0 Power should be reset")
|
||||
assert.Equal(t, float64(0), gm.GpuDataMap["1"].Count, "GPU 1 Count should be reset")
|
||||
assert.Equal(t, float64(0), gm.GpuDataMap["1"].Usage, "GPU 1 Usage should be reset")
|
||||
assert.Equal(t, float64(0), gm.GpuDataMap["1"].Power, "GPU 1 Power should be reset")
|
||||
})
|
||||
|
||||
t.Run("handles zero count without panicking", func(t *testing.T) {
|
||||
gm := &GPUManager{
|
||||
GpuDataMap: map[string]*system.GPUData{
|
||||
"0": {
|
||||
Name: "TestGPU",
|
||||
Count: 0,
|
||||
Usage: 0,
|
||||
Power: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
result := gm.GetCurrentData()
|
||||
var result map[string]system.GPUData
|
||||
assert.NotPanics(t, func() {
|
||||
result = gm.GetCurrentData()
|
||||
})
|
||||
|
||||
// Verify name disambiguation
|
||||
assert.Equal(t, "GPU1 0", result["0"].Name)
|
||||
assert.Equal(t, "GPU1 1", result["1"].Name)
|
||||
// Check that usage and power are 0
|
||||
assert.Equal(t, 0.0, result["0"].Usage)
|
||||
assert.Equal(t, 0.0, result["0"].Power)
|
||||
|
||||
// Check averaged values
|
||||
assert.InDelta(t, 50.0, result["0"].Usage, 0.01)
|
||||
assert.InDelta(t, 100.0, result["0"].Power, 0.01)
|
||||
assert.InDelta(t, 30.0, result["1"].Usage, 0.01)
|
||||
assert.InDelta(t, 60.0, result["1"].Power, 0.01)
|
||||
|
||||
// Verify reset counts
|
||||
assert.Equal(t, float64(1), gm.GpuDataMap["0"].Count)
|
||||
assert.Equal(t, float64(1), gm.GpuDataMap["1"].Count)
|
||||
// Verify reset count
|
||||
assert.Equal(t, float64(0), gm.GpuDataMap["0"].Count)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDetectGPUs(t *testing.T) {
|
||||
@@ -443,7 +483,7 @@ echo "test"`
|
||||
}
|
||||
return nil
|
||||
},
|
||||
wantNvidiaSmi: true,
|
||||
wantNvidiaSmi: false,
|
||||
wantRocmSmi: true,
|
||||
wantTegrastats: true,
|
||||
wantErr: false,
|
||||
@@ -737,6 +777,18 @@ func TestAccumulation(t *testing.T) {
|
||||
assert.InDelta(t, expected.avgUsage, gpu.Usage, 0.01, "Average usage in GetCurrentData should match")
|
||||
assert.InDelta(t, expected.avgPower, gpu.Power, 0.01, "Average power in GetCurrentData should match")
|
||||
}
|
||||
|
||||
// Verify that accumulators in the original map are reset
|
||||
for id := range tt.expectedValues {
|
||||
gpu, exists := gm.GpuDataMap[id]
|
||||
assert.True(t, exists, "GPU with ID %s should still exist after GetCurrentData", id)
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
assert.Equal(t, float64(0), gpu.Count, "Count should be reset for GPU ID %s", id)
|
||||
assert.Equal(t, float64(0), gpu.Usage, "Usage should be reset for GPU ID %s", id)
|
||||
assert.Equal(t, float64(0), gpu.Power, "Power should be reset for GPU ID %s", id)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
43
agent/health/health.go
Normal file
43
agent/health/health.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Package health provides functions to check and update the health of the agent.
|
||||
// It uses a file in the temp directory to store the timestamp of the last connection attempt.
|
||||
// If the timestamp is older than 90 seconds, the agent is considered unhealthy.
|
||||
// NB: The agent must be started with the Start() method to be considered healthy.
|
||||
package health
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// healthFile is the path to the health file
|
||||
var healthFile = filepath.Join(os.TempDir(), "beszel_health")
|
||||
|
||||
// Check checks if the agent is connected by checking the modification time of the health file
|
||||
func Check() error {
|
||||
fileInfo, err := os.Stat(healthFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if time.Since(fileInfo.ModTime()) > 91*time.Second {
|
||||
log.Println("over 90 seconds since last connection")
|
||||
return errors.New("unhealthy")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update updates the modification time of the health file
|
||||
func Update() error {
|
||||
file, err := os.Create(healthFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
// CleanUp removes the health file
|
||||
func CleanUp() error {
|
||||
return os.Remove(healthFile)
|
||||
}
|
||||
67
agent/health/health_test.go
Normal file
67
agent/health/health_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package health
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"testing/synctest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
// Override healthFile to use a temporary directory for this test.
|
||||
originalHealthFile := healthFile
|
||||
tmpDir := t.TempDir()
|
||||
healthFile = filepath.Join(tmpDir, "beszel_health_test")
|
||||
defer func() { healthFile = originalHealthFile }()
|
||||
|
||||
t.Run("check with no health file", func(t *testing.T) {
|
||||
err := Check()
|
||||
require.Error(t, err)
|
||||
assert.True(t, os.IsNotExist(err), "expected a file-not-exist error, but got: %v", err)
|
||||
})
|
||||
|
||||
t.Run("update and check", func(t *testing.T) {
|
||||
err := Update()
|
||||
require.NoError(t, err, "Update() failed")
|
||||
|
||||
err = Check()
|
||||
assert.NoError(t, err, "Check() failed immediately after Update()")
|
||||
})
|
||||
|
||||
// This test uses synctest to simulate time passing.
|
||||
// NOTE: This test requires GOEXPERIMENT=synctest to run.
|
||||
t.Run("check with simulated time", func(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
// Update the file to set the initial timestamp.
|
||||
require.NoError(t, Update(), "Update() failed inside synctest")
|
||||
|
||||
// Set the mtime to the current fake time to align the file's timestamp with the simulated clock.
|
||||
now := time.Now()
|
||||
require.NoError(t, os.Chtimes(healthFile, now, now), "Chtimes failed")
|
||||
|
||||
// Wait a duration less than the threshold.
|
||||
time.Sleep(89 * time.Second)
|
||||
synctest.Wait()
|
||||
|
||||
// The check should still pass.
|
||||
assert.NoError(t, Check(), "Check() failed after 89s")
|
||||
|
||||
// Wait for the total duration to exceed the threshold.
|
||||
time.Sleep(5 * time.Second)
|
||||
synctest.Wait()
|
||||
|
||||
// The check should now fail as unhealthy.
|
||||
err := Check()
|
||||
require.Error(t, err, "Check() should have failed after 91s")
|
||||
assert.Equal(t, "unhealthy", err.Error(), "Check() returned wrong error")
|
||||
})
|
||||
})
|
||||
}
|
||||
80
agent/lhm/beszel_lhm.cs
Normal file
80
agent/lhm/beszel_lhm.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
var computer = new Computer
|
||||
{
|
||||
IsCpuEnabled = true,
|
||||
IsGpuEnabled = true,
|
||||
IsMemoryEnabled = true,
|
||||
IsMotherboardEnabled = true,
|
||||
IsStorageEnabled = true,
|
||||
// IsPsuEnabled = true,
|
||||
// IsNetworkEnabled = true,
|
||||
};
|
||||
computer.Open();
|
||||
|
||||
var reader = Console.In;
|
||||
var writer = Console.Out;
|
||||
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.Trim().Equals("getTemps", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var hw in computer.Hardware)
|
||||
{
|
||||
// process main hardware sensors
|
||||
ProcessSensors(hw, writer);
|
||||
|
||||
// process subhardware sensors
|
||||
foreach (var subhardware in hw.SubHardware)
|
||||
{
|
||||
ProcessSensors(subhardware, writer);
|
||||
}
|
||||
}
|
||||
// send empty line to signal end of sensor data
|
||||
writer.WriteLine();
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
computer.Close();
|
||||
}
|
||||
|
||||
static void ProcessSensors(IHardware hardware, System.IO.TextWriter writer)
|
||||
{
|
||||
var updated = false;
|
||||
foreach (var sensor in hardware.Sensors)
|
||||
{
|
||||
var validTemp = sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue;
|
||||
if (!validTemp || sensor.Name.Contains("Distance"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!updated)
|
||||
{
|
||||
hardware.Update();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
var name = sensor.Name;
|
||||
// if sensor.Name starts with "Temperature" replace with hardware.Identifier but retain the rest of the name.
|
||||
// usually this is a number like Temperature 3
|
||||
if (sensor.Name.StartsWith("Temperature"))
|
||||
{
|
||||
name = hardware.Identifier.ToString().Replace("/", "_").TrimStart('_') + sensor.Name.Substring(11);
|
||||
}
|
||||
|
||||
// invariant culture assures the value is parsable as a float
|
||||
var value = sensor.Value.Value.ToString("0.##", CultureInfo.InvariantCulture);
|
||||
// write the name and value to the writer
|
||||
writer.WriteLine($"{name}|{value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
agent/lhm/beszel_lhm.csproj
Normal file
11
agent/lhm/beszel_lhm.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LibreHardwareMonitorLib" Version="0.9.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -57,6 +57,7 @@ func (a *Agent) skipNetworkInterface(v psutilNet.IOCountersStat) bool {
|
||||
strings.HasPrefix(v.Name, "docker"),
|
||||
strings.HasPrefix(v.Name, "br-"),
|
||||
strings.HasPrefix(v.Name, "veth"),
|
||||
strings.HasPrefix(v.Name, "bond"),
|
||||
v.BytesRecv == 0,
|
||||
v.BytesSent == 0:
|
||||
return true
|
||||
198
agent/sensors.go
Normal file
198
agent/sensors.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/common"
|
||||
"github.com/shirou/gopsutil/v4/sensors"
|
||||
)
|
||||
|
||||
type SensorConfig struct {
|
||||
context context.Context
|
||||
sensors map[string]struct{}
|
||||
primarySensor string
|
||||
isBlacklist bool
|
||||
hasWildcards bool
|
||||
skipCollection bool
|
||||
}
|
||||
|
||||
func (a *Agent) newSensorConfig() *SensorConfig {
|
||||
primarySensor, _ := GetEnv("PRIMARY_SENSOR")
|
||||
sysSensors, _ := GetEnv("SYS_SENSORS")
|
||||
sensorsEnvVal, sensorsSet := GetEnv("SENSORS")
|
||||
skipCollection := sensorsSet && sensorsEnvVal == ""
|
||||
|
||||
return a.newSensorConfigWithEnv(primarySensor, sysSensors, sensorsEnvVal, skipCollection)
|
||||
}
|
||||
|
||||
// Matches sensors.TemperaturesWithContext to allow for panic recovery (gopsutil/issues/1832)
|
||||
type getTempsFn func(ctx context.Context) ([]sensors.TemperatureStat, error)
|
||||
|
||||
// newSensorConfigWithEnv creates a SensorConfig with the provided environment variables
|
||||
// sensorsSet indicates if the SENSORS environment variable was explicitly set (even to empty string)
|
||||
func (a *Agent) newSensorConfigWithEnv(primarySensor, sysSensors, sensorsEnvVal string, skipCollection bool) *SensorConfig {
|
||||
config := &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: primarySensor,
|
||||
skipCollection: skipCollection,
|
||||
sensors: make(map[string]struct{}),
|
||||
}
|
||||
|
||||
// Set sensors context (allows overriding sys location for sensors)
|
||||
if sysSensors != "" {
|
||||
slog.Info("SYS_SENSORS", "path", sysSensors)
|
||||
config.context = context.WithValue(config.context,
|
||||
common.EnvKey, common.EnvMap{common.HostSysEnvKey: sysSensors},
|
||||
)
|
||||
}
|
||||
|
||||
// handle blacklist
|
||||
if strings.HasPrefix(sensorsEnvVal, "-") {
|
||||
config.isBlacklist = true
|
||||
sensorsEnvVal = sensorsEnvVal[1:]
|
||||
}
|
||||
|
||||
for sensor := range strings.SplitSeq(sensorsEnvVal, ",") {
|
||||
sensor = strings.TrimSpace(sensor)
|
||||
if sensor != "" {
|
||||
config.sensors[sensor] = struct{}{}
|
||||
if strings.Contains(sensor, "*") {
|
||||
config.hasWildcards = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// updateTemperatures updates the agent with the latest sensor temperatures
|
||||
func (a *Agent) updateTemperatures(systemStats *system.Stats) {
|
||||
// skip if sensors whitelist is set to empty string
|
||||
if a.sensorConfig.skipCollection {
|
||||
slog.Debug("Skipping temperature collection")
|
||||
return
|
||||
}
|
||||
|
||||
// reset high temp
|
||||
a.systemInfo.DashboardTemp = 0
|
||||
|
||||
temps, err := a.getTempsWithPanicRecovery(getSensorTemps)
|
||||
if err != nil {
|
||||
// retry once on panic (gopsutil/issues/1832)
|
||||
temps, err = a.getTempsWithPanicRecovery(getSensorTemps)
|
||||
if err != nil {
|
||||
slog.Warn("Error updating temperatures", "err", err)
|
||||
if len(systemStats.Temperatures) > 0 {
|
||||
systemStats.Temperatures = make(map[string]float64)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
slog.Debug("Temperature", "sensors", temps)
|
||||
|
||||
// return if no sensors
|
||||
if len(temps) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
systemStats.Temperatures = make(map[string]float64, len(temps))
|
||||
for i, sensor := range temps {
|
||||
// check for malformed strings on darwin (gopsutil/issues/1832)
|
||||
if runtime.GOOS == "darwin" && !utf8.ValidString(sensor.SensorKey) {
|
||||
continue
|
||||
}
|
||||
|
||||
// scale temperature
|
||||
if sensor.Temperature != 0 && sensor.Temperature < 1 {
|
||||
sensor.Temperature = scaleTemperature(sensor.Temperature)
|
||||
}
|
||||
// skip if temperature is unreasonable
|
||||
if sensor.Temperature <= 0 || sensor.Temperature >= 200 {
|
||||
continue
|
||||
}
|
||||
sensorName := sensor.SensorKey
|
||||
if _, ok := systemStats.Temperatures[sensorName]; ok {
|
||||
// if key already exists, append int to key
|
||||
sensorName = sensorName + "_" + strconv.Itoa(i)
|
||||
}
|
||||
// skip if not in whitelist or blacklist
|
||||
if !isValidSensor(sensorName, a.sensorConfig) {
|
||||
continue
|
||||
}
|
||||
// set dashboard temperature
|
||||
switch a.sensorConfig.primarySensor {
|
||||
case "":
|
||||
a.systemInfo.DashboardTemp = max(a.systemInfo.DashboardTemp, sensor.Temperature)
|
||||
case sensorName:
|
||||
a.systemInfo.DashboardTemp = sensor.Temperature
|
||||
}
|
||||
systemStats.Temperatures[sensorName] = twoDecimals(sensor.Temperature)
|
||||
}
|
||||
}
|
||||
|
||||
// getTempsWithPanicRecovery wraps sensors.TemperaturesWithContext to recover from panics (gopsutil/issues/1832)
|
||||
func (a *Agent) getTempsWithPanicRecovery(getTemps getTempsFn) (temps []sensors.TemperatureStat, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic: %v", r)
|
||||
}
|
||||
}()
|
||||
// get sensor data (error ignored intentionally as it may be only with one sensor)
|
||||
temps, _ = getTemps(a.sensorConfig.context)
|
||||
return
|
||||
}
|
||||
|
||||
// isValidSensor checks if a sensor is valid based on the sensor name and the sensor config
|
||||
func isValidSensor(sensorName string, config *SensorConfig) bool {
|
||||
// if no sensors configured, everything is valid
|
||||
if len(config.sensors) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// Exact match - return true if whitelist, false if blacklist
|
||||
if _, exactMatch := config.sensors[sensorName]; exactMatch {
|
||||
return !config.isBlacklist
|
||||
}
|
||||
|
||||
// If no wildcards, return true if blacklist, false if whitelist
|
||||
if !config.hasWildcards {
|
||||
return config.isBlacklist
|
||||
}
|
||||
|
||||
// Check for wildcard patterns
|
||||
for pattern := range config.sensors {
|
||||
if !strings.Contains(pattern, "*") {
|
||||
continue
|
||||
}
|
||||
if match, _ := path.Match(pattern, sensorName); match {
|
||||
return !config.isBlacklist
|
||||
}
|
||||
}
|
||||
|
||||
return config.isBlacklist
|
||||
}
|
||||
|
||||
// scaleTemperature scales temperatures in fractional values to reasonable Celsius values
|
||||
func scaleTemperature(temp float64) float64 {
|
||||
if temp > 1 {
|
||||
return temp
|
||||
}
|
||||
scaled100 := temp * 100
|
||||
scaled1000 := temp * 1000
|
||||
|
||||
if scaled100 >= 15 && scaled100 <= 95 {
|
||||
return scaled100
|
||||
} else if scaled1000 >= 15 && scaled1000 <= 95 {
|
||||
return scaled1000
|
||||
}
|
||||
return scaled100
|
||||
}
|
||||
9
agent/sensors_default.go
Normal file
9
agent/sensors_default.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build !windows
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"github.com/shirou/gopsutil/v4/sensors"
|
||||
)
|
||||
|
||||
var getSensorTemps = sensors.TemperaturesWithContext
|
||||
554
agent/sensors_test.go
Normal file
554
agent/sensors_test.go
Normal file
@@ -0,0 +1,554 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/common"
|
||||
"github.com/shirou/gopsutil/v4/sensors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIsValidSensor(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sensorName string
|
||||
config *SensorConfig
|
||||
expectedValid bool
|
||||
}{
|
||||
{
|
||||
name: "Whitelist - sensor in list",
|
||||
sensorName: "cpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}},
|
||||
isBlacklist: false,
|
||||
},
|
||||
expectedValid: true,
|
||||
},
|
||||
{
|
||||
name: "Whitelist - sensor not in list",
|
||||
sensorName: "gpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}},
|
||||
isBlacklist: false,
|
||||
},
|
||||
expectedValid: false,
|
||||
},
|
||||
{
|
||||
name: "Blacklist - sensor in list",
|
||||
sensorName: "cpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}},
|
||||
isBlacklist: true,
|
||||
},
|
||||
expectedValid: false,
|
||||
},
|
||||
{
|
||||
name: "Blacklist - sensor not in list",
|
||||
sensorName: "gpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}},
|
||||
isBlacklist: true,
|
||||
},
|
||||
expectedValid: true,
|
||||
},
|
||||
{
|
||||
name: "Whitelist with wildcard - matching pattern",
|
||||
sensorName: "core_0_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"core_*_temp": {}},
|
||||
isBlacklist: false,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: true,
|
||||
},
|
||||
{
|
||||
name: "Whitelist with wildcard - non-matching pattern",
|
||||
sensorName: "gpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"core_*_temp": {}},
|
||||
isBlacklist: false,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: false,
|
||||
},
|
||||
{
|
||||
name: "Blacklist with wildcard - matching pattern",
|
||||
sensorName: "core_0_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"core_*_temp": {}},
|
||||
isBlacklist: true,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: false,
|
||||
},
|
||||
{
|
||||
name: "Blacklist with wildcard - non-matching pattern",
|
||||
sensorName: "gpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"core_*_temp": {}},
|
||||
isBlacklist: true,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: true,
|
||||
},
|
||||
{
|
||||
name: "No sensors configured",
|
||||
sensorName: "any_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{},
|
||||
isBlacklist: false,
|
||||
hasWildcards: false,
|
||||
skipCollection: false,
|
||||
},
|
||||
expectedValid: true,
|
||||
},
|
||||
{
|
||||
name: "Mixed patterns in whitelist - exact match",
|
||||
sensorName: "cpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
|
||||
isBlacklist: false,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: true,
|
||||
},
|
||||
{
|
||||
name: "Mixed patterns in whitelist - wildcard match",
|
||||
sensorName: "core_1_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
|
||||
isBlacklist: false,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: true,
|
||||
},
|
||||
{
|
||||
name: "Mixed patterns in blacklist - exact match",
|
||||
sensorName: "cpu_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
|
||||
isBlacklist: true,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: false,
|
||||
},
|
||||
{
|
||||
name: "Mixed patterns in blacklist - wildcard match",
|
||||
sensorName: "core_1_temp",
|
||||
config: &SensorConfig{
|
||||
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
|
||||
isBlacklist: true,
|
||||
hasWildcards: true,
|
||||
},
|
||||
expectedValid: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := isValidSensor(tt.sensorName, tt.config)
|
||||
assert.Equal(t, tt.expectedValid, result, "isValidSensor(%q, config) returned unexpected result", tt.sensorName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewSensorConfigWithEnv(t *testing.T) {
|
||||
agent := &Agent{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
primarySensor string
|
||||
sysSensors string
|
||||
sensors string
|
||||
skipCollection bool
|
||||
expectedConfig *SensorConfig
|
||||
}{
|
||||
{
|
||||
name: "Empty configuration",
|
||||
primarySensor: "",
|
||||
sysSensors: "",
|
||||
sensors: "",
|
||||
expectedConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: "",
|
||||
sensors: map[string]struct{}{},
|
||||
isBlacklist: false,
|
||||
hasWildcards: false,
|
||||
skipCollection: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Explicitly set to empty string",
|
||||
primarySensor: "",
|
||||
sysSensors: "",
|
||||
sensors: "",
|
||||
skipCollection: true,
|
||||
expectedConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: "",
|
||||
sensors: map[string]struct{}{},
|
||||
isBlacklist: false,
|
||||
hasWildcards: false,
|
||||
skipCollection: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Primary sensor only - should create sensor map",
|
||||
primarySensor: "cpu_temp",
|
||||
sysSensors: "",
|
||||
sensors: "",
|
||||
expectedConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: "cpu_temp",
|
||||
sensors: map[string]struct{}{},
|
||||
isBlacklist: false,
|
||||
hasWildcards: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Whitelist sensors",
|
||||
primarySensor: "cpu_temp",
|
||||
sysSensors: "",
|
||||
sensors: "cpu_temp,gpu_temp",
|
||||
expectedConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: "cpu_temp",
|
||||
sensors: map[string]struct{}{
|
||||
"cpu_temp": {},
|
||||
"gpu_temp": {},
|
||||
},
|
||||
isBlacklist: false,
|
||||
hasWildcards: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Blacklist sensors",
|
||||
primarySensor: "cpu_temp",
|
||||
sysSensors: "",
|
||||
sensors: "-cpu_temp,gpu_temp",
|
||||
expectedConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: "cpu_temp",
|
||||
sensors: map[string]struct{}{
|
||||
"cpu_temp": {},
|
||||
"gpu_temp": {},
|
||||
},
|
||||
isBlacklist: true,
|
||||
hasWildcards: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Sensors with wildcard",
|
||||
primarySensor: "cpu_temp",
|
||||
sysSensors: "",
|
||||
sensors: "cpu_*,gpu_temp",
|
||||
expectedConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: "cpu_temp",
|
||||
sensors: map[string]struct{}{
|
||||
"cpu_*": {},
|
||||
"gpu_temp": {},
|
||||
},
|
||||
isBlacklist: false,
|
||||
hasWildcards: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Sensors with whitespace",
|
||||
primarySensor: "cpu_temp",
|
||||
sysSensors: "",
|
||||
sensors: "cpu_*, gpu_temp",
|
||||
expectedConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
primarySensor: "cpu_temp",
|
||||
sensors: map[string]struct{}{
|
||||
"cpu_*": {},
|
||||
"gpu_temp": {},
|
||||
},
|
||||
isBlacklist: false,
|
||||
hasWildcards: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With SYS_SENSORS path",
|
||||
primarySensor: "cpu_temp",
|
||||
sysSensors: "/custom/path",
|
||||
sensors: "cpu_temp",
|
||||
expectedConfig: &SensorConfig{
|
||||
primarySensor: "cpu_temp",
|
||||
sensors: map[string]struct{}{
|
||||
"cpu_temp": {},
|
||||
},
|
||||
isBlacklist: false,
|
||||
hasWildcards: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := agent.newSensorConfigWithEnv(tt.primarySensor, tt.sysSensors, tt.sensors, tt.skipCollection)
|
||||
|
||||
// Check primary sensor
|
||||
assert.Equal(t, tt.expectedConfig.primarySensor, result.primarySensor)
|
||||
|
||||
// Check sensor map
|
||||
if tt.expectedConfig.sensors == nil {
|
||||
assert.Nil(t, result.sensors)
|
||||
} else {
|
||||
assert.Equal(t, len(tt.expectedConfig.sensors), len(result.sensors))
|
||||
for sensor := range tt.expectedConfig.sensors {
|
||||
_, exists := result.sensors[sensor]
|
||||
assert.True(t, exists, "Sensor %s should exist in the result", sensor)
|
||||
}
|
||||
}
|
||||
|
||||
// Check flags
|
||||
assert.Equal(t, tt.expectedConfig.isBlacklist, result.isBlacklist)
|
||||
assert.Equal(t, tt.expectedConfig.hasWildcards, result.hasWildcards)
|
||||
|
||||
// Check context
|
||||
if tt.sysSensors != "" {
|
||||
// Verify context contains correct values
|
||||
envMap, ok := result.context.Value(common.EnvKey).(common.EnvMap)
|
||||
require.True(t, ok, "Context should contain EnvMap")
|
||||
sysPath, ok := envMap[common.HostSysEnvKey]
|
||||
require.True(t, ok, "EnvMap should contain HostSysEnvKey")
|
||||
assert.Equal(t, tt.sysSensors, sysPath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewSensorConfig(t *testing.T) {
|
||||
// Save original environment variables
|
||||
originalPrimary, hasPrimary := os.LookupEnv("BESZEL_AGENT_PRIMARY_SENSOR")
|
||||
originalSys, hasSys := os.LookupEnv("BESZEL_AGENT_SYS_SENSORS")
|
||||
originalSensors, hasSensors := os.LookupEnv("BESZEL_AGENT_SENSORS")
|
||||
|
||||
// Restore environment variables after the test
|
||||
defer func() {
|
||||
// Clean up test environment variables
|
||||
os.Unsetenv("BESZEL_AGENT_PRIMARY_SENSOR")
|
||||
os.Unsetenv("BESZEL_AGENT_SYS_SENSORS")
|
||||
os.Unsetenv("BESZEL_AGENT_SENSORS")
|
||||
|
||||
// Restore original values if they existed
|
||||
if hasPrimary {
|
||||
os.Setenv("BESZEL_AGENT_PRIMARY_SENSOR", originalPrimary)
|
||||
}
|
||||
if hasSys {
|
||||
os.Setenv("BESZEL_AGENT_SYS_SENSORS", originalSys)
|
||||
}
|
||||
if hasSensors {
|
||||
os.Setenv("BESZEL_AGENT_SENSORS", originalSensors)
|
||||
}
|
||||
}()
|
||||
|
||||
// Set test environment variables
|
||||
os.Setenv("BESZEL_AGENT_PRIMARY_SENSOR", "test_primary")
|
||||
os.Setenv("BESZEL_AGENT_SYS_SENSORS", "/test/path")
|
||||
os.Setenv("BESZEL_AGENT_SENSORS", "test_sensor1,test_*,test_sensor3")
|
||||
|
||||
agent := &Agent{}
|
||||
result := agent.newSensorConfig()
|
||||
|
||||
// Verify results
|
||||
assert.Equal(t, "test_primary", result.primarySensor)
|
||||
assert.NotNil(t, result.sensors)
|
||||
assert.Equal(t, 3, len(result.sensors))
|
||||
assert.True(t, result.hasWildcards)
|
||||
assert.False(t, result.isBlacklist)
|
||||
|
||||
// Check that sys sensors path is in context
|
||||
envMap, ok := result.context.Value(common.EnvKey).(common.EnvMap)
|
||||
require.True(t, ok, "Context should contain EnvMap")
|
||||
sysPath, ok := envMap[common.HostSysEnvKey]
|
||||
require.True(t, ok, "EnvMap should contain HostSysEnvKey")
|
||||
assert.Equal(t, "/test/path", sysPath)
|
||||
}
|
||||
|
||||
func TestScaleTemperature(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input float64
|
||||
expected float64
|
||||
desc string
|
||||
}{
|
||||
// Normal temperatures (no scaling needed)
|
||||
{"normal_cpu_temp", 45.0, 45.0, "Normal CPU temperature"},
|
||||
{"normal_room_temp", 25.0, 25.0, "Normal room temperature"},
|
||||
{"high_cpu_temp", 85.0, 85.0, "High CPU temperature"},
|
||||
// Zero temperature
|
||||
{"zero_temp", 0.0, 0.0, "Zero temperature"},
|
||||
// Fractional values that should use 100x scaling
|
||||
{"fractional_45c", 0.45, 45.0, "0.45 should become 45°C (100x)"},
|
||||
{"fractional_25c", 0.25, 25.0, "0.25 should become 25°C (100x)"},
|
||||
{"fractional_60c", 0.60, 60.0, "0.60 should become 60°C (100x)"},
|
||||
{"fractional_75c", 0.75, 75.0, "0.75 should become 75°C (100x)"},
|
||||
{"fractional_30c", 0.30, 30.0, "0.30 should become 30°C (100x)"},
|
||||
// Fractional values that should use 1000x scaling
|
||||
{"millifractional_45c", 0.045, 45.0, "0.045 should become 45°C (1000x)"},
|
||||
{"millifractional_25c", 0.025, 25.0, "0.025 should become 25°C (1000x)"},
|
||||
{"millifractional_60c", 0.060, 60.0, "0.060 should become 60°C (1000x)"},
|
||||
{"millifractional_75c", 0.075, 75.0, "0.075 should become 75°C (1000x)"},
|
||||
{"millifractional_35c", 0.035, 35.0, "0.035 should become 35°C (1000x)"},
|
||||
// Edge cases - values outside reasonable range
|
||||
{"very_low_fractional", 0.01, 1.0, "0.01 should default to 100x scaling (1°C)"},
|
||||
{"very_high_fractional", 0.99, 99.0, "0.99 should default to 100x scaling (99°C)"},
|
||||
{"extremely_low", 0.001, 0.1, "0.001 should default to 100x scaling (0.1°C)"},
|
||||
// Boundary cases around the reasonable range (15-95°C)
|
||||
{"boundary_low_100x", 0.15, 15.0, "0.15 should use 100x scaling (15°C)"},
|
||||
{"boundary_high_100x", 0.95, 95.0, "0.95 should use 100x scaling (95°C)"},
|
||||
{"boundary_low_1000x", 0.015, 15.0, "0.015 should use 1000x scaling (15°C)"},
|
||||
{"boundary_high_1000x", 0.095, 95.0, "0.095 should use 1000x scaling (95°C)"},
|
||||
// Values just outside reasonable range
|
||||
{"just_below_range_100x", 0.14, 14.0, "0.14 should default to 100x (14°C)"},
|
||||
{"just_above_range_100x", 0.96, 96.0, "0.96 should default to 100x (96°C)"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := scaleTemperature(tt.input)
|
||||
assert.InDelta(t, tt.expected, result, 0.001,
|
||||
"scaleTemperature(%v) = %v, expected %v (%s)",
|
||||
tt.input, result, tt.expected, tt.desc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaleTemperatureLogic(t *testing.T) {
|
||||
// Test the logic flow for ambiguous cases
|
||||
t.Run("prefers_100x_when_both_valid", func(t *testing.T) {
|
||||
// 0.5 could be 50°C (100x) or 500°C (1000x)
|
||||
// Should prefer 100x since it's tried first and is in range
|
||||
result := scaleTemperature(0.5)
|
||||
expected := 50.0
|
||||
assert.InDelta(t, expected, result, 0.001,
|
||||
"scaleTemperature(0.5) = %v, expected %v (should prefer 100x scaling)",
|
||||
result, expected)
|
||||
})
|
||||
|
||||
t.Run("uses_1000x_when_100x_too_low", func(t *testing.T) {
|
||||
// 0.05 -> 5°C (100x, too low) or 50°C (1000x, in range)
|
||||
// Should use 1000x since 100x is below reasonable range
|
||||
result := scaleTemperature(0.05)
|
||||
expected := 50.0
|
||||
assert.InDelta(t, expected, result, 0.001,
|
||||
"scaleTemperature(0.05) = %v, expected %v (should use 1000x scaling)",
|
||||
result, expected)
|
||||
})
|
||||
|
||||
t.Run("defaults_to_100x_when_both_invalid", func(t *testing.T) {
|
||||
// 0.005 -> 0.5°C (100x, too low) or 5°C (1000x, too low)
|
||||
// Should default to 100x scaling
|
||||
result := scaleTemperature(0.005)
|
||||
expected := 0.5
|
||||
assert.InDelta(t, expected, result, 0.001,
|
||||
"scaleTemperature(0.005) = %v, expected %v (should default to 100x)",
|
||||
result, expected)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetTempsWithPanicRecovery(t *testing.T) {
|
||||
agent := &Agent{
|
||||
systemInfo: system.Info{},
|
||||
sensorConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
getTempsFn getTempsFn
|
||||
expectError bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "successful_function_call",
|
||||
getTempsFn: func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
return []sensors.TemperatureStat{
|
||||
{SensorKey: "test_sensor", Temperature: 45.0},
|
||||
}, nil
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "function_returns_error",
|
||||
getTempsFn: func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
return []sensors.TemperatureStat{
|
||||
{SensorKey: "test_sensor", Temperature: 45.0},
|
||||
}, fmt.Errorf("sensor error")
|
||||
},
|
||||
expectError: false, // getTempsWithPanicRecovery ignores errors from the function
|
||||
},
|
||||
{
|
||||
name: "function_panics_with_string",
|
||||
getTempsFn: func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
panic("test panic")
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "panic: test panic",
|
||||
},
|
||||
{
|
||||
name: "function_panics_with_error",
|
||||
getTempsFn: func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
panic(fmt.Errorf("panic error"))
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "panic:",
|
||||
},
|
||||
{
|
||||
name: "function_panics_with_index_out_of_bounds",
|
||||
getTempsFn: func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
slice := []int{1, 2, 3}
|
||||
_ = slice[10] // out of bounds panic
|
||||
return nil, nil
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "panic:",
|
||||
},
|
||||
{
|
||||
name: "function_panics_with_any_conversion",
|
||||
getTempsFn: func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
var i any = "string"
|
||||
_ = i.(int) // type assertion panic
|
||||
return nil, nil
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "panic:",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var temps []sensors.TemperatureStat
|
||||
var err error
|
||||
|
||||
// The function should not panic, regardless of what the injected function does
|
||||
assert.NotPanics(t, func() {
|
||||
temps, err = agent.getTempsWithPanicRecovery(tt.getTempsFn)
|
||||
}, "getTempsWithPanicRecovery should not panic")
|
||||
|
||||
if tt.expectError {
|
||||
assert.Error(t, err, "Expected an error to be returned")
|
||||
if tt.errorMsg != "" {
|
||||
assert.Contains(t, err.Error(), tt.errorMsg,
|
||||
"Error message should contain expected text")
|
||||
}
|
||||
assert.Nil(t, temps, "Temps should be nil when panic occurs")
|
||||
} else {
|
||||
assert.NoError(t, err, "Should not return error for successful calls")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
286
agent/sensors_windows.go
Normal file
286
agent/sensors_windows.go
Normal file
@@ -0,0 +1,286 @@
|
||||
//go:build windows
|
||||
|
||||
//go:generate dotnet build -c Release lhm/beszel_lhm.csproj
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/sensors"
|
||||
)
|
||||
|
||||
// Note: This is always called from Agent.gatherStats() which holds Agent.Lock(),
|
||||
// so no internal concurrency protection is needed.
|
||||
|
||||
// lhmProcess is a wrapper around the LHM .NET process.
|
||||
type lhmProcess struct {
|
||||
cmd *exec.Cmd
|
||||
stdin io.WriteCloser
|
||||
stdout io.ReadCloser
|
||||
scanner *bufio.Scanner
|
||||
isRunning bool
|
||||
stoppedNoSensors bool
|
||||
consecutiveNoSensors uint8
|
||||
execPath string
|
||||
tempDir string
|
||||
}
|
||||
|
||||
//go:embed all:lhm/bin/Release/net48
|
||||
var lhmFs embed.FS
|
||||
|
||||
var (
|
||||
beszelLhm *lhmProcess
|
||||
beszelLhmOnce sync.Once
|
||||
useLHM = os.Getenv("LHM") == "true"
|
||||
)
|
||||
|
||||
var errNoSensors = errors.New("no sensors found (try running as admin with LHM=true)")
|
||||
|
||||
// newlhmProcess copies the embedded LHM executable to a temporary directory and starts it.
|
||||
func newlhmProcess() (*lhmProcess, error) {
|
||||
destDir := filepath.Join(os.TempDir(), "beszel")
|
||||
execPath := filepath.Join(destDir, "beszel_lhm.exe")
|
||||
|
||||
if err := os.MkdirAll(destDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
|
||||
// Only copy if executable doesn't exist
|
||||
if _, err := os.Stat(execPath); os.IsNotExist(err) {
|
||||
if err := copyEmbeddedDir(lhmFs, "lhm/bin/Release/net48", destDir); err != nil {
|
||||
return nil, fmt.Errorf("failed to copy embedded directory: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
lhm := &lhmProcess{
|
||||
execPath: execPath,
|
||||
tempDir: destDir,
|
||||
}
|
||||
|
||||
if err := lhm.startProcess(); err != nil {
|
||||
return nil, fmt.Errorf("failed to start process: %w", err)
|
||||
}
|
||||
|
||||
return lhm, nil
|
||||
}
|
||||
|
||||
// startProcess starts the external LHM process
|
||||
func (lhm *lhmProcess) startProcess() error {
|
||||
// Clean up any existing process
|
||||
lhm.cleanupProcess()
|
||||
|
||||
cmd := exec.Command(lhm.execPath)
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
stdin.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
stdin.Close()
|
||||
stdout.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// Update process state
|
||||
lhm.cmd = cmd
|
||||
lhm.stdin = stdin
|
||||
lhm.stdout = stdout
|
||||
lhm.scanner = bufio.NewScanner(stdout)
|
||||
lhm.isRunning = true
|
||||
|
||||
// Give process a moment to initialize
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cleanupProcess terminates the process and closes resources but preserves files
|
||||
func (lhm *lhmProcess) cleanupProcess() {
|
||||
lhm.isRunning = false
|
||||
|
||||
if lhm.cmd != nil && lhm.cmd.Process != nil {
|
||||
lhm.cmd.Process.Kill()
|
||||
lhm.cmd.Wait()
|
||||
}
|
||||
|
||||
if lhm.stdin != nil {
|
||||
lhm.stdin.Close()
|
||||
lhm.stdin = nil
|
||||
}
|
||||
if lhm.stdout != nil {
|
||||
lhm.stdout.Close()
|
||||
lhm.stdout = nil
|
||||
}
|
||||
|
||||
lhm.cmd = nil
|
||||
lhm.scanner = nil
|
||||
lhm.stoppedNoSensors = false
|
||||
lhm.consecutiveNoSensors = 0
|
||||
}
|
||||
|
||||
func (lhm *lhmProcess) getTemps(ctx context.Context) (temps []sensors.TemperatureStat, err error) {
|
||||
if !useLHM || lhm.stoppedNoSensors {
|
||||
// Fall back to gopsutil if we can't get sensors from LHM
|
||||
return sensors.TemperaturesWithContext(ctx)
|
||||
}
|
||||
|
||||
// Start process if it's not running
|
||||
if !lhm.isRunning || lhm.stdin == nil || lhm.scanner == nil {
|
||||
err := lhm.startProcess()
|
||||
if err != nil {
|
||||
return temps, err
|
||||
}
|
||||
}
|
||||
|
||||
// Send command to process
|
||||
_, err = fmt.Fprintln(lhm.stdin, "getTemps")
|
||||
if err != nil {
|
||||
lhm.isRunning = false
|
||||
return temps, fmt.Errorf("failed to send command: %w", err)
|
||||
}
|
||||
|
||||
// Read all sensor lines until we hit an empty line or EOF
|
||||
for lhm.scanner.Scan() {
|
||||
line := strings.TrimSpace(lhm.scanner.Text())
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
|
||||
parts := strings.Split(line, "|")
|
||||
if len(parts) != 2 {
|
||||
slog.Debug("Invalid sensor format", "line", line)
|
||||
continue
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(parts[0])
|
||||
valueStr := strings.TrimSpace(parts[1])
|
||||
|
||||
value, err := strconv.ParseFloat(valueStr, 64)
|
||||
if err != nil {
|
||||
slog.Debug("Failed to parse sensor", "err", err, "line", line)
|
||||
continue
|
||||
}
|
||||
|
||||
if name == "" || value <= 0 || value > 150 {
|
||||
slog.Debug("Invalid sensor", "name", name, "val", value, "line", line)
|
||||
continue
|
||||
}
|
||||
|
||||
temps = append(temps, sensors.TemperatureStat{
|
||||
SensorKey: name,
|
||||
Temperature: value,
|
||||
})
|
||||
}
|
||||
|
||||
if err := lhm.scanner.Err(); err != nil {
|
||||
lhm.isRunning = false
|
||||
return temps, err
|
||||
}
|
||||
|
||||
// Handle no sensors case
|
||||
if len(temps) == 0 {
|
||||
lhm.consecutiveNoSensors++
|
||||
if lhm.consecutiveNoSensors >= 3 {
|
||||
lhm.stoppedNoSensors = true
|
||||
slog.Warn(errNoSensors.Error())
|
||||
lhm.cleanup()
|
||||
}
|
||||
return sensors.TemperaturesWithContext(ctx)
|
||||
}
|
||||
|
||||
lhm.consecutiveNoSensors = 0
|
||||
|
||||
return temps, nil
|
||||
}
|
||||
|
||||
// getSensorTemps attempts to pull sensor temperatures from the embedded LHM process.
|
||||
// NB: LibreHardwareMonitorLib requires admin privileges to access all available sensors.
|
||||
func getSensorTemps(ctx context.Context) (temps []sensors.TemperatureStat, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
slog.Debug("Error reading sensors", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if !useLHM {
|
||||
return sensors.TemperaturesWithContext(ctx)
|
||||
}
|
||||
|
||||
// Initialize process once
|
||||
beszelLhmOnce.Do(func() {
|
||||
beszelLhm, err = newlhmProcess()
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return temps, fmt.Errorf("failed to initialize lhm: %w", err)
|
||||
}
|
||||
|
||||
if beszelLhm == nil {
|
||||
return temps, fmt.Errorf("lhm not available")
|
||||
}
|
||||
|
||||
return beszelLhm.getTemps(ctx)
|
||||
}
|
||||
|
||||
// cleanup terminates the process and closes resources
|
||||
func (lhm *lhmProcess) cleanup() {
|
||||
lhm.cleanupProcess()
|
||||
if lhm.tempDir != "" {
|
||||
os.RemoveAll(lhm.tempDir)
|
||||
}
|
||||
}
|
||||
|
||||
// copyEmbeddedDir copies the embedded directory to the destination path
|
||||
func copyEmbeddedDir(fs embed.FS, srcPath, destPath string) error {
|
||||
entries, err := fs.ReadDir(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(destPath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcEntryPath := path.Join(srcPath, entry.Name())
|
||||
destEntryPath := filepath.Join(destPath, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
if err := copyEmbeddedDir(fs, srcEntryPath, destEntryPath); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := fs.ReadFile(srcEntryPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(destEntryPath, data, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
224
agent/server.go
Normal file
224
agent/server.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel"
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/gliderlabs/ssh"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// ServerOptions contains configuration options for starting the SSH server.
|
||||
type ServerOptions struct {
|
||||
Addr string // Network address to listen on (e.g., ":45876" or "/path/to/socket")
|
||||
Network string // Network type ("tcp" or "unix")
|
||||
Keys []gossh.PublicKey // SSH public keys for authentication
|
||||
}
|
||||
|
||||
// hubVersions caches hub versions by session ID to avoid repeated parsing.
|
||||
var hubVersions map[string]semver.Version
|
||||
|
||||
// StartServer starts the SSH server with the provided options.
|
||||
// It configures the server with secure defaults, sets up authentication,
|
||||
// and begins listening for connections. Returns an error if the server
|
||||
// is already running or if there's an issue starting the server.
|
||||
func (a *Agent) StartServer(opts ServerOptions) error {
|
||||
if a.server != nil {
|
||||
return errors.New("server already started")
|
||||
}
|
||||
|
||||
slog.Info("Starting SSH server", "addr", opts.Addr, "network", opts.Network)
|
||||
|
||||
if opts.Network == "unix" {
|
||||
// remove existing socket file if it exists
|
||||
if err := os.Remove(opts.Addr); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// start listening on the address
|
||||
ln, err := net.Listen(opts.Network, opts.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
// base config (limit to allowed algorithms)
|
||||
config := &gossh.ServerConfig{
|
||||
ServerVersion: fmt.Sprintf("SSH-2.0-%s_%s", beszel.AppName, beszel.Version),
|
||||
}
|
||||
config.KeyExchanges = common.DefaultKeyExchanges
|
||||
config.MACs = common.DefaultMACs
|
||||
config.Ciphers = common.DefaultCiphers
|
||||
|
||||
// set default handler
|
||||
ssh.Handle(a.handleSession)
|
||||
|
||||
a.server = &ssh.Server{
|
||||
ServerConfigCallback: func(ctx ssh.Context) *gossh.ServerConfig {
|
||||
return config
|
||||
},
|
||||
// check public key(s)
|
||||
PublicKeyHandler: func(ctx ssh.Context, key ssh.PublicKey) bool {
|
||||
remoteAddr := ctx.RemoteAddr()
|
||||
for _, pubKey := range opts.Keys {
|
||||
if ssh.KeysEqual(key, pubKey) {
|
||||
slog.Info("SSH connected", "addr", remoteAddr)
|
||||
return true
|
||||
}
|
||||
}
|
||||
slog.Warn("Invalid SSH key", "addr", remoteAddr)
|
||||
return false
|
||||
},
|
||||
// disable pty
|
||||
PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool {
|
||||
return false
|
||||
},
|
||||
// close idle connections after 70 seconds
|
||||
IdleTimeout: 70 * time.Second,
|
||||
}
|
||||
|
||||
// Start SSH server on the listener
|
||||
return a.server.Serve(ln)
|
||||
}
|
||||
|
||||
// getHubVersion retrieves and caches the hub version for a given session.
|
||||
// It extracts the version from the SSH client version string and caches
|
||||
// it to avoid repeated parsing. Returns a zero version if parsing fails.
|
||||
func (a *Agent) getHubVersion(sessionId string, sessionCtx ssh.Context) semver.Version {
|
||||
if hubVersions == nil {
|
||||
hubVersions = make(map[string]semver.Version, 1)
|
||||
}
|
||||
hubVersion, ok := hubVersions[sessionId]
|
||||
if ok {
|
||||
return hubVersion
|
||||
}
|
||||
// Extract hub version from SSH client version
|
||||
clientVersion := sessionCtx.Value(ssh.ContextKeyClientVersion)
|
||||
if versionStr, ok := clientVersion.(string); ok {
|
||||
hubVersion, _ = extractHubVersion(versionStr)
|
||||
}
|
||||
hubVersions[sessionId] = hubVersion
|
||||
return hubVersion
|
||||
}
|
||||
|
||||
// handleSession handles an incoming SSH session by gathering system statistics
|
||||
// and sending them to the hub. It signals connection events, determines the
|
||||
// appropriate encoding format based on hub version, and exits with appropriate
|
||||
// status codes.
|
||||
func (a *Agent) handleSession(s ssh.Session) {
|
||||
a.connectionManager.eventChan <- SSHConnect
|
||||
|
||||
sessionCtx := s.Context()
|
||||
sessionID := sessionCtx.SessionID()
|
||||
|
||||
hubVersion := a.getHubVersion(sessionID, sessionCtx)
|
||||
|
||||
stats := a.gatherStats(sessionID)
|
||||
|
||||
err := a.writeToSession(s, stats, hubVersion)
|
||||
if err != nil {
|
||||
slog.Error("Error encoding stats", "err", err, "stats", stats)
|
||||
s.Exit(1)
|
||||
} else {
|
||||
s.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
// writeToSession encodes and writes system statistics to the session.
|
||||
// It chooses between CBOR and JSON encoding based on the hub version,
|
||||
// using CBOR for newer versions and JSON for legacy compatibility.
|
||||
func (a *Agent) writeToSession(w io.Writer, stats *system.CombinedData, hubVersion semver.Version) error {
|
||||
if hubVersion.GTE(beszel.MinVersionCbor) {
|
||||
return cbor.NewEncoder(w).Encode(stats)
|
||||
}
|
||||
return json.NewEncoder(w).Encode(stats)
|
||||
}
|
||||
|
||||
// extractHubVersion extracts the beszel version from SSH client version string.
|
||||
// Expected format: "SSH-2.0-beszel_X.Y.Z" or "beszel_X.Y.Z"
|
||||
func extractHubVersion(versionString string) (semver.Version, error) {
|
||||
_, after, _ := strings.Cut(versionString, "_")
|
||||
return semver.Parse(after)
|
||||
}
|
||||
|
||||
// ParseKeys parses a string containing SSH public keys in authorized_keys format.
|
||||
// It returns a slice of ssh.PublicKey and an error if any key fails to parse.
|
||||
func ParseKeys(input string) ([]gossh.PublicKey, error) {
|
||||
var parsedKeys []gossh.PublicKey
|
||||
for line := range strings.Lines(input) {
|
||||
line = strings.TrimSpace(line)
|
||||
// Skip empty lines or comments
|
||||
if len(line) == 0 || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
// Parse the key
|
||||
parsedKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(line))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse key: %s, error: %w", line, err)
|
||||
}
|
||||
parsedKeys = append(parsedKeys, parsedKey)
|
||||
}
|
||||
return parsedKeys, nil
|
||||
}
|
||||
|
||||
// GetAddress determines the network address to listen on from various sources.
|
||||
// It checks the provided address, then environment variables (LISTEN, PORT),
|
||||
// and finally defaults to ":45876".
|
||||
func GetAddress(addr string) string {
|
||||
if addr == "" {
|
||||
addr, _ = GetEnv("LISTEN")
|
||||
}
|
||||
if addr == "" {
|
||||
// Legacy PORT environment variable support
|
||||
addr, _ = GetEnv("PORT")
|
||||
}
|
||||
if addr == "" {
|
||||
return ":45876"
|
||||
}
|
||||
// prefix with : if only port was provided
|
||||
if GetNetwork(addr) != "unix" && !strings.Contains(addr, ":") {
|
||||
addr = ":" + addr
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
// GetNetwork determines the network type based on the address format.
|
||||
// It checks the NETWORK environment variable first, then infers from
|
||||
// the address format: addresses starting with "/" are "unix", others are "tcp".
|
||||
func GetNetwork(addr string) string {
|
||||
if network, ok := GetEnv("NETWORK"); ok && network != "" {
|
||||
return network
|
||||
}
|
||||
if strings.HasPrefix(addr, "/") {
|
||||
return "unix"
|
||||
}
|
||||
return "tcp"
|
||||
}
|
||||
|
||||
// StopServer stops the SSH server if it's running.
|
||||
// It returns an error if the server is not running or if there's an error stopping it.
|
||||
func (a *Agent) StopServer() error {
|
||||
if a.server == nil {
|
||||
return errors.New("SSH server not running")
|
||||
}
|
||||
|
||||
slog.Info("Stopping SSH server")
|
||||
_ = a.server.Close()
|
||||
a.server = nil
|
||||
a.connectionManager.eventChan <- SSHDisconnect
|
||||
return nil
|
||||
}
|
||||
606
agent/server_test.go
Normal file
606
agent/server_test.go
Normal file
@@ -0,0 +1,606 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/container"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/gliderlabs/ssh"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func TestStartServer(t *testing.T) {
|
||||
// Generate a test key pair
|
||||
pubKey, privKey, err := ed25519.GenerateKey(nil)
|
||||
require.NoError(t, err)
|
||||
signer, err := gossh.NewSignerFromKey(privKey)
|
||||
require.NoError(t, err)
|
||||
sshPubKey, err := gossh.NewPublicKey(pubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Generate a different key pair for bad key test
|
||||
badPubKey, badPrivKey, err := ed25519.GenerateKey(nil)
|
||||
require.NoError(t, err)
|
||||
badSigner, err := gossh.NewSignerFromKey(badPrivKey)
|
||||
require.NoError(t, err)
|
||||
sshBadPubKey, err := gossh.NewPublicKey(badPubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
socketFile := filepath.Join(t.TempDir(), "beszel-test.sock")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config ServerOptions
|
||||
wantErr bool
|
||||
errContains string
|
||||
setup func() error
|
||||
cleanup func() error
|
||||
}{
|
||||
{
|
||||
name: "tcp port only",
|
||||
config: ServerOptions{
|
||||
Network: "tcp",
|
||||
Addr: ":45987",
|
||||
Keys: []gossh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tcp with ipv4",
|
||||
config: ServerOptions{
|
||||
Network: "tcp4",
|
||||
Addr: "127.0.0.1:45988",
|
||||
Keys: []gossh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tcp with ipv6",
|
||||
config: ServerOptions{
|
||||
Network: "tcp6",
|
||||
Addr: "[::1]:45989",
|
||||
Keys: []gossh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unix socket",
|
||||
config: ServerOptions{
|
||||
Network: "unix",
|
||||
Addr: socketFile,
|
||||
Keys: []gossh.PublicKey{sshPubKey},
|
||||
},
|
||||
setup: func() error {
|
||||
// Create a socket file that should be removed
|
||||
f, err := os.Create(socketFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.Close()
|
||||
},
|
||||
cleanup: func() error {
|
||||
return os.Remove(socketFile)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad key should fail",
|
||||
config: ServerOptions{
|
||||
Network: "tcp",
|
||||
Addr: ":45987",
|
||||
Keys: []gossh.PublicKey{sshBadPubKey},
|
||||
},
|
||||
wantErr: true,
|
||||
errContains: "ssh: handshake failed",
|
||||
},
|
||||
{
|
||||
name: "good key still good",
|
||||
config: ServerOptions{
|
||||
Network: "tcp",
|
||||
Addr: ":45987",
|
||||
Keys: []gossh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.setup != nil {
|
||||
err := tt.setup()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
if tt.cleanup != nil {
|
||||
defer tt.cleanup()
|
||||
}
|
||||
|
||||
agent, err := NewAgent("")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Start server in a goroutine since it blocks
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
errChan <- agent.StartServer(tt.config)
|
||||
}()
|
||||
|
||||
// Add a short delay to allow the server to start
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Try to connect to verify server is running
|
||||
var client *gossh.Client
|
||||
|
||||
// Choose the appropriate signer based on the test case
|
||||
testSigner := signer
|
||||
if tt.name == "bad key should fail" {
|
||||
testSigner = badSigner
|
||||
}
|
||||
|
||||
sshClientConfig := &gossh.ClientConfig{
|
||||
User: "a",
|
||||
Auth: []gossh.AuthMethod{
|
||||
gossh.PublicKeys(testSigner),
|
||||
},
|
||||
HostKeyCallback: gossh.InsecureIgnoreHostKey(),
|
||||
Timeout: 4 * time.Second,
|
||||
}
|
||||
|
||||
switch tt.config.Network {
|
||||
case "unix":
|
||||
client, err = gossh.Dial("unix", tt.config.Addr, sshClientConfig)
|
||||
default:
|
||||
if !strings.Contains(tt.config.Addr, ":") {
|
||||
tt.config.Addr = ":" + tt.config.Addr
|
||||
}
|
||||
client, err = gossh.Dial("tcp", tt.config.Addr, sshClientConfig)
|
||||
}
|
||||
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
if tt.errContains != "" {
|
||||
assert.Contains(t, err.Error(), tt.errContains)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, client)
|
||||
client.Close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//////////////////// ParseKeys Tests ////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// Helper function to generate a temporary file with content
|
||||
func createTempFile(content string) (string, error) {
|
||||
tmpFile, err := os.CreateTemp("", "ssh_keys_*.txt")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temp file: %w", err)
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
|
||||
if _, err := tmpFile.WriteString(content); err != nil {
|
||||
return "", fmt.Errorf("failed to write to temp file: %w", err)
|
||||
}
|
||||
|
||||
return tmpFile.Name(), nil
|
||||
}
|
||||
|
||||
// Test case 1: String with a single SSH key
|
||||
func TestParseSingleKeyFromString(t *testing.T) {
|
||||
input := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo"
|
||||
keys, err := ParseKeys(input)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 1 {
|
||||
t.Fatalf("Expected 1 key, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Expected key type 'ssh-ed25519', got '%s'", keys[0].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 2: String with multiple SSH keys
|
||||
func TestParseMultipleKeysFromString(t *testing.T) {
|
||||
input := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D \n #comment\n ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D"
|
||||
keys, err := ParseKeys(input)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 3 {
|
||||
t.Fatalf("Expected 3 keys, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" || keys[1].Type() != "ssh-ed25519" || keys[2].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Unexpected key types: %s, %s, %s", keys[0].Type(), keys[1].Type(), keys[2].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 3: File with a single SSH key
|
||||
func TestParseSingleKeyFromFile(t *testing.T) {
|
||||
content := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo"
|
||||
filePath, err := createTempFile(content)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file: %v", err)
|
||||
}
|
||||
defer os.Remove(filePath) // Clean up the file after the test
|
||||
|
||||
// Read the file content
|
||||
fileContent, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read temp file: %v", err)
|
||||
}
|
||||
|
||||
// Parse the keys
|
||||
keys, err := ParseKeys(string(fileContent))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 1 {
|
||||
t.Fatalf("Expected 1 key, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Expected key type 'ssh-ed25519', got '%s'", keys[0].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 4: File with multiple SSH keys
|
||||
func TestParseMultipleKeysFromFile(t *testing.T) {
|
||||
content := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D \n #comment\n ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D"
|
||||
filePath, err := createTempFile(content)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file: %v", err)
|
||||
}
|
||||
// defer os.Remove(filePath) // Clean up the file after the test
|
||||
|
||||
// Read the file content
|
||||
fileContent, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read temp file: %v", err)
|
||||
}
|
||||
|
||||
// Parse the keys
|
||||
keys, err := ParseKeys(string(fileContent))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 3 {
|
||||
t.Fatalf("Expected 3 keys, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" || keys[1].Type() != "ssh-ed25519" || keys[2].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Unexpected key types: %s, %s, %s", keys[0].Type(), keys[1].Type(), keys[2].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 5: Invalid SSH key input
|
||||
func TestParseInvalidKey(t *testing.T) {
|
||||
input := "invalid-key-data"
|
||||
_, err := ParseKeys(input)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error for invalid key, got nil")
|
||||
}
|
||||
expectedErrMsg := "failed to parse key"
|
||||
if !strings.Contains(err.Error(), expectedErrMsg) {
|
||||
t.Fatalf("Expected error message to contain '%s', got: %v", expectedErrMsg, err)
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//////////////////// Hub Version Tests //////////////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
func TestExtractHubVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
clientVersion string
|
||||
expectedVersion string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "valid beszel client version with underscore",
|
||||
clientVersion: "SSH-2.0-beszel_0.11.1",
|
||||
expectedVersion: "0.11.1",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "valid beszel client version with beta",
|
||||
clientVersion: "SSH-2.0-beszel_1.0.0-beta",
|
||||
expectedVersion: "1.0.0-beta",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "valid beszel client version with rc",
|
||||
clientVersion: "SSH-2.0-beszel_0.12.0-rc1",
|
||||
expectedVersion: "0.12.0-rc1",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "different SSH client",
|
||||
clientVersion: "SSH-2.0-OpenSSH_8.0",
|
||||
expectedVersion: "8.0",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "malformed version string without underscore",
|
||||
clientVersion: "SSH-2.0-beszel",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "empty version string",
|
||||
clientVersion: "",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "version string with underscore but no version",
|
||||
clientVersion: "beszel_",
|
||||
expectedVersion: "",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "version with patch and build metadata",
|
||||
clientVersion: "SSH-2.0-beszel_1.2.3+build.123",
|
||||
expectedVersion: "1.2.3+build.123",
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := extractHubVersion(tt.clientVersion)
|
||||
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedVersion, result.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/////////////// Hub Version Detection Tests ////////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
func TestGetHubVersion(t *testing.T) {
|
||||
agent, err := NewAgent("")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Mock SSH context that implements the ssh.Context interface
|
||||
mockCtx := &mockSSHContext{
|
||||
sessionID: "test-session-123",
|
||||
clientVersion: "SSH-2.0-beszel_0.12.0",
|
||||
}
|
||||
|
||||
// Test first call - should extract and cache version
|
||||
version := agent.getHubVersion("test-session-123", mockCtx)
|
||||
assert.Equal(t, "0.12.0", version.String())
|
||||
|
||||
// Test second call - should return cached version
|
||||
mockCtx.clientVersion = "SSH-2.0-beszel_0.11.0" // Change version but should still return cached
|
||||
version = agent.getHubVersion("test-session-123", mockCtx)
|
||||
assert.Equal(t, "0.12.0", version.String()) // Should still be cached version
|
||||
|
||||
// Test different session - should extract new version
|
||||
version = agent.getHubVersion("different-session", mockCtx)
|
||||
assert.Equal(t, "0.11.0", version.String())
|
||||
|
||||
// Test with invalid version string (non-beszel client)
|
||||
mockCtx.clientVersion = "SSH-2.0-OpenSSH_8.0"
|
||||
version = agent.getHubVersion("invalid-session", mockCtx)
|
||||
assert.Equal(t, "0.0.0", version.String()) // Should be empty version for non-beszel clients
|
||||
|
||||
// Test with no client version
|
||||
mockCtx.clientVersion = ""
|
||||
version = agent.getHubVersion("no-version-session", mockCtx)
|
||||
assert.True(t, version.EQ(semver.Version{})) // Should be empty version
|
||||
}
|
||||
|
||||
// mockSSHContext implements ssh.Context for testing
|
||||
type mockSSHContext struct {
|
||||
context.Context
|
||||
sync.Mutex
|
||||
sessionID string
|
||||
clientVersion string
|
||||
}
|
||||
|
||||
func (m *mockSSHContext) SessionID() string {
|
||||
return m.sessionID
|
||||
}
|
||||
|
||||
func (m *mockSSHContext) ClientVersion() string {
|
||||
return m.clientVersion
|
||||
}
|
||||
|
||||
func (m *mockSSHContext) ServerVersion() string {
|
||||
return "SSH-2.0-beszel_test"
|
||||
}
|
||||
|
||||
func (m *mockSSHContext) Value(key interface{}) interface{} {
|
||||
if key == ssh.ContextKeyClientVersion {
|
||||
return m.clientVersion
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockSSHContext) User() string { return "test-user" }
|
||||
func (m *mockSSHContext) RemoteAddr() net.Addr { return nil }
|
||||
func (m *mockSSHContext) LocalAddr() net.Addr { return nil }
|
||||
func (m *mockSSHContext) Permissions() *ssh.Permissions { return nil }
|
||||
func (m *mockSSHContext) SetValue(key, value interface{}) {}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/////////////// CBOR vs JSON Encoding Tests ////////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// TestWriteToSessionEncoding tests that writeToSession actually encodes data in the correct format
|
||||
func TestWriteToSessionEncoding(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
hubVersion string
|
||||
expectedUsesCbor bool
|
||||
}{
|
||||
{
|
||||
name: "old hub version should use JSON",
|
||||
hubVersion: "0.11.1",
|
||||
expectedUsesCbor: false,
|
||||
},
|
||||
{
|
||||
name: "non-beta release should use CBOR",
|
||||
hubVersion: "0.12.0",
|
||||
expectedUsesCbor: true,
|
||||
},
|
||||
{
|
||||
name: "even newer hub version should use CBOR",
|
||||
hubVersion: "0.16.4",
|
||||
expectedUsesCbor: true,
|
||||
},
|
||||
{
|
||||
name: "beta version below release threshold should use JSON",
|
||||
hubVersion: "0.12.0-beta0",
|
||||
expectedUsesCbor: false,
|
||||
},
|
||||
// {
|
||||
// name: "matching beta version should use CBOR",
|
||||
// hubVersion: "0.12.0-beta2",
|
||||
// expectedUsesCbor: true,
|
||||
// },
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Reset the global hubVersions map to ensure clean state for each test
|
||||
hubVersions = nil
|
||||
|
||||
agent, err := NewAgent("")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Parse the test version
|
||||
version, err := semver.Parse(tt.hubVersion)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create test data to encode
|
||||
testData := createTestCombinedData()
|
||||
|
||||
var buf strings.Builder
|
||||
err = agent.writeToSession(&buf, testData, version)
|
||||
require.NoError(t, err)
|
||||
|
||||
encodedData := buf.String()
|
||||
require.NotEmpty(t, encodedData)
|
||||
|
||||
// Verify the encoding format by attempting to decode
|
||||
if tt.expectedUsesCbor {
|
||||
var decodedCbor system.CombinedData
|
||||
err = cbor.Unmarshal([]byte(encodedData), &decodedCbor)
|
||||
assert.NoError(t, err, "Should be valid CBOR data")
|
||||
|
||||
var decodedJson system.CombinedData
|
||||
err = json.Unmarshal([]byte(encodedData), &decodedJson)
|
||||
assert.Error(t, err, "Should not be valid JSON data")
|
||||
|
||||
assert.Equal(t, testData.Info.Hostname, decodedCbor.Info.Hostname)
|
||||
assert.Equal(t, testData.Stats.Cpu, decodedCbor.Stats.Cpu)
|
||||
} else {
|
||||
// Should be JSON - try to decode as JSON
|
||||
var decodedJson system.CombinedData
|
||||
err = json.Unmarshal([]byte(encodedData), &decodedJson)
|
||||
assert.NoError(t, err, "Should be valid JSON data")
|
||||
|
||||
var decodedCbor system.CombinedData
|
||||
err = cbor.Unmarshal([]byte(encodedData), &decodedCbor)
|
||||
assert.Error(t, err, "Should not be valid CBOR data")
|
||||
|
||||
// Verify the decoded JSON data matches our test data
|
||||
assert.Equal(t, testData.Info.Hostname, decodedJson.Info.Hostname)
|
||||
assert.Equal(t, testData.Stats.Cpu, decodedJson.Stats.Cpu)
|
||||
|
||||
// Verify it looks like JSON (starts with '{' and contains readable field names)
|
||||
assert.True(t, strings.HasPrefix(encodedData, "{"), "JSON should start with '{'")
|
||||
assert.Contains(t, encodedData, `"info"`, "JSON should contain readable field names")
|
||||
assert.Contains(t, encodedData, `"stats"`, "JSON should contain readable field names")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create test data for encoding tests
|
||||
func createTestCombinedData() *system.CombinedData {
|
||||
return &system.CombinedData{
|
||||
Stats: system.Stats{
|
||||
Cpu: 25.5,
|
||||
Mem: 8589934592, // 8GB
|
||||
MemUsed: 4294967296, // 4GB
|
||||
MemPct: 50.0,
|
||||
DiskTotal: 1099511627776, // 1TB
|
||||
DiskUsed: 549755813888, // 512GB
|
||||
DiskPct: 50.0,
|
||||
},
|
||||
Info: system.Info{
|
||||
Hostname: "test-host",
|
||||
Cores: 8,
|
||||
CpuModel: "Test CPU Model",
|
||||
Uptime: 3600,
|
||||
AgentVersion: "0.12.0",
|
||||
Os: system.Linux,
|
||||
},
|
||||
Containers: []*container.Stats{
|
||||
{
|
||||
Name: "test-container",
|
||||
Cpu: 10.5,
|
||||
Mem: 1073741824, // 1GB
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestHubVersionCaching(t *testing.T) {
|
||||
// Reset the global hubVersions map to ensure clean state
|
||||
hubVersions = nil
|
||||
|
||||
agent, err := NewAgent("")
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx1 := &mockSSHContext{
|
||||
sessionID: "session1",
|
||||
clientVersion: "SSH-2.0-beszel_0.12.0",
|
||||
}
|
||||
ctx2 := &mockSSHContext{
|
||||
sessionID: "session2",
|
||||
clientVersion: "SSH-2.0-beszel_0.11.0",
|
||||
}
|
||||
|
||||
// First calls should cache the versions
|
||||
v1 := agent.getHubVersion("session1", ctx1)
|
||||
v2 := agent.getHubVersion("session2", ctx2)
|
||||
|
||||
assert.Equal(t, "0.12.0", v1.String())
|
||||
assert.Equal(t, "0.11.0", v2.String())
|
||||
|
||||
// Verify caching by changing context but keeping same session ID
|
||||
ctx1.clientVersion = "SSH-2.0-beszel_0.10.0"
|
||||
v1Cached := agent.getHubVersion("session1", ctx1)
|
||||
assert.Equal(t, "0.12.0", v1Cached.String()) // Should still be cached version
|
||||
|
||||
// New session should get new version
|
||||
ctx3 := &mockSSHContext{
|
||||
sessionID: "session3",
|
||||
clientVersion: "SSH-2.0-beszel_0.13.0",
|
||||
}
|
||||
v3 := agent.getHubVersion("session3", ctx3)
|
||||
assert.Equal(t, "0.13.0", v3.String())
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel"
|
||||
"beszel/internal/entities/system"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -11,19 +9,41 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel"
|
||||
"github.com/henrygd/beszel/agent/battery"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/cpu"
|
||||
"github.com/shirou/gopsutil/v4/disk"
|
||||
"github.com/shirou/gopsutil/v4/host"
|
||||
"github.com/shirou/gopsutil/v4/load"
|
||||
"github.com/shirou/gopsutil/v4/mem"
|
||||
psutilNet "github.com/shirou/gopsutil/v4/net"
|
||||
"github.com/shirou/gopsutil/v4/sensors"
|
||||
)
|
||||
|
||||
// Sets initial / non-changing values about the host system
|
||||
func (a *Agent) initializeSystemInfo() {
|
||||
a.systemInfo.AgentVersion = beszel.Version
|
||||
a.systemInfo.Hostname, _ = os.Hostname()
|
||||
a.systemInfo.KernelVersion, _ = host.KernelVersion()
|
||||
|
||||
platform, _, version, _ := host.PlatformInformation()
|
||||
|
||||
if platform == "darwin" {
|
||||
a.systemInfo.KernelVersion = version
|
||||
a.systemInfo.Os = system.Darwin
|
||||
} else if strings.Contains(platform, "indows") {
|
||||
a.systemInfo.KernelVersion = strings.Replace(platform, "Microsoft ", "", 1) + " " + version
|
||||
a.systemInfo.Os = system.Windows
|
||||
} else if platform == "freebsd" {
|
||||
a.systemInfo.Os = system.Freebsd
|
||||
a.systemInfo.KernelVersion = version
|
||||
} else {
|
||||
a.systemInfo.Os = system.Linux
|
||||
}
|
||||
|
||||
if a.systemInfo.KernelVersion == "" {
|
||||
a.systemInfo.KernelVersion, _ = host.KernelVersion()
|
||||
}
|
||||
|
||||
// cpu model
|
||||
if info, err := cpu.Info(); err == nil && len(info) > 0 {
|
||||
@@ -41,10 +61,10 @@ func (a *Agent) initializeSystemInfo() {
|
||||
}
|
||||
|
||||
// zfs
|
||||
if _, err := getARCSize(); err == nil {
|
||||
a.zfs = true
|
||||
} else {
|
||||
if _, err := getARCSize(); err != nil {
|
||||
slog.Debug("Not monitoring ZFS ARC", "err", err)
|
||||
} else {
|
||||
a.zfs = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +72,11 @@ func (a *Agent) initializeSystemInfo() {
|
||||
func (a *Agent) getSystemStats() system.Stats {
|
||||
systemStats := system.Stats{}
|
||||
|
||||
// battery
|
||||
if battery.HasReadableBattery() {
|
||||
systemStats.Battery[0], systemStats.Battery[1], _ = battery.GetBatteryStats()
|
||||
}
|
||||
|
||||
// cpu percent
|
||||
cpuPct, err := cpu.Percent(0, false)
|
||||
if err != nil {
|
||||
@@ -60,6 +85,16 @@ func (a *Agent) getSystemStats() system.Stats {
|
||||
systemStats.Cpu = twoDecimals(cpuPct[0])
|
||||
}
|
||||
|
||||
// load average
|
||||
if avgstat, err := load.Avg(); err == nil {
|
||||
systemStats.LoadAvg[0] = avgstat.Load1
|
||||
systemStats.LoadAvg[1] = avgstat.Load5
|
||||
systemStats.LoadAvg[2] = avgstat.Load15
|
||||
slog.Debug("Load average", "5m", avgstat.Load5, "15m", avgstat.Load15)
|
||||
} else {
|
||||
slog.Error("Error getting load average", "err", err)
|
||||
}
|
||||
|
||||
// memory
|
||||
if v, err := mem.VirtualMemory(); err == nil {
|
||||
// swap
|
||||
@@ -146,24 +181,27 @@ func (a *Agent) getSystemStats() system.Stats {
|
||||
a.initializeNetIoStats()
|
||||
}
|
||||
if netIO, err := psutilNet.IOCounters(true); err == nil {
|
||||
secondsElapsed := time.Since(a.netIoStats.Time).Seconds()
|
||||
msElapsed := uint64(time.Since(a.netIoStats.Time).Milliseconds())
|
||||
a.netIoStats.Time = time.Now()
|
||||
bytesSent := uint64(0)
|
||||
bytesRecv := uint64(0)
|
||||
totalBytesSent := uint64(0)
|
||||
totalBytesRecv := uint64(0)
|
||||
// sum all bytes sent and received
|
||||
for _, v := range netIO {
|
||||
// skip if not in valid network interfaces list
|
||||
if _, exists := a.netInterfaces[v.Name]; !exists {
|
||||
continue
|
||||
}
|
||||
bytesSent += v.BytesSent
|
||||
bytesRecv += v.BytesRecv
|
||||
totalBytesSent += v.BytesSent
|
||||
totalBytesRecv += v.BytesRecv
|
||||
}
|
||||
// add to systemStats
|
||||
sentPerSecond := float64(bytesSent-a.netIoStats.BytesSent) / secondsElapsed
|
||||
recvPerSecond := float64(bytesRecv-a.netIoStats.BytesRecv) / secondsElapsed
|
||||
networkSentPs := bytesToMegabytes(sentPerSecond)
|
||||
networkRecvPs := bytesToMegabytes(recvPerSecond)
|
||||
var bytesSentPerSecond, bytesRecvPerSecond uint64
|
||||
if msElapsed > 0 {
|
||||
bytesSentPerSecond = (totalBytesSent - a.netIoStats.BytesSent) * 1000 / msElapsed
|
||||
bytesRecvPerSecond = (totalBytesRecv - a.netIoStats.BytesRecv) * 1000 / msElapsed
|
||||
}
|
||||
networkSentPs := bytesToMegabytes(float64(bytesSentPerSecond))
|
||||
networkRecvPs := bytesToMegabytes(float64(bytesRecvPerSecond))
|
||||
// add check for issue (#150) where sent is a massive number
|
||||
if networkSentPs > 10_000 || networkRecvPs > 10_000 {
|
||||
slog.Warn("Invalid net stats. Resetting.", "sent", networkSentPs, "recv", networkRecvPs)
|
||||
@@ -178,9 +216,10 @@ func (a *Agent) getSystemStats() system.Stats {
|
||||
} else {
|
||||
systemStats.NetworkSent = networkSentPs
|
||||
systemStats.NetworkRecv = networkRecvPs
|
||||
systemStats.Bandwidth[0], systemStats.Bandwidth[1] = bytesSentPerSecond, bytesRecvPerSecond
|
||||
// update netIoStats
|
||||
a.netIoStats.BytesSent = bytesSent
|
||||
a.netIoStats.BytesRecv = bytesRecv
|
||||
a.netIoStats.BytesSent = totalBytesSent
|
||||
a.netIoStats.BytesRecv = totalBytesRecv
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,76 +239,45 @@ func (a *Agent) getSystemStats() system.Stats {
|
||||
if systemStats.Temperatures == nil {
|
||||
systemStats.Temperatures = make(map[string]float64, len(gpuData))
|
||||
}
|
||||
highestTemp := 0.0
|
||||
for _, gpu := range gpuData {
|
||||
if gpu.Temperature > 0 {
|
||||
systemStats.Temperatures[gpu.Name] = gpu.Temperature
|
||||
if a.primarySensor == gpu.Name {
|
||||
if a.sensorConfig.primarySensor == gpu.Name {
|
||||
a.systemInfo.DashboardTemp = gpu.Temperature
|
||||
}
|
||||
if gpu.Temperature > highestTemp {
|
||||
highestTemp = gpu.Temperature
|
||||
}
|
||||
}
|
||||
// update high gpu percent for dashboard
|
||||
a.systemInfo.GpuPct = max(a.systemInfo.GpuPct, gpu.Usage)
|
||||
}
|
||||
// use highest temp for dashboard temp if dashboard temp is unset
|
||||
if a.systemInfo.DashboardTemp == 0 {
|
||||
a.systemInfo.DashboardTemp = highestTemp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update base system info
|
||||
a.systemInfo.Cpu = systemStats.Cpu
|
||||
a.systemInfo.LoadAvg = systemStats.LoadAvg
|
||||
// TODO: remove these in future release in favor of load avg array
|
||||
a.systemInfo.LoadAvg1 = systemStats.LoadAvg[0]
|
||||
a.systemInfo.LoadAvg5 = systemStats.LoadAvg[1]
|
||||
a.systemInfo.LoadAvg15 = systemStats.LoadAvg[2]
|
||||
a.systemInfo.MemPct = systemStats.MemPct
|
||||
a.systemInfo.DiskPct = systemStats.DiskPct
|
||||
a.systemInfo.Uptime, _ = host.Uptime()
|
||||
// TODO: in future release, remove MB bandwidth values in favor of bytes
|
||||
a.systemInfo.Bandwidth = twoDecimals(systemStats.NetworkSent + systemStats.NetworkRecv)
|
||||
a.systemInfo.BandwidthBytes = systemStats.Bandwidth[0] + systemStats.Bandwidth[1]
|
||||
slog.Debug("sysinfo", "data", a.systemInfo)
|
||||
|
||||
return systemStats
|
||||
}
|
||||
|
||||
func (a *Agent) updateTemperatures(systemStats *system.Stats) {
|
||||
// skip if sensors whitelist is set to empty string
|
||||
if a.sensorsWhitelist != nil && len(a.sensorsWhitelist) == 0 {
|
||||
slog.Debug("Skipping temperature collection")
|
||||
return
|
||||
}
|
||||
|
||||
// reset high temp
|
||||
a.systemInfo.DashboardTemp = 0
|
||||
|
||||
// get sensor data
|
||||
temps, _ := sensors.TemperaturesWithContext(a.sensorsContext)
|
||||
slog.Debug("Temperature", "sensors", temps)
|
||||
|
||||
// return if no sensors
|
||||
if len(temps) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
systemStats.Temperatures = make(map[string]float64, len(temps))
|
||||
for i, sensor := range temps {
|
||||
// skip if temperature is unreasonable
|
||||
if sensor.Temperature <= 0 || sensor.Temperature >= 200 {
|
||||
continue
|
||||
}
|
||||
sensorName := sensor.SensorKey
|
||||
if _, ok := systemStats.Temperatures[sensorName]; ok {
|
||||
// if key already exists, append int to key
|
||||
sensorName = sensorName + "_" + strconv.Itoa(i)
|
||||
}
|
||||
// skip if not in whitelist
|
||||
if a.sensorsWhitelist != nil {
|
||||
if _, nameInWhitelist := a.sensorsWhitelist[sensorName]; !nameInWhitelist {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// set dashboard temperature
|
||||
if a.primarySensor == "" {
|
||||
a.systemInfo.DashboardTemp = max(a.systemInfo.DashboardTemp, sensor.Temperature)
|
||||
} else if a.primarySensor == sensorName {
|
||||
a.systemInfo.DashboardTemp = sensor.Temperature
|
||||
}
|
||||
systemStats.Temperatures[sensorName] = twoDecimals(sensor.Temperature)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the size of the ZFS ARC memory cache in bytes
|
||||
func getARCSize() (uint64, error) {
|
||||
file, err := os.Open("/proc/spl/kstat/zfs/arcstats")
|
||||
165
agent/update.go
Normal file
165
agent/update.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/henrygd/beszel/internal/ghupdate"
|
||||
)
|
||||
|
||||
// restarter knows how to restart the beszel-agent service.
|
||||
type restarter interface {
|
||||
Restart() error
|
||||
}
|
||||
|
||||
type systemdRestarter struct{ cmd string }
|
||||
|
||||
func (s *systemdRestarter) Restart() error {
|
||||
// Only restart if the service is active
|
||||
if err := exec.Command(s.cmd, "is-active", "beszel-agent.service").Run(); err != nil {
|
||||
return nil
|
||||
}
|
||||
ghupdate.ColorPrint(ghupdate.ColorYellow, "Restarting beszel-agent.service via systemd…")
|
||||
return exec.Command(s.cmd, "restart", "beszel-agent.service").Run()
|
||||
}
|
||||
|
||||
type openRCRestarter struct{ cmd string }
|
||||
|
||||
func (o *openRCRestarter) Restart() error {
|
||||
if err := exec.Command(o.cmd, "status", "beszel-agent").Run(); err != nil {
|
||||
return nil
|
||||
}
|
||||
ghupdate.ColorPrint(ghupdate.ColorYellow, "Restarting beszel-agent via OpenRC…")
|
||||
return exec.Command(o.cmd, "restart", "beszel-agent").Run()
|
||||
}
|
||||
|
||||
type openWRTRestarter struct{ cmd string }
|
||||
|
||||
func (w *openWRTRestarter) Restart() error {
|
||||
if err := exec.Command(w.cmd, "running", "beszel-agent").Run(); err != nil {
|
||||
return nil
|
||||
}
|
||||
ghupdate.ColorPrint(ghupdate.ColorYellow, "Restarting beszel-agent via procd…")
|
||||
return exec.Command(w.cmd, "restart", "beszel-agent").Run()
|
||||
}
|
||||
|
||||
type freeBSDRestarter struct{ cmd string }
|
||||
|
||||
func (f *freeBSDRestarter) Restart() error {
|
||||
if err := exec.Command(f.cmd, "beszel-agent", "status").Run(); err != nil {
|
||||
return nil
|
||||
}
|
||||
ghupdate.ColorPrint(ghupdate.ColorYellow, "Restarting beszel-agent via FreeBSD rc…")
|
||||
return exec.Command(f.cmd, "beszel-agent", "restart").Run()
|
||||
}
|
||||
|
||||
func detectRestarter() restarter {
|
||||
if path, err := exec.LookPath("systemctl"); err == nil {
|
||||
return &systemdRestarter{cmd: path}
|
||||
}
|
||||
if path, err := exec.LookPath("rc-service"); err == nil {
|
||||
return &openRCRestarter{cmd: path}
|
||||
}
|
||||
if path, err := exec.LookPath("service"); err == nil {
|
||||
if runtime.GOOS == "freebsd" {
|
||||
return &freeBSDRestarter{cmd: path}
|
||||
}
|
||||
return &openWRTRestarter{cmd: path}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update checks GitHub for a newer release of beszel-agent, applies it,
|
||||
// fixes SELinux context if needed, and restarts the service.
|
||||
func Update(useMirror bool) error {
|
||||
exePath, _ := os.Executable()
|
||||
|
||||
dataDir, err := getDataDir()
|
||||
if err != nil {
|
||||
dataDir = os.TempDir()
|
||||
}
|
||||
updated, err := ghupdate.Update(ghupdate.Config{
|
||||
ArchiveExecutable: "beszel-agent",
|
||||
DataDir: dataDir,
|
||||
UseMirror: useMirror,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if !updated {
|
||||
return nil
|
||||
}
|
||||
|
||||
// make sure the file is executable
|
||||
if err := os.Chmod(exePath, 0755); err != nil {
|
||||
ghupdate.ColorPrintf(ghupdate.ColorYellow, "Warning: failed to set executable permissions: %v", err)
|
||||
}
|
||||
// set ownership to beszel:beszel if possible
|
||||
if chownPath, err := exec.LookPath("chown"); err == nil {
|
||||
if err := exec.Command(chownPath, "beszel:beszel", exePath).Run(); err != nil {
|
||||
ghupdate.ColorPrintf(ghupdate.ColorYellow, "Warning: failed to set file ownership: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 6) Fix SELinux context if necessary
|
||||
if err := handleSELinuxContext(exePath); err != nil {
|
||||
ghupdate.ColorPrintf(ghupdate.ColorYellow, "Warning: SELinux context handling: %v", err)
|
||||
}
|
||||
|
||||
// 7) Restart service if running under a recognised init system
|
||||
if r := detectRestarter(); r != nil {
|
||||
if err := r.Restart(); err != nil {
|
||||
ghupdate.ColorPrintf(ghupdate.ColorYellow, "Warning: failed to restart service: %v", err)
|
||||
ghupdate.ColorPrint(ghupdate.ColorYellow, "Please restart the service manually.")
|
||||
} else {
|
||||
ghupdate.ColorPrint(ghupdate.ColorGreen, "Service restarted successfully")
|
||||
}
|
||||
} else {
|
||||
ghupdate.ColorPrint(ghupdate.ColorYellow, "No supported init system detected; please restart manually if needed.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleSELinuxContext restores or applies the correct SELinux label to the binary.
|
||||
func handleSELinuxContext(path string) error {
|
||||
out, err := exec.Command("getenforce").Output()
|
||||
if err != nil {
|
||||
// SELinux not enabled or getenforce not available
|
||||
return nil
|
||||
}
|
||||
state := strings.TrimSpace(string(out))
|
||||
if state == "Disabled" {
|
||||
return nil
|
||||
}
|
||||
|
||||
ghupdate.ColorPrint(ghupdate.ColorYellow, "SELinux is enabled; applying context…")
|
||||
var errs []string
|
||||
|
||||
// Try persistent context via semanage+restorecon
|
||||
if semanagePath, err := exec.LookPath("semanage"); err == nil {
|
||||
if err := exec.Command(semanagePath, "fcontext", "-a", "-t", "bin_t", path).Run(); err != nil {
|
||||
errs = append(errs, "semanage fcontext failed: "+err.Error())
|
||||
} else if restoreconPath, err := exec.LookPath("restorecon"); err == nil {
|
||||
if err := exec.Command(restoreconPath, "-v", path).Run(); err != nil {
|
||||
errs = append(errs, "restorecon failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to temporary context via chcon
|
||||
if chconPath, err := exec.LookPath("chcon"); err == nil {
|
||||
if err := exec.Command(chconPath, "-t", "bin_t", path).Run(); err != nil {
|
||||
errs = append(errs, "chcon failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("SELinux context errors: %s", strings.Join(errs, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
15
beszel.go
Normal file
15
beszel.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// Package beszel provides core application constants and version information
|
||||
// which are used throughout the application.
|
||||
package beszel
|
||||
|
||||
import "github.com/blang/semver"
|
||||
|
||||
const (
|
||||
// Version is the current version of the application.
|
||||
Version = "0.12.7"
|
||||
// AppName is the name of the application.
|
||||
AppName = "beszel"
|
||||
)
|
||||
|
||||
// MinVersionCbor is the minimum supported version for CBOR compatibility.
|
||||
var MinVersionCbor = semver.MustParse("0.12.0")
|
||||
@@ -1,123 +0,0 @@
|
||||
version: 2
|
||||
|
||||
project_name: beszel
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
||||
builds:
|
||||
- id: beszel
|
||||
binary: beszel
|
||||
main: cmd/hub/hub.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
- arm
|
||||
|
||||
- id: beszel-agent
|
||||
binary: beszel-agent
|
||||
main: cmd/agent/agent.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- freebsd
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
- arm
|
||||
- mips64
|
||||
- riscv64
|
||||
ignore:
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: darwin
|
||||
goarch: riscv64
|
||||
- goos: windows
|
||||
goarch: riscv64
|
||||
|
||||
archives:
|
||||
- id: beszel
|
||||
format: tar.gz
|
||||
builds:
|
||||
- beszel-agent
|
||||
name_template: >-
|
||||
{{ .Binary }}_
|
||||
{{- .Os }}_
|
||||
{{- .Arch }}
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
- id: beszel-agent
|
||||
format: tar.gz
|
||||
builds:
|
||||
- beszel
|
||||
name_template: >-
|
||||
{{ .Binary }}_
|
||||
{{- .Os }}_
|
||||
{{- .Arch }}
|
||||
|
||||
nfpms:
|
||||
- id: beszel-agent
|
||||
package_name: beszel-agent
|
||||
description: |-
|
||||
Agent for Beszel
|
||||
Beszel is a lightweight server monitoring platform that includes Docker
|
||||
statistics, historical data, and alert functions. It has a friendly web
|
||||
interface, simple configuration, and is ready to use out of the box.
|
||||
It supports automatic backup, multi-user, OAuth authentication, and
|
||||
API access.
|
||||
maintainer: henrygd <hank@henrygd.me>
|
||||
section: net
|
||||
builds:
|
||||
- beszel-agent
|
||||
formats:
|
||||
- deb
|
||||
# don't think this is needed with CGO_ENABLED=0
|
||||
# dependencies:
|
||||
# - libc6
|
||||
contents:
|
||||
- src: ../supplemental/debian/beszel-agent.service
|
||||
dst: lib/systemd/system/beszel-agent.service
|
||||
packager: deb
|
||||
- src: ../supplemental/debian/copyright
|
||||
dst: usr/share/doc/beszel-agent/copyright
|
||||
packager: deb
|
||||
- src: ../supplemental/debian/lintian-overrides
|
||||
dst: usr/share/lintian/overrides/beszel-agent
|
||||
packager: deb
|
||||
scripts:
|
||||
postinstall: ../supplemental/debian/postinstall.sh
|
||||
preremove: ../supplemental/debian/prerm.sh
|
||||
postremove: ../supplemental/debian/postrm.sh
|
||||
deb:
|
||||
predepends:
|
||||
- adduser
|
||||
- debconf
|
||||
scripts:
|
||||
templates: ../supplemental/debian/templates
|
||||
# Currently broken due to a bug in goreleaser
|
||||
# https://github.com/goreleaser/goreleaser/issues/5487
|
||||
#config: ../supplemental/debian/config.sh
|
||||
|
||||
release:
|
||||
draft: true
|
||||
|
||||
changelog:
|
||||
disable: true
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
@@ -1,72 +0,0 @@
|
||||
# Default OS/ARCH values
|
||||
OS ?= $(shell go env GOOS)
|
||||
ARCH ?= $(shell go env GOARCH)
|
||||
# Skip building the web UI if true
|
||||
SKIP_WEB ?= false
|
||||
|
||||
.PHONY: tidy build-agent build-hub build clean lint dev-server dev-agent dev-hub dev generate-locales
|
||||
.DEFAULT_GOAL := build
|
||||
|
||||
clean:
|
||||
go clean
|
||||
rm -rf ./build
|
||||
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
test: export GOEXPERIMENT=synctest
|
||||
test:
|
||||
go test -tags=testing ./...
|
||||
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
build-web-ui:
|
||||
@if command -v bun >/dev/null 2>&1; then \
|
||||
bun install --cwd ./site && \
|
||||
bun run --cwd ./site build; \
|
||||
else \
|
||||
npm install --prefix ./site && \
|
||||
npm run --prefix ./site build; \
|
||||
fi
|
||||
|
||||
build-agent: tidy
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel-agent_$(OS)_$(ARCH) -ldflags "-w -s" beszel/cmd/agent
|
||||
|
||||
build-hub: tidy $(if $(filter false,$(SKIP_WEB)),build-web-ui)
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel_$(OS)_$(ARCH) -ldflags "-w -s" beszel/cmd/hub
|
||||
|
||||
build: build-agent build-hub
|
||||
|
||||
generate-locales:
|
||||
@if [ ! -f ./site/src/locales/en/en.ts ]; then \
|
||||
echo "Generating locales..."; \
|
||||
command -v bun >/dev/null 2>&1 && cd ./site && bun install && bun run sync || cd ./site && npm install && npm run sync; \
|
||||
fi
|
||||
|
||||
dev-server: generate-locales
|
||||
cd ./site
|
||||
@if command -v bun >/dev/null 2>&1; then \
|
||||
cd ./site && bun run dev; \
|
||||
else \
|
||||
cd ./site && npm run dev; \
|
||||
fi
|
||||
|
||||
dev-hub: export ENV=dev
|
||||
dev-hub:
|
||||
mkdir -p ./site/dist && touch ./site/dist/index.html
|
||||
@if command -v entr >/dev/null 2>&1; then \
|
||||
find ./cmd/hub/*.go ./internal/{alerts,hub,records,users}/*.go | entr -r -s "cd ./cmd/hub && go run . serve"; \
|
||||
else \
|
||||
cd ./cmd/hub && go run . serve; \
|
||||
fi
|
||||
|
||||
dev-agent:
|
||||
@if command -v entr >/dev/null 2>&1; then \
|
||||
find ./cmd/agent/*.go ./internal/agent/*.go | entr -r go run beszel/cmd/agent; \
|
||||
else \
|
||||
go run beszel/cmd/agent; \
|
||||
fi
|
||||
|
||||
# KEY="..." make -j dev
|
||||
dev: dev-server dev-hub dev-agent
|
||||
@@ -1,122 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"beszel"
|
||||
"beszel/internal/agent"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// cli options
|
||||
type cmdOptions struct {
|
||||
key string // key is the public key(s) for SSH authentication.
|
||||
listen string // listen is the address or port to listen on.
|
||||
}
|
||||
|
||||
// parse parses the command line flags and populates the config struct.
|
||||
// It returns true if a subcommand was handled and the program should exit.
|
||||
func (opts *cmdOptions) parse() bool {
|
||||
flag.StringVar(&opts.key, "key", "", "Public key(s) for SSH authentication")
|
||||
flag.StringVar(&opts.listen, "listen", "", "Address or port to listen on")
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Printf("Usage: %s [command] [flags]\n", os.Args[0])
|
||||
fmt.Println("\nCommands:")
|
||||
fmt.Println(" health Check if the agent is running")
|
||||
fmt.Println(" help Display this help message")
|
||||
fmt.Println(" update Update to the latest version")
|
||||
fmt.Println(" version Display the version")
|
||||
fmt.Println("\nFlags:")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
subcommand := ""
|
||||
if len(os.Args) > 1 {
|
||||
subcommand = os.Args[1]
|
||||
}
|
||||
|
||||
switch subcommand {
|
||||
case "-v", "version":
|
||||
fmt.Println(beszel.AppName+"-agent", beszel.Version)
|
||||
return true
|
||||
case "help":
|
||||
flag.Usage()
|
||||
return true
|
||||
case "update":
|
||||
agent.Update()
|
||||
return true
|
||||
case "health":
|
||||
// for health, we need to parse flags first to get the listen address
|
||||
args := append(os.Args[2:], subcommand)
|
||||
flag.CommandLine.Parse(args)
|
||||
addr := opts.getAddress()
|
||||
network := agent.GetNetwork(addr)
|
||||
err := agent.Health(addr, network)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Print("ok")
|
||||
return true
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
return false
|
||||
}
|
||||
|
||||
// loadPublicKeys loads the public keys from the command line flag, environment variable, or key file.
|
||||
func (opts *cmdOptions) loadPublicKeys() ([]ssh.PublicKey, error) {
|
||||
// Try command line flag first
|
||||
if opts.key != "" {
|
||||
return agent.ParseKeys(opts.key)
|
||||
}
|
||||
|
||||
// Try environment variable
|
||||
if key, ok := agent.GetEnv("KEY"); ok && key != "" {
|
||||
return agent.ParseKeys(key)
|
||||
}
|
||||
|
||||
// Try key file
|
||||
keyFile, ok := agent.GetEnv("KEY_FILE")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no key provided: must set -key flag, KEY env var, or KEY_FILE env var. Use 'beszel-agent help' for usage")
|
||||
}
|
||||
|
||||
pubKey, err := os.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read key file: %w", err)
|
||||
}
|
||||
return agent.ParseKeys(string(pubKey))
|
||||
}
|
||||
|
||||
func (opts *cmdOptions) getAddress() string {
|
||||
return agent.GetAddress(opts.listen)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var opts cmdOptions
|
||||
subcommandHandled := opts.parse()
|
||||
|
||||
if subcommandHandled {
|
||||
return
|
||||
}
|
||||
|
||||
var serverConfig agent.ServerOptions
|
||||
var err error
|
||||
serverConfig.Keys, err = opts.loadPublicKeys()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load public keys:", err)
|
||||
}
|
||||
|
||||
addr := opts.getAddress()
|
||||
serverConfig.Addr = addr
|
||||
serverConfig.Network = agent.GetNetwork(addr)
|
||||
|
||||
agent := agent.NewAgent()
|
||||
if err := agent.StartServer(serverConfig); err != nil {
|
||||
log.Fatal("Failed to start server:", err)
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
module beszel
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/containrrr/shoutrrr v0.8.0
|
||||
github.com/gliderlabs/ssh v0.3.8
|
||||
github.com/goccy/go-json v0.10.5
|
||||
github.com/pocketbase/dbx v1.11.0
|
||||
github.com/pocketbase/pocketbase v0.25.9
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3
|
||||
github.com/shirou/gopsutil/v4 v4.25.2
|
||||
github.com/spf13/cast v1.7.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/crypto v0.35.0
|
||||
golang.org/x/exp v0.0.0-20250228200357-dead58393ab7
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.61 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.64 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.78.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.16 // indirect
|
||||
github.com/aws/smithy-go v1.22.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.2 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/go-github/v30 v30.1.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250224150550-a661cff19cfb // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.9.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
gocloud.dev v0.40.0 // indirect
|
||||
golang.org/x/image v0.24.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
google.golang.org/api v0.223.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e // indirect
|
||||
google.golang.org/grpc v1.70.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.35.0 // indirect
|
||||
)
|
||||
394
beszel/go.sum
394
beszel/go.sum
@@ -1,394 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
|
||||
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
|
||||
cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
|
||||
cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
|
||||
cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0=
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4=
|
||||
cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zFMNbus=
|
||||
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
|
||||
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
|
||||
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.8 h1:RpwAfYcV2lr/yRc4lWhUM9JRPQqKgKWmou3LV7UfWP4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.8/go.mod h1:t+G7Fq1OcO8cXTPPXzxQSnj/5Xzdc9jAAD3Xrn9/Mgo=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.61 h1:Hd/uX6Wo2iUW1JWII+rmyCD7MMhOe7ALwQXN6sKDd1o=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.61/go.mod h1:L7vaLkwHY1qgW0gG1zG0z/X0sQ5tpIY5iI13+j3qI80=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.64 h1:RTko0AQ0i1vWXDM97DkuW6zskgOxFxm4RqC0kmBJFkE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.64/go.mod h1:ty968MpOa5CoQ/ALWNB8Gmfoehof2nRHDR/DZDPfimE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.2 h1:t/gZFyrijKuSU0elA5kRngP/oU3mc0I+Dvp8HwRE4c0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.2/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.78.0 h1:EBm8lXevBWe+kK9VOU/IBeOI189WPRwPUc3LvJK9GOs=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.78.0/go.mod h1:4qzsZSzB/KiX2EzDjs9D7A8rI/WGJxZceVJIHqtJjIU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.0 h1:2U9sF8nKy7UgyEeLiZTRg6ShBS22z8UnYpV6aRFL0is=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.0/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.0 h1:wjAdc85cXdQR5uLx5FwWvGIHm4OPJhTyzUHU8craXtE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.0/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.16 h1:BHEK2Q/7CMRMCb3nySi/w8UbIcPhKvYP5s1xf8/izn0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.16/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
||||
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
|
||||
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
|
||||
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
|
||||
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
|
||||
github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
|
||||
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
||||
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lufia/plan9stats v0.0.0-20250224150550-a661cff19cfb h1:YU0XAr3+rMpM8fP80KEesn32Qa9qkbquokvuwzWyYuA=
|
||||
github.com/lufia/plan9stats v0.0.0-20250224150550-a661cff19cfb/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU=
|
||||
github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.25.9 h1:/PSJcy39vEGv4lsBG4HV0ZFLcFsTdK9oMkJbxVlVJSs=
|
||||
github.com/pocketbase/pocketbase v0.25.9/go.mod h1:gOnPr+g/GS+iqKh5XYXycdRWVGhiHY4c1H4TGjU9DDw=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag=
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.2 h1:NMscG3l2CqtWFS86kj3vP7soOczqrQYIEhO/pMvvQkk=
|
||||
github.com/shirou/gopsutil/v4 v4.25.2/go.mod h1:34gBYJzyqCDT11b6bMHP0XCvWeU3J61XRT7a2EmCRTA=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE=
|
||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
|
||||
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
|
||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
gocloud.dev v0.40.0 h1:f8LgP+4WDqOG/RXoUcyLpeIAGOcAbZrZbDQCUee10ng=
|
||||
gocloud.dev v0.40.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20250228200357-dead58393ab7 h1:aWwlzYV971S4BXRS9AmqwDLAD85ouC6X+pocatKY58c=
|
||||
golang.org/x/exp v0.0.0-20250228200357-dead58393ab7/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
google.golang.org/api v0.223.0 h1:JUTaWEriXmEy5AhvdMgksGGPEFsYfUKaPEYXd4c3Wvc=
|
||||
google.golang.org/api v0.223.0/go.mod h1:C+RS7Z+dDwds2b+zoAk5hN/eSfsiCn0UDrYof/M4d2M=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
|
||||
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e h1:YA5lmSs3zc/5w+xsRcHqpETkaYyK63ivEPzNTcUUlSA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
|
||||
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
|
||||
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
|
||||
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
|
||||
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
|
||||
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.35.0 h1:yQps4fegMnZFdphtzlfQTCNBWtS0CZv48pRpW3RFHRw=
|
||||
modernc.org/sqlite v1.35.0/go.mod h1:9cr2sicr7jIaWTBKQmAxQLfBv9LL0su4ZTEV+utt3ic=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
@@ -1,139 +0,0 @@
|
||||
// Package agent handles the agent's SSH server and system stats collection.
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel"
|
||||
"beszel/internal/entities/system"
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/common"
|
||||
)
|
||||
|
||||
type Agent struct {
|
||||
sync.Mutex // Used to lock agent while collecting data
|
||||
debug bool // true if LOG_LEVEL is set to debug
|
||||
zfs bool // true if system has arcstats
|
||||
memCalc string // Memory calculation formula
|
||||
fsNames []string // List of filesystem device names being monitored
|
||||
fsStats map[string]*system.FsStats // Keeps track of disk stats for each filesystem
|
||||
netInterfaces map[string]struct{} // Stores all valid network interfaces
|
||||
netIoStats system.NetIoStats // Keeps track of bandwidth usage
|
||||
dockerManager *dockerManager // Manages Docker API requests
|
||||
sensorsContext context.Context // Sensors context to override sys location
|
||||
sensorsWhitelist map[string]struct{} // List of sensors to monitor
|
||||
primarySensor string // Value of PRIMARY_SENSOR env var
|
||||
systemInfo system.Info // Host system info
|
||||
gpuManager *GPUManager // Manages GPU data
|
||||
cache *SessionCache // Cache for system stats based on primary session ID
|
||||
}
|
||||
|
||||
func NewAgent() *Agent {
|
||||
agent := &Agent{
|
||||
sensorsContext: context.Background(),
|
||||
fsStats: make(map[string]*system.FsStats),
|
||||
cache: NewSessionCache(69 * time.Second),
|
||||
}
|
||||
agent.memCalc, _ = GetEnv("MEM_CALC")
|
||||
agent.primarySensor, _ = GetEnv("PRIMARY_SENSOR")
|
||||
// Set up slog with a log level determined by the LOG_LEVEL env var
|
||||
if logLevelStr, exists := GetEnv("LOG_LEVEL"); exists {
|
||||
switch strings.ToLower(logLevelStr) {
|
||||
case "debug":
|
||||
agent.debug = true
|
||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||
case "warn":
|
||||
slog.SetLogLoggerLevel(slog.LevelWarn)
|
||||
case "error":
|
||||
slog.SetLogLoggerLevel(slog.LevelError)
|
||||
}
|
||||
}
|
||||
|
||||
slog.Debug(beszel.Version)
|
||||
|
||||
// Set sensors context (allows overriding sys location for sensors)
|
||||
if sysSensors, exists := GetEnv("SYS_SENSORS"); exists {
|
||||
slog.Info("SYS_SENSORS", "path", sysSensors)
|
||||
agent.sensorsContext = context.WithValue(agent.sensorsContext,
|
||||
common.EnvKey, common.EnvMap{common.HostSysEnvKey: sysSensors},
|
||||
)
|
||||
}
|
||||
|
||||
// Set sensors whitelist
|
||||
if sensors, exists := GetEnv("SENSORS"); exists {
|
||||
agent.sensorsWhitelist = make(map[string]struct{})
|
||||
for sensor := range strings.SplitSeq(sensors, ",") {
|
||||
if sensor != "" {
|
||||
agent.sensorsWhitelist[sensor] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initialize system info / docker manager
|
||||
agent.initializeSystemInfo()
|
||||
agent.initializeDiskInfo()
|
||||
agent.initializeNetIoStats()
|
||||
agent.dockerManager = newDockerManager(agent)
|
||||
|
||||
// initialize GPU manager
|
||||
if gm, err := NewGPUManager(); err != nil {
|
||||
slog.Debug("GPU", "err", err)
|
||||
} else {
|
||||
agent.gpuManager = gm
|
||||
}
|
||||
|
||||
// if debugging, print stats
|
||||
if agent.debug {
|
||||
slog.Debug("Stats", "data", agent.gatherStats(""))
|
||||
}
|
||||
|
||||
return agent
|
||||
}
|
||||
|
||||
// GetEnv retrieves an environment variable with a "BESZEL_AGENT_" prefix, or falls back to the unprefixed key.
|
||||
func GetEnv(key string) (value string, exists bool) {
|
||||
if value, exists = os.LookupEnv("BESZEL_AGENT_" + key); exists {
|
||||
return value, exists
|
||||
}
|
||||
// Fallback to the old unprefixed key
|
||||
return os.LookupEnv(key)
|
||||
}
|
||||
|
||||
func (a *Agent) gatherStats(sessionID string) *system.CombinedData {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
cachedData, ok := a.cache.Get(sessionID)
|
||||
if ok {
|
||||
slog.Debug("Cached stats", "session", sessionID)
|
||||
return cachedData
|
||||
}
|
||||
|
||||
*cachedData = system.CombinedData{
|
||||
Stats: a.getSystemStats(),
|
||||
Info: a.systemInfo,
|
||||
}
|
||||
slog.Debug("System stats", "data", cachedData)
|
||||
|
||||
if containerStats, err := a.dockerManager.getDockerStats(); err == nil {
|
||||
cachedData.Containers = containerStats
|
||||
slog.Debug("Docker stats", "data", cachedData.Containers)
|
||||
} else {
|
||||
slog.Debug("Docker stats", "err", err)
|
||||
}
|
||||
|
||||
cachedData.Stats.ExtraFs = make(map[string]*system.FsStats)
|
||||
for name, stats := range a.fsStats {
|
||||
if !stats.Root && stats.DiskTotal > 0 {
|
||||
cachedData.Stats.ExtraFs[name] = stats
|
||||
}
|
||||
}
|
||||
slog.Debug("Extra filesystems", "data", cachedData.Stats.ExtraFs)
|
||||
|
||||
a.cache.Set(sessionID, cachedData)
|
||||
return cachedData
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Health checks if the agent's server is running by attempting to connect to it.
|
||||
//
|
||||
// If an error occurs when attempting to connect to the server, it returns the error.
|
||||
func Health(addr string, network string) error {
|
||||
conn, err := net.DialTimeout(network, addr, 4*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn.Close()
|
||||
return nil
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"beszel/internal/agent"
|
||||
)
|
||||
|
||||
// setupTestServer creates a temporary server for testing
|
||||
func setupTestServer(t *testing.T) (string, func()) {
|
||||
// Create a temporary socket file for Unix socket testing
|
||||
tempSockFile := os.TempDir() + "/beszel_health_test.sock"
|
||||
|
||||
// Clean up any existing socket file
|
||||
os.Remove(tempSockFile)
|
||||
|
||||
// Create a listener
|
||||
listener, err := net.Listen("unix", tempSockFile)
|
||||
require.NoError(t, err, "Failed to create test listener")
|
||||
|
||||
// Start a simple server in a goroutine
|
||||
go func() {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
return // Listener closed
|
||||
}
|
||||
defer conn.Close()
|
||||
// Just accept the connection and do nothing
|
||||
}()
|
||||
|
||||
// Return the socket file path and a cleanup function
|
||||
return tempSockFile, func() {
|
||||
listener.Close()
|
||||
os.Remove(tempSockFile)
|
||||
}
|
||||
}
|
||||
|
||||
// setupTCPTestServer creates a temporary TCP server for testing
|
||||
func setupTCPTestServer(t *testing.T) (string, func()) {
|
||||
// Listen on a random available port
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err, "Failed to create test listener")
|
||||
|
||||
// Get the port that was assigned
|
||||
addr := listener.Addr().(*net.TCPAddr)
|
||||
port := addr.Port
|
||||
|
||||
// Start a simple server in a goroutine
|
||||
go func() {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
return // Listener closed
|
||||
}
|
||||
defer conn.Close()
|
||||
// Just accept the connection and do nothing
|
||||
}()
|
||||
|
||||
// Return the address and a cleanup function
|
||||
return fmt.Sprintf("127.0.0.1:%d", port), func() {
|
||||
listener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
t.Run("server is running (unix socket)", func(t *testing.T) {
|
||||
// Setup a test server
|
||||
sockFile, cleanup := setupTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
// Run the health check with explicit parameters
|
||||
err := agent.Health(sockFile, "unix")
|
||||
require.NoError(t, err, "Failed to check health")
|
||||
})
|
||||
|
||||
t.Run("server is running (tcp address)", func(t *testing.T) {
|
||||
// Setup a test server
|
||||
addr, cleanup := setupTCPTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
// Run the health check with explicit parameters
|
||||
err := agent.Health(addr, "tcp")
|
||||
require.NoError(t, err, "Failed to check health")
|
||||
})
|
||||
|
||||
t.Run("server is not running", func(t *testing.T) {
|
||||
// Use an address that's likely not in use
|
||||
addr := "127.0.0.1:65535"
|
||||
|
||||
// Run the health check with explicit parameters
|
||||
err := agent.Health(addr, "tcp")
|
||||
require.Error(t, err, "Health check should return an error when server is not running")
|
||||
})
|
||||
|
||||
t.Run("invalid network", func(t *testing.T) {
|
||||
// Use an invalid network type
|
||||
err := agent.Health("127.0.0.1:8080", "invalid_network")
|
||||
require.Error(t, err, "Health check should return an error with invalid network")
|
||||
})
|
||||
|
||||
t.Run("unix socket not found", func(t *testing.T) {
|
||||
// Use a non-existent unix socket
|
||||
nonExistentSocket := os.TempDir() + "/non_existent_socket.sock"
|
||||
|
||||
// Make sure it really doesn't exist
|
||||
os.Remove(nonExistentSocket)
|
||||
|
||||
err := agent.Health(nonExistentSocket, "unix")
|
||||
require.Error(t, err, "Health check should return an error when socket doesn't exist")
|
||||
})
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
sshServer "github.com/gliderlabs/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type ServerOptions struct {
|
||||
Addr string
|
||||
Network string
|
||||
Keys []ssh.PublicKey
|
||||
}
|
||||
|
||||
func (a *Agent) StartServer(opts ServerOptions) error {
|
||||
sshServer.Handle(a.handleSession)
|
||||
|
||||
slog.Info("Starting SSH server", "addr", opts.Addr, "network", opts.Network)
|
||||
|
||||
if opts.Network == "unix" {
|
||||
// remove existing socket file if it exists
|
||||
if err := os.Remove(opts.Addr); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// start listening on the address
|
||||
ln, err := net.Listen(opts.Network, opts.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
// Start SSH server on the listener
|
||||
return sshServer.Serve(ln, nil, sshServer.NoPty(),
|
||||
sshServer.PublicKeyAuth(func(ctx sshServer.Context, key sshServer.PublicKey) bool {
|
||||
for _, pubKey := range opts.Keys {
|
||||
if sshServer.KeysEqual(key, pubKey) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func (a *Agent) handleSession(s sshServer.Session) {
|
||||
slog.Debug("New session", "client", s.RemoteAddr())
|
||||
stats := a.gatherStats(s.Context().SessionID())
|
||||
if err := json.NewEncoder(s).Encode(stats); err != nil {
|
||||
slog.Error("Error encoding stats", "err", err, "stats", stats)
|
||||
s.Exit(1)
|
||||
}
|
||||
s.Exit(0)
|
||||
}
|
||||
|
||||
// ParseKeys parses a string containing SSH public keys in authorized_keys format.
|
||||
// It returns a slice of ssh.PublicKey and an error if any key fails to parse.
|
||||
func ParseKeys(input string) ([]ssh.PublicKey, error) {
|
||||
var parsedKeys []ssh.PublicKey
|
||||
for line := range strings.Lines(input) {
|
||||
line = strings.TrimSpace(line)
|
||||
// Skip empty lines or comments
|
||||
if len(line) == 0 || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
// Parse the key
|
||||
parsedKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(line))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse key: %s, error: %w", line, err)
|
||||
}
|
||||
parsedKeys = append(parsedKeys, parsedKey)
|
||||
}
|
||||
return parsedKeys, nil
|
||||
}
|
||||
|
||||
// GetAddress gets the address to listen on or connect to from environment variables or default value.
|
||||
func GetAddress(addr string) string {
|
||||
if addr == "" {
|
||||
addr, _ = GetEnv("LISTEN")
|
||||
}
|
||||
if addr == "" {
|
||||
// Legacy PORT environment variable support
|
||||
addr, _ = GetEnv("PORT")
|
||||
}
|
||||
if addr == "" {
|
||||
return ":45876"
|
||||
}
|
||||
// prefix with : if only port was provided
|
||||
if GetNetwork(addr) != "unix" && !strings.Contains(addr, ":") {
|
||||
addr = ":" + addr
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
// GetNetwork returns the network type to use based on the address
|
||||
func GetNetwork(addr string) string {
|
||||
if network, ok := GetEnv("NETWORK"); ok && network != "" {
|
||||
return network
|
||||
}
|
||||
if strings.HasPrefix(addr, "/") {
|
||||
return "unix"
|
||||
}
|
||||
return "tcp"
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func TestStartServer(t *testing.T) {
|
||||
// Generate a test key pair
|
||||
pubKey, privKey, err := ed25519.GenerateKey(nil)
|
||||
require.NoError(t, err)
|
||||
signer, err := ssh.NewSignerFromKey(privKey)
|
||||
require.NoError(t, err)
|
||||
sshPubKey, err := ssh.NewPublicKey(pubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Generate a different key pair for bad key test
|
||||
badPubKey, badPrivKey, err := ed25519.GenerateKey(nil)
|
||||
require.NoError(t, err)
|
||||
badSigner, err := ssh.NewSignerFromKey(badPrivKey)
|
||||
require.NoError(t, err)
|
||||
sshBadPubKey, err := ssh.NewPublicKey(badPubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
socketFile := filepath.Join(t.TempDir(), "beszel-test.sock")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config ServerOptions
|
||||
wantErr bool
|
||||
errContains string
|
||||
setup func() error
|
||||
cleanup func() error
|
||||
}{
|
||||
{
|
||||
name: "tcp port only",
|
||||
config: ServerOptions{
|
||||
Network: "tcp",
|
||||
Addr: ":45987",
|
||||
Keys: []ssh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tcp with ipv4",
|
||||
config: ServerOptions{
|
||||
Network: "tcp4",
|
||||
Addr: "127.0.0.1:45988",
|
||||
Keys: []ssh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tcp with ipv6",
|
||||
config: ServerOptions{
|
||||
Network: "tcp6",
|
||||
Addr: "[::1]:45989",
|
||||
Keys: []ssh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unix socket",
|
||||
config: ServerOptions{
|
||||
Network: "unix",
|
||||
Addr: socketFile,
|
||||
Keys: []ssh.PublicKey{sshPubKey},
|
||||
},
|
||||
setup: func() error {
|
||||
// Create a socket file that should be removed
|
||||
f, err := os.Create(socketFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.Close()
|
||||
},
|
||||
cleanup: func() error {
|
||||
return os.Remove(socketFile)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad key should fail",
|
||||
config: ServerOptions{
|
||||
Network: "tcp",
|
||||
Addr: ":45987",
|
||||
Keys: []ssh.PublicKey{sshBadPubKey},
|
||||
},
|
||||
wantErr: true,
|
||||
errContains: "ssh: handshake failed",
|
||||
},
|
||||
{
|
||||
name: "good key still good",
|
||||
config: ServerOptions{
|
||||
Network: "tcp",
|
||||
Addr: ":45987",
|
||||
Keys: []ssh.PublicKey{sshPubKey},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.setup != nil {
|
||||
err := tt.setup()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
if tt.cleanup != nil {
|
||||
defer tt.cleanup()
|
||||
}
|
||||
|
||||
agent := NewAgent()
|
||||
|
||||
// Start server in a goroutine since it blocks
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
errChan <- agent.StartServer(tt.config)
|
||||
}()
|
||||
|
||||
// Add a short delay to allow the server to start
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Try to connect to verify server is running
|
||||
var client *ssh.Client
|
||||
var err error
|
||||
|
||||
// Choose the appropriate signer based on the test case
|
||||
testSigner := signer
|
||||
if tt.name == "bad key should fail" {
|
||||
testSigner = badSigner
|
||||
}
|
||||
|
||||
sshClientConfig := &ssh.ClientConfig{
|
||||
User: "a",
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.PublicKeys(testSigner),
|
||||
},
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
Timeout: 4 * time.Second,
|
||||
}
|
||||
|
||||
switch tt.config.Network {
|
||||
case "unix":
|
||||
client, err = ssh.Dial("unix", tt.config.Addr, sshClientConfig)
|
||||
default:
|
||||
if !strings.Contains(tt.config.Addr, ":") {
|
||||
tt.config.Addr = ":" + tt.config.Addr
|
||||
}
|
||||
client, err = ssh.Dial("tcp", tt.config.Addr, sshClientConfig)
|
||||
}
|
||||
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
if tt.errContains != "" {
|
||||
assert.Contains(t, err.Error(), tt.errContains)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, client)
|
||||
client.Close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//////////////////// ParseKeys Tests ////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// Helper function to generate a temporary file with content
|
||||
func createTempFile(content string) (string, error) {
|
||||
tmpFile, err := os.CreateTemp("", "ssh_keys_*.txt")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temp file: %w", err)
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
|
||||
if _, err := tmpFile.WriteString(content); err != nil {
|
||||
return "", fmt.Errorf("failed to write to temp file: %w", err)
|
||||
}
|
||||
|
||||
return tmpFile.Name(), nil
|
||||
}
|
||||
|
||||
// Test case 1: String with a single SSH key
|
||||
func TestParseSingleKeyFromString(t *testing.T) {
|
||||
input := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo"
|
||||
keys, err := ParseKeys(input)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 1 {
|
||||
t.Fatalf("Expected 1 key, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Expected key type 'ssh-ed25519', got '%s'", keys[0].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 2: String with multiple SSH keys
|
||||
func TestParseMultipleKeysFromString(t *testing.T) {
|
||||
input := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D \n #comment\n ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D"
|
||||
keys, err := ParseKeys(input)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 3 {
|
||||
t.Fatalf("Expected 3 keys, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" || keys[1].Type() != "ssh-ed25519" || keys[2].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Unexpected key types: %s, %s, %s", keys[0].Type(), keys[1].Type(), keys[2].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 3: File with a single SSH key
|
||||
func TestParseSingleKeyFromFile(t *testing.T) {
|
||||
content := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo"
|
||||
filePath, err := createTempFile(content)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file: %v", err)
|
||||
}
|
||||
defer os.Remove(filePath) // Clean up the file after the test
|
||||
|
||||
// Read the file content
|
||||
fileContent, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read temp file: %v", err)
|
||||
}
|
||||
|
||||
// Parse the keys
|
||||
keys, err := ParseKeys(string(fileContent))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 1 {
|
||||
t.Fatalf("Expected 1 key, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Expected key type 'ssh-ed25519', got '%s'", keys[0].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 4: File with multiple SSH keys
|
||||
func TestParseMultipleKeysFromFile(t *testing.T) {
|
||||
content := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKCBM91kukN7hbvFKtbpEeo2JXjCcNxXcdBH7V7ADMBo\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D \n #comment\n ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDMtAOQfxDlCxe+A5lVbUY/DHxK1LAF2Z3AV0FYv36D"
|
||||
filePath, err := createTempFile(content)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file: %v", err)
|
||||
}
|
||||
// defer os.Remove(filePath) // Clean up the file after the test
|
||||
|
||||
// Read the file content
|
||||
fileContent, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read temp file: %v", err)
|
||||
}
|
||||
|
||||
// Parse the keys
|
||||
keys, err := ParseKeys(string(fileContent))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
if len(keys) != 3 {
|
||||
t.Fatalf("Expected 3 keys, got %d keys", len(keys))
|
||||
}
|
||||
if keys[0].Type() != "ssh-ed25519" || keys[1].Type() != "ssh-ed25519" || keys[2].Type() != "ssh-ed25519" {
|
||||
t.Fatalf("Unexpected key types: %s, %s, %s", keys[0].Type(), keys[1].Type(), keys[2].Type())
|
||||
}
|
||||
}
|
||||
|
||||
// Test case 5: Invalid SSH key input
|
||||
func TestParseInvalidKey(t *testing.T) {
|
||||
input := "invalid-key-data"
|
||||
_, err := ParseKeys(input)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error for invalid key, got nil")
|
||||
}
|
||||
expectedErrMsg := "failed to parse key"
|
||||
if !strings.Contains(err.Error(), expectedErrMsg) {
|
||||
t.Fatalf("Expected error message to contain '%s', got: %v", expectedErrMsg, err)
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"beszel"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/rhysd/go-github-selfupdate/selfupdate"
|
||||
)
|
||||
|
||||
// Update updates beszel-agent to the latest version
|
||||
func Update() {
|
||||
var latest *selfupdate.Release
|
||||
var found bool
|
||||
var err error
|
||||
currentVersion := semver.MustParse(beszel.Version)
|
||||
fmt.Println("beszel-agent", currentVersion)
|
||||
fmt.Println("Checking for updates...")
|
||||
updater, _ := selfupdate.NewUpdater(selfupdate.Config{
|
||||
Filters: []string{"beszel-agent"},
|
||||
})
|
||||
latest, found, err = updater.DetectLatest("henrygd/beszel")
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error checking for updates:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Println("No updates found")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
fmt.Println("Latest version:", latest.Version)
|
||||
|
||||
if latest.Version.LTE(currentVersion) {
|
||||
fmt.Println("You are up to date")
|
||||
return
|
||||
}
|
||||
|
||||
var binaryPath string
|
||||
fmt.Printf("Updating from %s to %s...\n", currentVersion, latest.Version)
|
||||
binaryPath, err = os.Executable()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting binary path:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = selfupdate.UpdateTo(latest.AssetURL, binaryPath)
|
||||
if err != nil {
|
||||
fmt.Println("Please try rerunning with sudo. Error:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Successfully updated to %s\n\n%s\n", latest.Version, strings.TrimSpace(latest.ReleaseNotes))
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package container
|
||||
|
||||
import "time"
|
||||
|
||||
// Docker container info from /containers/json
|
||||
type ApiInfo struct {
|
||||
Id string
|
||||
IdShort string
|
||||
Names []string
|
||||
Status string
|
||||
// Image string
|
||||
// ImageID string
|
||||
// Command string
|
||||
// Created int64
|
||||
// Ports []Port
|
||||
// SizeRw int64 `json:",omitempty"`
|
||||
// SizeRootFs int64 `json:",omitempty"`
|
||||
// Labels map[string]string
|
||||
// State string
|
||||
// HostConfig struct {
|
||||
// NetworkMode string `json:",omitempty"`
|
||||
// Annotations map[string]string `json:",omitempty"`
|
||||
// }
|
||||
// NetworkSettings *SummaryNetworkSettings
|
||||
// Mounts []MountPoint
|
||||
}
|
||||
|
||||
// Docker container resources from /containers/{id}/stats
|
||||
type ApiStats struct {
|
||||
// Common stats
|
||||
// Read time.Time `json:"read"`
|
||||
// PreRead time.Time `json:"preread"`
|
||||
|
||||
// Linux specific stats, not populated on Windows.
|
||||
// PidsStats PidsStats `json:"pids_stats,omitempty"`
|
||||
// BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
|
||||
|
||||
// Windows specific stats, not populated on Linux.
|
||||
// NumProcs uint32 `json:"num_procs"`
|
||||
// StorageStats StorageStats `json:"storage_stats,omitempty"`
|
||||
// Networks request version >=1.21
|
||||
Networks map[string]NetworkStats
|
||||
|
||||
// Shared stats
|
||||
CPUStats CPUStats `json:"cpu_stats,omitempty"`
|
||||
// PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous"
|
||||
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
|
||||
}
|
||||
|
||||
type CPUStats struct {
|
||||
// CPU Usage. Linux and Windows.
|
||||
CPUUsage CPUUsage `json:"cpu_usage"`
|
||||
|
||||
// System Usage. Linux only.
|
||||
SystemUsage uint64 `json:"system_cpu_usage,omitempty"`
|
||||
|
||||
// Online CPUs. Linux only.
|
||||
// OnlineCPUs uint32 `json:"online_cpus,omitempty"`
|
||||
|
||||
// Throttling Data. Linux only.
|
||||
// ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
|
||||
}
|
||||
|
||||
type CPUUsage struct {
|
||||
// Total CPU time consumed.
|
||||
// Units: nanoseconds (Linux)
|
||||
// Units: 100's of nanoseconds (Windows)
|
||||
TotalUsage uint64 `json:"total_usage"`
|
||||
|
||||
// Total CPU time consumed per core (Linux). Not used on Windows.
|
||||
// Units: nanoseconds.
|
||||
// PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
|
||||
|
||||
// Time spent by tasks of the cgroup in kernel mode (Linux).
|
||||
// Time spent by all container processes in kernel mode (Windows).
|
||||
// Units: nanoseconds (Linux).
|
||||
// Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers.
|
||||
// UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
|
||||
|
||||
// Time spent by tasks of the cgroup in user mode (Linux).
|
||||
// Time spent by all container processes in user mode (Windows).
|
||||
// Units: nanoseconds (Linux).
|
||||
// Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers
|
||||
// UsageInUsermode uint64 `json:"usage_in_usermode"`
|
||||
}
|
||||
|
||||
type MemoryStats struct {
|
||||
// current res_counter usage for memory
|
||||
Usage uint64 `json:"usage,omitempty"`
|
||||
// all the stats exported via memory.stat.
|
||||
Stats MemoryStatsStats `json:"stats,omitempty"`
|
||||
// maximum usage ever recorded.
|
||||
// MaxUsage uint64 `json:"max_usage,omitempty"`
|
||||
// TODO(vishh): Export these as stronger types.
|
||||
// number of times memory usage hits limits.
|
||||
// Failcnt uint64 `json:"failcnt,omitempty"`
|
||||
// Limit uint64 `json:"limit,omitempty"`
|
||||
|
||||
// // committed bytes
|
||||
// Commit uint64 `json:"commitbytes,omitempty"`
|
||||
// // peak committed bytes
|
||||
// CommitPeak uint64 `json:"commitpeakbytes,omitempty"`
|
||||
// // private working set
|
||||
// PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"`
|
||||
}
|
||||
|
||||
type MemoryStatsStats struct {
|
||||
Cache uint64 `json:"cache,omitempty"`
|
||||
InactiveFile uint64 `json:"inactive_file,omitempty"`
|
||||
}
|
||||
|
||||
type NetworkStats struct {
|
||||
// Bytes received. Windows and Linux.
|
||||
RxBytes uint64 `json:"rx_bytes"`
|
||||
// Bytes sent. Windows and Linux.
|
||||
TxBytes uint64 `json:"tx_bytes"`
|
||||
}
|
||||
|
||||
type prevNetStats struct {
|
||||
Sent uint64
|
||||
Recv uint64
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
// Docker container stats
|
||||
type Stats struct {
|
||||
Name string `json:"n"`
|
||||
Cpu float64 `json:"c"`
|
||||
Mem float64 `json:"m"`
|
||||
NetworkSent float64 `json:"ns"`
|
||||
NetworkRecv float64 `json:"nr"`
|
||||
PrevCpu [2]uint64 `json:"-"`
|
||||
PrevNet prevNetStats `json:"-"`
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package system
|
||||
|
||||
// TODO: this is confusing, make common package with common/types common/helpers etc
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/container"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Stats struct {
|
||||
Cpu float64 `json:"cpu"`
|
||||
MaxCpu float64 `json:"cpum,omitempty"`
|
||||
Mem float64 `json:"m"`
|
||||
MemUsed float64 `json:"mu"`
|
||||
MemPct float64 `json:"mp"`
|
||||
MemBuffCache float64 `json:"mb"`
|
||||
MemZfsArc float64 `json:"mz,omitempty"` // ZFS ARC memory
|
||||
Swap float64 `json:"s,omitempty"`
|
||||
SwapUsed float64 `json:"su,omitempty"`
|
||||
DiskTotal float64 `json:"d"`
|
||||
DiskUsed float64 `json:"du"`
|
||||
DiskPct float64 `json:"dp"`
|
||||
DiskReadPs float64 `json:"dr"`
|
||||
DiskWritePs float64 `json:"dw"`
|
||||
MaxDiskReadPs float64 `json:"drm,omitempty"`
|
||||
MaxDiskWritePs float64 `json:"dwm,omitempty"`
|
||||
NetworkSent float64 `json:"ns"`
|
||||
NetworkRecv float64 `json:"nr"`
|
||||
MaxNetworkSent float64 `json:"nsm,omitempty"`
|
||||
MaxNetworkRecv float64 `json:"nrm,omitempty"`
|
||||
Temperatures map[string]float64 `json:"t,omitempty"`
|
||||
ExtraFs map[string]*FsStats `json:"efs,omitempty"`
|
||||
GPUData map[string]GPUData `json:"g,omitempty"`
|
||||
}
|
||||
|
||||
type GPUData struct {
|
||||
Name string `json:"n"`
|
||||
Temperature float64 `json:"-"`
|
||||
MemoryUsed float64 `json:"mu,omitempty"`
|
||||
MemoryTotal float64 `json:"mt,omitempty"`
|
||||
Usage float64 `json:"u"`
|
||||
Power float64 `json:"p,omitempty"`
|
||||
Count float64 `json:"-"`
|
||||
}
|
||||
|
||||
type FsStats struct {
|
||||
Time time.Time `json:"-"`
|
||||
Root bool `json:"-"`
|
||||
Mountpoint string `json:"-"`
|
||||
DiskTotal float64 `json:"d"`
|
||||
DiskUsed float64 `json:"du"`
|
||||
TotalRead uint64 `json:"-"`
|
||||
TotalWrite uint64 `json:"-"`
|
||||
DiskReadPs float64 `json:"r"`
|
||||
DiskWritePs float64 `json:"w"`
|
||||
MaxDiskReadPS float64 `json:"rm,omitempty"`
|
||||
MaxDiskWritePS float64 `json:"wm,omitempty"`
|
||||
}
|
||||
|
||||
type NetIoStats struct {
|
||||
BytesRecv uint64
|
||||
BytesSent uint64
|
||||
Time time.Time
|
||||
Name string
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Hostname string `json:"h"`
|
||||
KernelVersion string `json:"k,omitempty"`
|
||||
Cores int `json:"c"`
|
||||
Threads int `json:"t,omitempty"`
|
||||
CpuModel string `json:"m"`
|
||||
Uptime uint64 `json:"u"`
|
||||
Cpu float64 `json:"cpu"`
|
||||
MemPct float64 `json:"mp"`
|
||||
DiskPct float64 `json:"dp"`
|
||||
Bandwidth float64 `json:"b"`
|
||||
AgentVersion string `json:"v"`
|
||||
Podman bool `json:"p,omitempty"`
|
||||
GpuPct float64 `json:"g,omitempty"`
|
||||
DashboardTemp float64 `json:"dt,omitempty"`
|
||||
}
|
||||
|
||||
// Final data structure to return to the hub
|
||||
type CombinedData struct {
|
||||
Stats Stats `json:"stats"`
|
||||
Info Info `json:"info"`
|
||||
Containers []*container.Stats `json:"container"`
|
||||
}
|
||||
@@ -1,435 +0,0 @@
|
||||
package systems
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/system"
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/store"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const (
|
||||
up string = "up"
|
||||
down string = "down"
|
||||
paused string = "paused"
|
||||
pending string = "pending"
|
||||
|
||||
interval int = 60_000
|
||||
|
||||
sessionTimeout = 4 * time.Second
|
||||
)
|
||||
|
||||
type SystemManager struct {
|
||||
hub hubLike
|
||||
systems *store.Store[string, *System]
|
||||
sshConfig *ssh.ClientConfig
|
||||
}
|
||||
|
||||
type System struct {
|
||||
Id string `db:"id"`
|
||||
Host string `db:"host"`
|
||||
Port string `db:"port"`
|
||||
Status string `db:"status"`
|
||||
manager *SystemManager
|
||||
client *ssh.Client
|
||||
data *system.CombinedData
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
type hubLike interface {
|
||||
core.App
|
||||
GetSSHKey() ([]byte, error)
|
||||
HandleSystemAlerts(systemRecord *core.Record, data *system.CombinedData) error
|
||||
HandleStatusAlerts(status string, systemRecord *core.Record) error
|
||||
}
|
||||
|
||||
func NewSystemManager(hub hubLike) *SystemManager {
|
||||
return &SystemManager{
|
||||
systems: store.New(map[string]*System{}),
|
||||
hub: hub,
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize initializes the system manager.
|
||||
// It binds the event hooks and starts updating existing systems.
|
||||
func (sm *SystemManager) Initialize() error {
|
||||
sm.bindEventHooks()
|
||||
// ssh setup
|
||||
key, err := sm.hub.GetSSHKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sm.createSSHClientConfig(key); err != nil {
|
||||
return err
|
||||
}
|
||||
// start updating existing systems
|
||||
var systems []*System
|
||||
err = sm.hub.DB().NewQuery("SELECT id, host, port, status FROM systems WHERE status != 'paused'").All(&systems)
|
||||
if err != nil || len(systems) == 0 {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
// time between initial system updates
|
||||
delta := interval / max(1, len(systems))
|
||||
delta = min(delta, 2_000)
|
||||
sleepTime := time.Duration(delta) * time.Millisecond
|
||||
for _, system := range systems {
|
||||
time.Sleep(sleepTime)
|
||||
_ = sm.AddSystem(system)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sm *SystemManager) bindEventHooks() {
|
||||
sm.hub.OnRecordCreate("systems").BindFunc(sm.onRecordCreate)
|
||||
sm.hub.OnRecordAfterCreateSuccess("systems").BindFunc(sm.onRecordAfterCreateSuccess)
|
||||
sm.hub.OnRecordUpdate("systems").BindFunc(sm.onRecordUpdate)
|
||||
sm.hub.OnRecordAfterUpdateSuccess("systems").BindFunc(sm.onRecordAfterUpdateSuccess)
|
||||
sm.hub.OnRecordAfterDeleteSuccess("systems").BindFunc(sm.onRecordAfterDeleteSuccess)
|
||||
}
|
||||
|
||||
// Runs before the record is committed to the database
|
||||
func (sm *SystemManager) onRecordCreate(e *core.RecordEvent) error {
|
||||
e.Record.Set("info", system.Info{})
|
||||
e.Record.Set("status", pending)
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
// Runs after the record is committed to the database
|
||||
func (sm *SystemManager) onRecordAfterCreateSuccess(e *core.RecordEvent) error {
|
||||
if err := sm.AddRecord(e.Record); err != nil {
|
||||
e.App.Logger().Error("Error adding record", "err", err)
|
||||
}
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
// Runs before the record is updated
|
||||
func (sm *SystemManager) onRecordUpdate(e *core.RecordEvent) error {
|
||||
if e.Record.GetString("status") == paused {
|
||||
e.Record.Set("info", system.Info{})
|
||||
}
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
// Runs after the record is updated
|
||||
func (sm *SystemManager) onRecordAfterUpdateSuccess(e *core.RecordEvent) error {
|
||||
newStatus := e.Record.GetString("status")
|
||||
switch newStatus {
|
||||
case paused:
|
||||
sm.RemoveSystem(e.Record.Id)
|
||||
return e.Next()
|
||||
case pending:
|
||||
if err := sm.AddRecord(e.Record); err != nil {
|
||||
e.App.Logger().Error("Error adding record", "err", err)
|
||||
}
|
||||
return e.Next()
|
||||
}
|
||||
system, ok := sm.systems.GetOk(e.Record.Id)
|
||||
if !ok {
|
||||
return sm.AddRecord(e.Record)
|
||||
}
|
||||
prevStatus := system.Status
|
||||
system.Status = newStatus
|
||||
// system alerts if system is up
|
||||
if system.Status == up {
|
||||
if err := sm.hub.HandleSystemAlerts(e.Record, system.data); err != nil {
|
||||
e.App.Logger().Error("Error handling system alerts", "err", err)
|
||||
}
|
||||
}
|
||||
if (system.Status == down && prevStatus == up) || (system.Status == up && prevStatus == down) {
|
||||
if err := sm.hub.HandleStatusAlerts(system.Status, e.Record); err != nil {
|
||||
e.App.Logger().Error("Error handling status alerts", "err", err)
|
||||
}
|
||||
}
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
// Runs after the record is deleted
|
||||
func (sm *SystemManager) onRecordAfterDeleteSuccess(e *core.RecordEvent) error {
|
||||
sm.RemoveSystem(e.Record.Id)
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
// AddSystem adds a system to the manager
|
||||
func (sm *SystemManager) AddSystem(sys *System) error {
|
||||
if sm.systems.Has(sys.Id) {
|
||||
return fmt.Errorf("system exists")
|
||||
}
|
||||
if sys.Id == "" || sys.Host == "" {
|
||||
return fmt.Errorf("system is missing required fields")
|
||||
}
|
||||
sys.manager = sm
|
||||
sys.ctx, sys.cancel = context.WithCancel(context.Background())
|
||||
sys.data = &system.CombinedData{}
|
||||
sm.systems.Set(sys.Id, sys)
|
||||
go sys.StartUpdater()
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveSystem removes a system from the manager
|
||||
func (sm *SystemManager) RemoveSystem(systemID string) error {
|
||||
system, ok := sm.systems.GetOk(systemID)
|
||||
if !ok {
|
||||
return fmt.Errorf("system not found")
|
||||
}
|
||||
// cancel the context to signal stop
|
||||
if system.cancel != nil {
|
||||
system.cancel()
|
||||
}
|
||||
system.resetSSHClient()
|
||||
sm.systems.Remove(systemID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRecord adds a record to the system manager.
|
||||
// It first removes any existing system with the same ID, then creates a new System
|
||||
// instance from the record data and adds it to the manager.
|
||||
// This function is typically called when a new system is created or when an existing
|
||||
// system's status changes to pending.
|
||||
func (sm *SystemManager) AddRecord(record *core.Record) (err error) {
|
||||
_ = sm.RemoveSystem(record.Id)
|
||||
system := &System{
|
||||
Id: record.Id,
|
||||
Status: record.GetString("status"),
|
||||
Host: record.GetString("host"),
|
||||
Port: record.GetString("port"),
|
||||
}
|
||||
return sm.AddSystem(system)
|
||||
}
|
||||
|
||||
// StartUpdater starts the system updater.
|
||||
// It first fetches the data from the agent then updates the records.
|
||||
// If the data is not found or the system is down, it sets the system down.
|
||||
func (sys *System) StartUpdater() {
|
||||
if sys.data == nil {
|
||||
sys.data = &system.CombinedData{}
|
||||
}
|
||||
if err := sys.update(); err != nil {
|
||||
_ = sys.setDown(err)
|
||||
}
|
||||
|
||||
c := time.Tick(time.Duration(interval) * time.Millisecond)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-sys.ctx.Done():
|
||||
return
|
||||
case <-c:
|
||||
err := sys.update()
|
||||
if err != nil {
|
||||
_ = sys.setDown(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update updates the system data and records.
|
||||
// It first fetches the data from the agent then updates the records.
|
||||
func (sys *System) update() error {
|
||||
_, err := sys.fetchDataFromAgent()
|
||||
if err == nil {
|
||||
_, err = sys.createRecords()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// createRecords updates the system record and adds system_stats and container_stats records
|
||||
func (sys *System) createRecords() (*core.Record, error) {
|
||||
systemRecord, err := sys.getRecord()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hub := sys.manager.hub
|
||||
// add system_stats and container_stats records
|
||||
systemStats, err := hub.FindCachedCollectionByNameOrId("system_stats")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
systemStatsRecord := core.NewRecord(systemStats)
|
||||
systemStatsRecord.Set("system", systemRecord.Id)
|
||||
systemStatsRecord.Set("stats", sys.data.Stats)
|
||||
systemStatsRecord.Set("type", "1m")
|
||||
if err := hub.SaveNoValidate(systemStatsRecord); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// add new container_stats record
|
||||
if len(sys.data.Containers) > 0 {
|
||||
containerStats, err := hub.FindCachedCollectionByNameOrId("container_stats")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containerStatsRecord := core.NewRecord(containerStats)
|
||||
containerStatsRecord.Set("system", systemRecord.Id)
|
||||
containerStatsRecord.Set("stats", sys.data.Containers)
|
||||
containerStatsRecord.Set("type", "1m")
|
||||
if err := hub.SaveNoValidate(containerStatsRecord); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// update system record (do this last because it triggers alerts and we need above records to be inserted first)
|
||||
systemRecord.Set("status", up)
|
||||
systemRecord.Set("info", sys.data.Info)
|
||||
if err := hub.SaveNoValidate(systemRecord); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return systemRecord, nil
|
||||
}
|
||||
|
||||
// getRecord retrieves the system record from the database.
|
||||
// If the record is not found or the system is paused, it removes the system from the manager.
|
||||
func (sys *System) getRecord() (*core.Record, error) {
|
||||
record, err := sys.manager.hub.FindRecordById("systems", sys.Id)
|
||||
if err != nil || record == nil {
|
||||
_ = sys.manager.RemoveSystem(sys.Id)
|
||||
return nil, err
|
||||
}
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// setDown marks a system as down in the database.
|
||||
// It takes the original error that caused the system to go down and returns any error
|
||||
// encountered during the process of updating the system status.
|
||||
func (sys *System) setDown(OriginalError error) error {
|
||||
if sys.Status == down {
|
||||
return nil
|
||||
}
|
||||
record, err := sys.getRecord()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sys.manager.hub.Logger().Error("System down", "system", record.GetString("name"), "err", OriginalError)
|
||||
record.Set("status", down)
|
||||
err = sys.manager.hub.SaveNoValidate(record)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fetchDataFromAgent fetches the data from the agent.
|
||||
// It first creates a new SSH client if it doesn't exist or the system is down.
|
||||
// Then it creates a new SSH session and fetches the data from the agent.
|
||||
// If the data is not found or the system is down, it sets the system down.
|
||||
func (sys *System) fetchDataFromAgent() (*system.CombinedData, error) {
|
||||
maxRetries := 1
|
||||
for attempt := 0; attempt <= maxRetries; attempt++ {
|
||||
if sys.client == nil || sys.Status == down {
|
||||
if err := sys.createSSHClient(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
session, err := sys.createSessionWithTimeout(4 * time.Second)
|
||||
if err != nil {
|
||||
if attempt >= maxRetries {
|
||||
return nil, err
|
||||
}
|
||||
sys.manager.hub.Logger().Warn("Session closed. Retrying...", "host", sys.Host, "port", sys.Port, "err", err)
|
||||
sys.resetSSHClient()
|
||||
continue
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
stdout, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := session.Shell(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// this is initialized in startUpdater, should never be nil
|
||||
*sys.data = system.CombinedData{}
|
||||
if err := json.NewDecoder(stdout).Decode(sys.data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// wait for the session to complete
|
||||
if err := session.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sys.data, nil
|
||||
}
|
||||
|
||||
// this should never be reached due to the return in the loop
|
||||
return nil, fmt.Errorf("failed to fetch data")
|
||||
}
|
||||
|
||||
func (sm *SystemManager) createSSHClientConfig(key []byte) error {
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sm.sshConfig = &ssh.ClientConfig{
|
||||
User: "u",
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.PublicKeys(signer),
|
||||
},
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
Timeout: sessionTimeout,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createSSHClient creates a new SSH client for the system
|
||||
func (s *System) createSSHClient() error {
|
||||
network := "tcp"
|
||||
host := s.Host
|
||||
if strings.HasPrefix(host, "/") {
|
||||
network = "unix"
|
||||
} else {
|
||||
host = net.JoinHostPort(host, s.Port)
|
||||
}
|
||||
var err error
|
||||
s.client, err = ssh.Dial(network, host, s.manager.sshConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createSessionWithTimeout creates a new SSH session with a timeout to avoid hanging
|
||||
// in case of network issues
|
||||
func (sys *System) createSessionWithTimeout(timeout time.Duration) (*ssh.Session, error) {
|
||||
if sys.client == nil {
|
||||
return nil, fmt.Errorf("client not initialized")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(sys.ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
sessionChan := make(chan *ssh.Session, 1)
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
if session, err := sys.client.NewSession(); err != nil {
|
||||
errChan <- err
|
||||
} else {
|
||||
sessionChan <- session
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case session := <-sessionChan:
|
||||
return session, nil
|
||||
case err := <-errChan:
|
||||
return nil, err
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("timeout")
|
||||
}
|
||||
}
|
||||
|
||||
// resetSSHClient closes the SSH connection and resets the client to nil
|
||||
func (sys *System) resetSSHClient() {
|
||||
if sys.client != nil {
|
||||
sys.client.Close()
|
||||
}
|
||||
sys.client = nil
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package hub
|
||||
|
||||
import (
|
||||
"beszel"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/rhysd/go-github-selfupdate/selfupdate"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Update updates beszel to the latest version
|
||||
func Update(_ *cobra.Command, _ []string) {
|
||||
var latest *selfupdate.Release
|
||||
var found bool
|
||||
var err error
|
||||
currentVersion := semver.MustParse(beszel.Version)
|
||||
fmt.Println("beszel", currentVersion)
|
||||
fmt.Println("Checking for updates...")
|
||||
updater, _ := selfupdate.NewUpdater(selfupdate.Config{
|
||||
Filters: []string{"beszel_"},
|
||||
})
|
||||
latest, found, err = updater.DetectLatest("henrygd/beszel")
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error checking for updates:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Println("No updates found")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
fmt.Println("Latest version:", latest.Version)
|
||||
|
||||
if latest.Version.LTE(currentVersion) {
|
||||
fmt.Println("You are up to date")
|
||||
return
|
||||
}
|
||||
|
||||
var binaryPath string
|
||||
fmt.Printf("Updating from %s to %s...\n", currentVersion, latest.Version)
|
||||
binaryPath, err = os.Executable()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting binary path:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = selfupdate.UpdateTo(latest.AssetURL, binaryPath)
|
||||
if err != nil {
|
||||
fmt.Println("Please try rerunning with sudo. Error:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Successfully updated to %s\n\n%s\n", latest.Version, strings.TrimSpace(latest.ReleaseNotes))
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Package tests provides helpers for testing the application.
|
||||
package tests
|
||||
|
||||
import (
|
||||
"beszel/internal/hub"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tests"
|
||||
|
||||
_ "github.com/pocketbase/pocketbase/migrations"
|
||||
)
|
||||
|
||||
// TestHub is a wrapper hub instance used for testing.
|
||||
type TestHub struct {
|
||||
core.App
|
||||
*tests.TestApp
|
||||
*hub.Hub
|
||||
}
|
||||
|
||||
// NewTestHub creates and initializes a test application instance.
|
||||
//
|
||||
// It is the caller's responsibility to call app.Cleanup() when the app is no longer needed.
|
||||
func NewTestHub(optTestDataDir ...string) (*TestHub, error) {
|
||||
var testDataDir string
|
||||
if len(optTestDataDir) > 0 {
|
||||
testDataDir = optTestDataDir[0]
|
||||
}
|
||||
|
||||
return NewTestHubWithConfig(core.BaseAppConfig{
|
||||
DataDir: testDataDir,
|
||||
EncryptionEnv: "pb_test_env",
|
||||
})
|
||||
}
|
||||
|
||||
// NewTestHubWithConfig creates and initializes a test application instance
|
||||
// from the provided config.
|
||||
//
|
||||
// If config.DataDir is not set it fallbacks to the default internal test data directory.
|
||||
//
|
||||
// config.DataDir is cloned for each new test application instance.
|
||||
//
|
||||
// It is the caller's responsibility to call app.Cleanup() when the app is no longer needed.
|
||||
func NewTestHubWithConfig(config core.BaseAppConfig) (*TestHub, error) {
|
||||
testApp, err := tests.NewTestAppWithConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hub := hub.NewHub(testApp)
|
||||
|
||||
t := &TestHub{
|
||||
App: testApp,
|
||||
TestApp: testApp,
|
||||
Hub: hub,
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
m "github.com/pocketbase/pocketbase/migrations"
|
||||
)
|
||||
|
||||
var (
|
||||
TempAdminEmail = "_@b.b"
|
||||
)
|
||||
|
||||
func init() {
|
||||
m.Register(func(app core.App) error {
|
||||
// initial settings
|
||||
settings := app.Settings()
|
||||
settings.Meta.AppName = "Beszel"
|
||||
settings.Meta.HideControls = true
|
||||
settings.Logs.MinLevel = 4
|
||||
if err := app.Save(settings); err != nil {
|
||||
return err
|
||||
}
|
||||
// create superuser
|
||||
collection, _ := app.FindCollectionByNameOrId(core.CollectionNameSuperusers)
|
||||
user := core.NewRecord(collection)
|
||||
user.SetEmail(TempAdminEmail)
|
||||
user.SetRandomPassword()
|
||||
return app.Save(user)
|
||||
}, nil)
|
||||
}
|
||||
Binary file not shown.
@@ -1,73 +0,0 @@
|
||||
{
|
||||
"name": "beszel",
|
||||
"private": true,
|
||||
"version": "0.10.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "lingui extract --overwrite && lingui compile && vite build",
|
||||
"preview": "vite preview",
|
||||
"sync": "lingui extract --overwrite && lingui compile",
|
||||
"sync_and_purge": "lingui extract --overwrite --clean && lingui compile"
|
||||
},
|
||||
"dependencies": {
|
||||
"@henrygd/queue": "^1.0.7",
|
||||
"@henrygd/semaphore": "^0.0.2",
|
||||
"@lingui/detect-locale": "^5.2.0",
|
||||
"@lingui/macro": "^5.2.0",
|
||||
"@lingui/react": "^5.2.0",
|
||||
"@nanostores/react": "^0.7.3",
|
||||
"@nanostores/router": "^0.11.0",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||
"@radix-ui/react-checkbox": "^1.1.4",
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-direction": "^1.1.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slider": "^1.2.3",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-switch": "^1.1.3",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-toast": "^1.2.6",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.4",
|
||||
"d3-time": "^3.1.0",
|
||||
"lucide-react": "^0.452.0",
|
||||
"nanostores": "^0.11.4",
|
||||
"pocketbase": "^0.25.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"recharts": "^2.15.1",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"valibot": "^0.42.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lingui/cli": "^5.2.0",
|
||||
"@lingui/swc-plugin": "^5.5.0",
|
||||
"@lingui/vite-plugin": "^5.2.0",
|
||||
"@types/bun": "^1.2.4",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"postcss": "^8.5.3",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tailwindcss-rtl": "^0.9.0",
|
||||
"typescript": "^5.8.2",
|
||||
"vite": "^6.2.0"
|
||||
},
|
||||
"overrides": {
|
||||
"@nanostores/router": {
|
||||
"nanostores": "^0.11.3"
|
||||
}
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/linux-arm64": "^0.21.5"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { memo, useMemo, useState } from "react"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { $alerts } from "@/lib/stores"
|
||||
import {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog"
|
||||
import { BellIcon, GlobeIcon, ServerIcon } from "lucide-react"
|
||||
import { alertInfo, cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { AlertRecord, SystemRecord } from "@/types"
|
||||
import { Link } from "../router"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { Checkbox } from "../ui/checkbox"
|
||||
import { SystemAlert, SystemAlertGlobal } from "./alerts-system"
|
||||
|
||||
export default memo(function AlertsButton({ system }: { system: SystemRecord }) {
|
||||
const alerts = useStore($alerts)
|
||||
const [opened, setOpened] = useState(false)
|
||||
|
||||
const hasAlert = alerts.some((alert) => alert.system === system.id)
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="icon" aria-label={t`Alerts`} data-nolink onClick={() => setOpened(true)}>
|
||||
<BellIcon
|
||||
className={cn("h-[1.2em] w-[1.2em] pointer-events-none", {
|
||||
"fill-primary": hasAlert,
|
||||
})}
|
||||
/>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-h-full overflow-auto max-w-[35rem]">
|
||||
{opened && <AlertDialogContent system={system} />}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
),
|
||||
[opened, hasAlert]
|
||||
)
|
||||
})
|
||||
|
||||
function AlertDialogContent({ system }: { system: SystemRecord }) {
|
||||
const alerts = useStore($alerts)
|
||||
const [overwriteExisting, setOverwriteExisting] = useState<boolean | "indeterminate">(false)
|
||||
|
||||
// alertsSignature changes only when alerts for this system change
|
||||
let alertsSignature = ""
|
||||
const systemAlerts = alerts.filter((alert) => {
|
||||
if (alert.system === system.id) {
|
||||
alertsSignature += alert.name + alert.min + alert.value
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}) as AlertRecord[]
|
||||
|
||||
return useMemo(() => {
|
||||
// console.log("render modal", system.name, alertsSignature)
|
||||
const data = Object.keys(alertInfo).map((name) => {
|
||||
const alert = alertInfo[name as keyof typeof alertInfo]
|
||||
return {
|
||||
name: name as keyof typeof alertInfo,
|
||||
alert,
|
||||
system,
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-xl">
|
||||
<Trans>Alerts</Trans>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Trans>
|
||||
See{" "}
|
||||
<Link href="/settings/notifications" className="link">
|
||||
notification settings
|
||||
</Link>{" "}
|
||||
to configure how you receive alerts.
|
||||
</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Tabs defaultValue="system">
|
||||
<TabsList className="mb-1 -mt-0.5">
|
||||
<TabsTrigger value="system">
|
||||
<ServerIcon className="me-2 h-3.5 w-3.5" />
|
||||
{system.name}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="global">
|
||||
<GlobeIcon className="me-1.5 h-3.5 w-3.5" />
|
||||
<Trans>All Systems</Trans>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="system">
|
||||
<div className="grid gap-3">
|
||||
{data.map((d) => (
|
||||
<SystemAlert key={d.name} system={system} data={d} systemAlerts={systemAlerts} />
|
||||
))}
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="global">
|
||||
<label
|
||||
htmlFor="ovw"
|
||||
className="mb-3 flex gap-2 items-center justify-center cursor-pointer border rounded-sm py-3 px-4 border-destructive text-destructive font-semibold text-sm"
|
||||
>
|
||||
<Checkbox
|
||||
id="ovw"
|
||||
className="text-destructive border-destructive data-[state=checked]:bg-destructive"
|
||||
checked={overwriteExisting}
|
||||
onCheckedChange={setOverwriteExisting}
|
||||
/>
|
||||
<Trans>Overwrite existing alerts</Trans>
|
||||
</label>
|
||||
<div className="grid gap-3">
|
||||
{data.map((d) => (
|
||||
<SystemAlertGlobal key={d.name} data={d} overwrite={overwriteExisting} />
|
||||
))}
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</>
|
||||
)
|
||||
}, [alertsSignature, overwriteExisting])
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans, Plural } from "@lingui/react/macro"
|
||||
import { $alerts, $systems, pb } from "@/lib/stores"
|
||||
import { alertInfo, cn } from "@/lib/utils"
|
||||
import { Switch } from "@/components/ui/switch"
|
||||
import { AlertInfo, AlertRecord, SystemRecord } from "@/types"
|
||||
import { lazy, Suspense, useMemo, useState } from "react"
|
||||
import { toast } from "../ui/use-toast"
|
||||
import { BatchService } from "pocketbase"
|
||||
import { getSemaphore } from "@henrygd/semaphore"
|
||||
|
||||
interface AlertData {
|
||||
checked?: boolean
|
||||
val?: number
|
||||
min?: number
|
||||
updateAlert?: (checked: boolean, value: number, min: number) => void
|
||||
name: keyof typeof alertInfo
|
||||
alert: AlertInfo
|
||||
system: SystemRecord
|
||||
}
|
||||
|
||||
const Slider = lazy(() => import("@/components/ui/slider"))
|
||||
|
||||
const failedUpdateToast = () =>
|
||||
toast({
|
||||
title: t`Failed to update alert`,
|
||||
description: t`Please check logs for more details.`,
|
||||
variant: "destructive",
|
||||
})
|
||||
|
||||
export function SystemAlert({
|
||||
system,
|
||||
systemAlerts,
|
||||
data,
|
||||
}: {
|
||||
system: SystemRecord
|
||||
systemAlerts: AlertRecord[]
|
||||
data: AlertData
|
||||
}) {
|
||||
const alert = systemAlerts.find((alert) => alert.name === data.name)
|
||||
|
||||
data.updateAlert = async (checked: boolean, value: number, min: number) => {
|
||||
try {
|
||||
if (alert && !checked) {
|
||||
await pb.collection("alerts").delete(alert.id)
|
||||
} else if (alert && checked) {
|
||||
await pb.collection("alerts").update(alert.id, { value, min, triggered: false })
|
||||
} else if (checked) {
|
||||
pb.collection("alerts").create({
|
||||
system: system.id,
|
||||
user: pb.authStore.record!.id,
|
||||
name: data.name,
|
||||
value: value,
|
||||
min: min,
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
failedUpdateToast()
|
||||
}
|
||||
}
|
||||
|
||||
if (alert) {
|
||||
data.checked = true
|
||||
data.val = alert.value
|
||||
data.min = alert.min || 1
|
||||
}
|
||||
|
||||
return <AlertContent data={data} />
|
||||
}
|
||||
|
||||
export const SystemAlertGlobal = ({ data, overwrite }: { data: AlertData; overwrite: boolean | "indeterminate" }) => {
|
||||
data.checked = false
|
||||
data.val = data.min = 0
|
||||
|
||||
// set of system ids that have an alert for this name when the component is mounted
|
||||
const existingAlertsSystems = useMemo(() => {
|
||||
const map = new Set<string>()
|
||||
const alerts = $alerts.get()
|
||||
for (const alert of alerts) {
|
||||
if (alert.name === data.name) {
|
||||
map.add(alert.system)
|
||||
}
|
||||
}
|
||||
return map
|
||||
}, [])
|
||||
|
||||
data.updateAlert = async (checked: boolean, value: number, min: number) => {
|
||||
const sem = getSemaphore("alerts")
|
||||
await sem.acquire()
|
||||
try {
|
||||
// if another update is waiting behind, don't start this one
|
||||
if (sem.size() > 1) {
|
||||
return
|
||||
}
|
||||
|
||||
const recordData: Partial<AlertRecord> = {
|
||||
value,
|
||||
min,
|
||||
triggered: false,
|
||||
}
|
||||
|
||||
const batch = batchWrapper("alerts", 25)
|
||||
const systems = $systems.get()
|
||||
const currentAlerts = $alerts.get()
|
||||
|
||||
// map of current alerts with this name right now by system id
|
||||
const currentAlertsSystems = new Map<string, AlertRecord>()
|
||||
for (const alert of currentAlerts) {
|
||||
if (alert.name === data.name) {
|
||||
currentAlertsSystems.set(alert.system, alert)
|
||||
}
|
||||
}
|
||||
|
||||
if (overwrite) {
|
||||
existingAlertsSystems.clear()
|
||||
}
|
||||
|
||||
const processSystem = async (system: SystemRecord): Promise<void> => {
|
||||
const existingAlert = existingAlertsSystems.has(system.id)
|
||||
|
||||
if (!overwrite && existingAlert) {
|
||||
return
|
||||
}
|
||||
|
||||
const currentAlert = currentAlertsSystems.get(system.id)
|
||||
|
||||
// delete existing alert if unchecked
|
||||
if (!checked && currentAlert) {
|
||||
return batch.remove(currentAlert.id)
|
||||
}
|
||||
if (checked && currentAlert) {
|
||||
// update existing alert if checked
|
||||
return batch.update(currentAlert.id, recordData)
|
||||
}
|
||||
if (checked) {
|
||||
// create new alert if checked and not existing
|
||||
return batch.create({
|
||||
system: system.id,
|
||||
user: pb.authStore.record!.id,
|
||||
name: data.name,
|
||||
...recordData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// make sure current system is updated in the first batch
|
||||
await processSystem(data.system)
|
||||
for (const system of systems) {
|
||||
if (system.id === data.system.id) {
|
||||
continue
|
||||
}
|
||||
if (sem.size() > 1) {
|
||||
return
|
||||
}
|
||||
await processSystem(system)
|
||||
}
|
||||
await batch.send()
|
||||
} finally {
|
||||
sem.release()
|
||||
}
|
||||
}
|
||||
|
||||
return <AlertContent data={data} />
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapper for performing batch operations on a specified collection.
|
||||
*/
|
||||
function batchWrapper(collection: string, batchSize: number) {
|
||||
let batch: BatchService | undefined
|
||||
let count = 0
|
||||
|
||||
const create = async <T extends Record<string, any>>(options: T) => {
|
||||
batch ||= pb.createBatch()
|
||||
batch.collection(collection).create(options)
|
||||
if (++count >= batchSize) {
|
||||
await send()
|
||||
}
|
||||
}
|
||||
|
||||
const update = async <T extends Record<string, any>>(id: string, data: T) => {
|
||||
batch ||= pb.createBatch()
|
||||
batch.collection(collection).update(id, data)
|
||||
if (++count >= batchSize) {
|
||||
await send()
|
||||
}
|
||||
}
|
||||
|
||||
const remove = async (id: string) => {
|
||||
batch ||= pb.createBatch()
|
||||
batch.collection(collection).delete(id)
|
||||
if (++count >= batchSize) {
|
||||
await send()
|
||||
}
|
||||
}
|
||||
|
||||
const send = async () => {
|
||||
if (count) {
|
||||
await batch?.send({ requestKey: null })
|
||||
batch = undefined
|
||||
count = 0
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
update,
|
||||
remove,
|
||||
send,
|
||||
create,
|
||||
}
|
||||
}
|
||||
|
||||
function AlertContent({ data }: { data: AlertData }) {
|
||||
const { name } = data
|
||||
|
||||
const singleDescription = data.alert.singleDesc?.()
|
||||
|
||||
const [checked, setChecked] = useState(data.checked || false)
|
||||
const [min, setMin] = useState(data.min || 10)
|
||||
const [value, setValue] = useState(data.val || (singleDescription ? 0 : 80))
|
||||
|
||||
const Icon = alertInfo[name].icon
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-muted-foreground/15 hover:border-muted-foreground/20 transition-colors duration-100 group">
|
||||
<label
|
||||
htmlFor={`s${name}`}
|
||||
className={cn("flex flex-row items-center justify-between gap-4 cursor-pointer p-4", {
|
||||
"pb-0": checked,
|
||||
})}
|
||||
>
|
||||
<div className="grid gap-1 select-none">
|
||||
<p className="font-semibold flex gap-3 items-center">
|
||||
<Icon className="h-4 w-4 opacity-85" /> {data.alert.name()}
|
||||
</p>
|
||||
{!checked && <span className="block text-sm text-muted-foreground">{data.alert.desc()}</span>}
|
||||
</div>
|
||||
<Switch
|
||||
id={`s${name}`}
|
||||
checked={checked}
|
||||
onCheckedChange={(newChecked) => {
|
||||
setChecked(newChecked)
|
||||
data.updateAlert?.(newChecked, value, min)
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
{checked && (
|
||||
<div className="grid sm:grid-cols-2 mt-1.5 gap-5 px-4 pb-5 tabular-nums text-muted-foreground">
|
||||
<Suspense fallback={<div className="h-10" />}>
|
||||
{!singleDescription && (
|
||||
<div>
|
||||
<p id={`v${name}`} className="text-sm block h-8">
|
||||
<Trans>
|
||||
Average exceeds{" "}
|
||||
<strong className="text-foreground">
|
||||
{value}
|
||||
{data.alert.unit}
|
||||
</strong>
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex gap-3">
|
||||
<Slider
|
||||
aria-labelledby={`v${name}`}
|
||||
defaultValue={[value]}
|
||||
onValueCommit={(val) => {
|
||||
data.updateAlert?.(true, val[0], min)
|
||||
}}
|
||||
onValueChange={(val) => {
|
||||
setValue(val[0])
|
||||
}}
|
||||
min={1}
|
||||
max={alertInfo[name].max ?? 99}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={cn(singleDescription && "col-span-full lowercase")}>
|
||||
<p id={`t${name}`} className="text-sm block h-8 first-letter:uppercase">
|
||||
{singleDescription && (
|
||||
<>
|
||||
{singleDescription}
|
||||
{` `}
|
||||
</>
|
||||
)}
|
||||
<Trans>
|
||||
For <strong className="text-foreground">{min}</strong>{" "}
|
||||
<Plural value={min} one="minute" other="minutes" />
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex gap-3">
|
||||
<Slider
|
||||
aria-labelledby={`v${name}`}
|
||||
defaultValue={[min]}
|
||||
onValueCommit={(min) => {
|
||||
data.updateAlert?.(true, value, min[0])
|
||||
}}
|
||||
onValueChange={(val) => {
|
||||
setMin(val[0])
|
||||
}}
|
||||
min={1}
|
||||
max={60}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Suspense>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import {
|
||||
useYAxisWidth,
|
||||
cn,
|
||||
formatShortDate,
|
||||
toFixedWithoutTrailingZeros,
|
||||
decimalString,
|
||||
chartMargin,
|
||||
} from "@/lib/utils"
|
||||
// import Spinner from '../spinner'
|
||||
import { ChartData } from "@/types"
|
||||
import { memo, useMemo } from "react"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
|
||||
/** [label, key, color, opacity] */
|
||||
type DataKeys = [string, string, number, number]
|
||||
|
||||
const getNestedValue = (path: string, max = false, data: any): number | null => {
|
||||
// fallback value (obj?.stats?.cpum ? 0 : null) should only come into play when viewing
|
||||
// a max value which doesn't exist, or the value was zero and omitted from the stats object.
|
||||
// so we check if cpum is present. if so, return 0 to make sure the zero value is displayed.
|
||||
// if not, return null - there is no max data so do not display anything.
|
||||
return `stats.${path}${max ? "m" : ""}`
|
||||
.split(".")
|
||||
.reduce((acc: any, key: string) => acc?.[key] ?? (data.stats?.cpum ? 0 : null), data)
|
||||
}
|
||||
|
||||
export default memo(function AreaChartDefault({
|
||||
maxToggled = false,
|
||||
unit = " MB/s",
|
||||
chartName,
|
||||
chartData,
|
||||
max,
|
||||
tickFormatter,
|
||||
contentFormatter,
|
||||
}: {
|
||||
maxToggled?: boolean
|
||||
unit?: string
|
||||
chartName: string
|
||||
chartData: ChartData
|
||||
max?: number
|
||||
tickFormatter?: (value: number) => string
|
||||
contentFormatter?: (value: number) => string
|
||||
}) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { i18n } = useLingui()
|
||||
|
||||
const { chartTime } = chartData
|
||||
|
||||
const showMax = chartTime !== "1h" && maxToggled
|
||||
|
||||
const dataKeys: DataKeys[] = useMemo(() => {
|
||||
// [label, key, color, opacity]
|
||||
if (chartName === "CPU Usage") {
|
||||
return [[t`CPU Usage`, "cpu", 1, 0.4]]
|
||||
} else if (chartName === "dio") {
|
||||
return [
|
||||
[t({ message: "Write", comment: "Disk write" }), "dw", 3, 0.3],
|
||||
[t({ message: "Read", comment: "Disk read" }), "dr", 1, 0.3],
|
||||
]
|
||||
} else if (chartName === "bw") {
|
||||
return [
|
||||
[t({ message: "Sent", comment: "Network bytes sent (upload)" }), "ns", 5, 0.2],
|
||||
[t({ message: "Received", comment: "Network bytes received (download)" }), "nr", 2, 0.2],
|
||||
]
|
||||
} else if (chartName.startsWith("efs")) {
|
||||
return [
|
||||
[t`Write`, `${chartName}.w`, 3, 0.3],
|
||||
[t`Read`, `${chartName}.r`, 1, 0.3],
|
||||
]
|
||||
} else if (chartName.startsWith("g.")) {
|
||||
return [chartName.includes("mu") ? [t`Used`, chartName, 2, 0.25] : [t`Usage`, chartName, 1, 0.4]]
|
||||
}
|
||||
return []
|
||||
}, [chartName, i18n.locale])
|
||||
|
||||
// console.log('Rendered at', new Date())
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
domain={[0, max ?? "auto"]}
|
||||
tickFormatter={(value) => {
|
||||
let val: string
|
||||
if (tickFormatter) {
|
||||
val = tickFormatter(value)
|
||||
} else {
|
||||
val = toFixedWithoutTrailingZeros(value, 2) + unit
|
||||
}
|
||||
return updateYAxisWidth(val)
|
||||
}}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={({ value }) => {
|
||||
if (contentFormatter) {
|
||||
return contentFormatter(value)
|
||||
}
|
||||
return decimalString(value) + unit
|
||||
}}
|
||||
// indicator="line"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{dataKeys.map((key, i) => {
|
||||
const color = `hsl(var(--chart-${key[2]}))`
|
||||
return (
|
||||
<Area
|
||||
key={i}
|
||||
dataKey={getNestedValue.bind(null, key[1], showMax)}
|
||||
name={key[0]}
|
||||
type="monotoneX"
|
||||
fill={color}
|
||||
fillOpacity={key[3]}
|
||||
stroke={color}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{/* <ChartLegend content={<ChartLegendContent />} /> */}
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -1,56 +0,0 @@
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { LaptopIcon, MoonStarIcon, SunIcon } from "lucide-react"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
||||
import { useTheme } from "@/components/theme-provider"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export function ModeToggle() {
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
const options = [
|
||||
{
|
||||
theme: "light",
|
||||
Icon: SunIcon,
|
||||
label: <Trans comment="Light theme">Light</Trans>,
|
||||
},
|
||||
{
|
||||
theme: "dark",
|
||||
Icon: MoonStarIcon,
|
||||
label: <Trans comment="Dark theme">Dark</Trans>,
|
||||
},
|
||||
{
|
||||
theme: "system",
|
||||
Icon: LaptopIcon,
|
||||
label: <Trans comment="System theme">System</Trans>,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant={"ghost"} size="icon" aria-label={t`Toggle theme`}>
|
||||
<SunIcon className="h-[1.2rem] w-[1.2rem] dark:opacity-0" />
|
||||
<MoonStarIcon className="absolute h-[1.2rem] w-[1.2rem] opacity-0 dark:opacity-100" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
{options.map((opt) => {
|
||||
const selected = opt.theme === theme
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={opt.theme}
|
||||
className={cn("px-2.5", selected ? "font-semibold" : "")}
|
||||
onClick={() => setTheme(opt.theme as "dark" | "light" | "system")}
|
||||
>
|
||||
<opt.Icon className={cn("me-2 h-4 w-4 opacity-80", selected && "opacity-100")} />
|
||||
{opt.label}
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
import { Suspense, lazy, memo, useEffect, useMemo } from "react"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"
|
||||
import { $alerts, $systems, pb } from "@/lib/stores"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { GithubIcon } from "lucide-react"
|
||||
import { Separator } from "../ui/separator"
|
||||
import { alertInfo, updateRecordList, updateSystemList } from "@/lib/utils"
|
||||
import { AlertRecord, SystemRecord } from "@/types"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
import { $router, Link } from "../router"
|
||||
import { Plural, Trans, useLingui } from "@lingui/react/macro"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
|
||||
const SystemsTable = lazy(() => import("../systems-table/systems-table"))
|
||||
|
||||
export const Home = memo(() => {
|
||||
const alerts = useStore($alerts)
|
||||
const systems = useStore($systems)
|
||||
const { t } = useLingui()
|
||||
|
||||
let alertsKey = ""
|
||||
const activeAlerts = useMemo(() => {
|
||||
const activeAlerts = alerts.filter((alert) => {
|
||||
const active = alert.triggered && alert.name in alertInfo
|
||||
if (!active) {
|
||||
return false
|
||||
}
|
||||
alert.sysname = systems.find((system) => system.id === alert.system)?.name
|
||||
alertsKey += alert.id
|
||||
return true
|
||||
})
|
||||
return activeAlerts
|
||||
}, [systems, alerts])
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t`Dashboard` + " / Beszel"
|
||||
}, [t])
|
||||
|
||||
useEffect(() => {
|
||||
// make sure we have the latest list of systems
|
||||
updateSystemList()
|
||||
|
||||
// subscribe to real time updates for systems / alerts
|
||||
pb.collection<SystemRecord>("systems").subscribe("*", (e) => {
|
||||
updateRecordList(e, $systems)
|
||||
})
|
||||
pb.collection<AlertRecord>("alerts").subscribe("*", (e) => {
|
||||
updateRecordList(e, $alerts)
|
||||
})
|
||||
return () => {
|
||||
pb.collection("systems").unsubscribe("*")
|
||||
// pb.collection('alerts').unsubscribe('*')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<>
|
||||
{/* show active alerts */}
|
||||
{activeAlerts.length > 0 && <ActiveAlerts key={activeAlerts.length} activeAlerts={activeAlerts} />}
|
||||
<Suspense>
|
||||
<SystemsTable />
|
||||
</Suspense>
|
||||
|
||||
<div className="flex gap-1.5 justify-end items-center pe-3 sm:pe-6 mt-3.5 text-xs opacity-80">
|
||||
<a
|
||||
href="https://github.com/henrygd/beszel"
|
||||
target="_blank"
|
||||
className="flex items-center gap-0.5 text-muted-foreground hover:text-foreground duration-75"
|
||||
>
|
||||
<GithubIcon className="h-3 w-3" /> GitHub
|
||||
</a>
|
||||
<Separator orientation="vertical" className="h-2.5 bg-muted-foreground opacity-70" />
|
||||
<a
|
||||
href="https://github.com/henrygd/beszel/releases"
|
||||
target="_blank"
|
||||
className="text-muted-foreground hover:text-foreground duration-75"
|
||||
>
|
||||
Beszel {globalThis.BESZEL.HUB_VERSION}
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
[alertsKey]
|
||||
)
|
||||
})
|
||||
|
||||
const ActiveAlerts = memo(({ activeAlerts }: { activeAlerts: AlertRecord[] }) => {
|
||||
return (
|
||||
<Card className="mb-4">
|
||||
<CardHeader className="pb-4 px-2 sm:px-6 max-sm:pt-5 max-sm:pb-1">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle>
|
||||
<Trans>Active Alerts</Trans>
|
||||
</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="max-sm:p-2">
|
||||
{activeAlerts.length > 0 && (
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-3">
|
||||
{activeAlerts.map((alert) => {
|
||||
const info = alertInfo[alert.name as keyof typeof alertInfo]
|
||||
return (
|
||||
<Alert
|
||||
key={alert.id}
|
||||
className="hover:-translate-y-[1px] duration-200 bg-transparent border-foreground/10 hover:shadow-md shadow-black"
|
||||
>
|
||||
<info.icon className="h-4 w-4" />
|
||||
<AlertTitle>
|
||||
{alert.sysname} {info.name().toLowerCase().replace("cpu", "CPU")}
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
<Trans>
|
||||
Exceeds {alert.value}
|
||||
{info.unit} in last <Plural value={alert.min} one="# minute" other="# minutes" />
|
||||
</Trans>
|
||||
</AlertDescription>
|
||||
<Link
|
||||
href={getPagePath($router, "system", { name: alert.sysname! })}
|
||||
className="absolute inset-0 w-full h-full"
|
||||
aria-label="View system"
|
||||
></Link>
|
||||
</Alert>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})
|
||||
@@ -1,111 +0,0 @@
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { chartTimeData } from "@/lib/utils"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { LanguagesIcon, LoaderCircleIcon, SaveIcon } from "lucide-react"
|
||||
import { UserSettings } from "@/types"
|
||||
import { saveSettings } from "./layout"
|
||||
import { useState } from "react"
|
||||
import languages from "@/lib/languages"
|
||||
import { dynamicActivate } from "@/lib/i18n"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
// import { setLang } from "@/lib/i18n"
|
||||
|
||||
export default function SettingsProfilePage({ userSettings }: { userSettings: UserSettings }) {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { i18n } = useLingui()
|
||||
|
||||
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
setIsLoading(true)
|
||||
const formData = new FormData(e.target as HTMLFormElement)
|
||||
const data = Object.fromEntries(formData) as Partial<UserSettings>
|
||||
await saveSettings(data)
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<h3 className="text-xl font-medium mb-2">
|
||||
<Trans>General</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
<Trans>Change general application options.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<form onSubmit={handleSubmit} className="space-y-5">
|
||||
<div className="space-y-2">
|
||||
<div className="mb-4">
|
||||
<h3 className="mb-1 text-lg font-medium flex items-center gap-2">
|
||||
<LanguagesIcon className="h-4 w-4" />
|
||||
<Trans>Language</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
<Trans>
|
||||
Want to help us make our translations even better? Check out{" "}
|
||||
<a href="https://crowdin.com/project/beszel" className="link" target="_blank" rel="noopener noreferrer">
|
||||
Crowdin
|
||||
</a>{" "}
|
||||
for more details.
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Label className="block" htmlFor="lang">
|
||||
<Trans>Preferred Language</Trans>
|
||||
</Label>
|
||||
<Select value={i18n.locale} onValueChange={(lang: string) => dynamicActivate(lang)}>
|
||||
<SelectTrigger id="lang">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{languages.map((lang) => (
|
||||
<SelectItem key={lang.lang} value={lang.lang}>
|
||||
<span className="me-2.5">{lang.e}</span>
|
||||
{lang.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<div className="mb-4">
|
||||
<h3 className="mb-1 text-lg font-medium">
|
||||
<Trans>Chart options</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
<Trans>Adjust display options for charts.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Label className="block" htmlFor="chartTime">
|
||||
<Trans>Default time period</Trans>
|
||||
</Label>
|
||||
<Select name="chartTime" key={userSettings.chartTime} defaultValue={userSettings.chartTime}>
|
||||
<SelectTrigger id="chartTime">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Object.entries(chartTimeData).map(([value, { label }]) => (
|
||||
<SelectItem key={value} value={value}>
|
||||
{label()}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-[0.8rem] text-muted-foreground">
|
||||
<Trans>Sets the default time range for charts when a system is viewed.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<Button type="submit" className="flex items-center gap-1.5 disabled:opacity-100" disabled={isLoading}>
|
||||
{isLoading ? <LoaderCircleIcon className="h-4 w-4 animate-spin" /> : <SaveIcon className="h-4 w-4" />}
|
||||
<Trans>Save Settings</Trans>
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,736 +0,0 @@
|
||||
import {
|
||||
CellContext,
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
getFilteredRowModel,
|
||||
SortingState,
|
||||
getSortedRowModel,
|
||||
flexRender,
|
||||
VisibilityState,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
HeaderContext,
|
||||
Row,
|
||||
Table as TableType,
|
||||
} from "@tanstack/react-table"
|
||||
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
|
||||
import { Button, buttonVariants } from "@/components/ui/button"
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog"
|
||||
|
||||
import { SystemRecord } from "@/types"
|
||||
import {
|
||||
MoreHorizontalIcon,
|
||||
ArrowUpDownIcon,
|
||||
MemoryStickIcon,
|
||||
CopyIcon,
|
||||
PauseCircleIcon,
|
||||
PlayCircleIcon,
|
||||
Trash2Icon,
|
||||
WifiIcon,
|
||||
HardDriveIcon,
|
||||
ServerIcon,
|
||||
CpuIcon,
|
||||
LayoutGridIcon,
|
||||
LayoutListIcon,
|
||||
ArrowDownIcon,
|
||||
ArrowUpIcon,
|
||||
Settings2Icon,
|
||||
EyeIcon,
|
||||
PenBoxIcon,
|
||||
} from "lucide-react"
|
||||
import { memo, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { $systems, pb } from "@/lib/stores"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { cn, copyToClipboard, decimalString, isReadOnlyUser, useLocalStorage } from "@/lib/utils"
|
||||
import AlertsButton from "../alerts/alert-button"
|
||||
import { $router, Link, navigate } from "../router"
|
||||
import { EthernetIcon, GpuIcon, ThermometerIcon } from "../ui/icons"
|
||||
import { useLingui, Trans } from "@lingui/react/macro"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
|
||||
import { Input } from "../ui/input"
|
||||
import { ClassValue } from "clsx"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { SystemDialog } from "../add-system"
|
||||
import { Dialog } from "../ui/dialog"
|
||||
|
||||
type ViewMode = "table" | "grid"
|
||||
|
||||
function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
const val = (info.getValue() as number) || 0
|
||||
return (
|
||||
<div className="flex gap-2 items-center tabular-nums tracking-tight">
|
||||
<span className="min-w-[3.3em]">{decimalString(val, 1)}%</span>
|
||||
<span className="grow min-w-10 block bg-muted h-[1em] relative rounded-sm overflow-hidden">
|
||||
<span
|
||||
className={cn(
|
||||
"absolute inset-0 w-full h-full origin-left",
|
||||
(info.row.original.status !== "up" && "bg-primary/30") ||
|
||||
(val < 65 && "bg-green-500") ||
|
||||
(val < 90 && "bg-yellow-500") ||
|
||||
"bg-red-600"
|
||||
)}
|
||||
style={{
|
||||
transform: `scalex(${val / 100})`,
|
||||
}}
|
||||
></span>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function sortableHeader(context: HeaderContext<SystemRecord, unknown>) {
|
||||
const { column } = context
|
||||
// @ts-ignore
|
||||
const { Icon, hideSort, name }: { Icon: React.ElementType; name: () => string; hideSort: boolean } = column.columnDef
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-9 px-3 flex"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
{Icon && <Icon className="me-2 size-4" />}
|
||||
{name()}
|
||||
{hideSort || <ArrowUpDownIcon className="ms-2 size-4" />}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export default function SystemsTable() {
|
||||
const data = useStore($systems)
|
||||
const { i18n, t } = useLingui()
|
||||
const [filter, setFilter] = useState<string>()
|
||||
const [sorting, setSorting] = useState<SortingState>([{ id: "system", desc: false }])
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
||||
const [columnVisibility, setColumnVisibility] = useLocalStorage<VisibilityState>("cols", {})
|
||||
const [viewMode, setViewMode] = useLocalStorage<ViewMode>("viewMode", window.innerWidth > 1024 ? "table" : "grid")
|
||||
|
||||
const locale = i18n.locale
|
||||
|
||||
useEffect(() => {
|
||||
if (filter !== undefined) {
|
||||
table.getColumn("system")?.setFilterValue(filter)
|
||||
}
|
||||
}, [filter])
|
||||
|
||||
const columnDefs = useMemo(() => {
|
||||
const statusTranslations = {
|
||||
up: () => t`Up`.toLowerCase(),
|
||||
down: () => t`Down`.toLowerCase(),
|
||||
paused: () => t`Paused`.toLowerCase(),
|
||||
}
|
||||
return [
|
||||
{
|
||||
// size: 200,
|
||||
size: 200,
|
||||
minSize: 0,
|
||||
accessorKey: "name",
|
||||
id: "system",
|
||||
name: () => t`System`,
|
||||
filterFn: (row, _, filterVal) => {
|
||||
const filterLower = filterVal.toLowerCase()
|
||||
const { name, status } = row.original
|
||||
// Check if the filter matches the name or status for this row
|
||||
if (
|
||||
name.toLowerCase().includes(filterLower) ||
|
||||
statusTranslations[status as keyof typeof statusTranslations]?.().includes(filterLower)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
enableHiding: false,
|
||||
Icon: ServerIcon,
|
||||
cell: (info) => (
|
||||
<span className="flex gap-0.5 items-center text-base md:pe-5">
|
||||
<IndicatorDot system={info.row.original} />
|
||||
<Button
|
||||
data-nolink
|
||||
variant={"ghost"}
|
||||
className="text-primary/90 h-7 px-1.5 gap-1.5"
|
||||
onClick={() => copyToClipboard(info.getValue() as string)}
|
||||
>
|
||||
{info.getValue() as string}
|
||||
<CopyIcon className="h-2.5 w-2.5" />
|
||||
</Button>
|
||||
</span>
|
||||
),
|
||||
header: sortableHeader,
|
||||
},
|
||||
{
|
||||
accessorKey: "info.cpu",
|
||||
id: "cpu",
|
||||
name: () => t`CPU`,
|
||||
invertSorting: true,
|
||||
cell: CellFormatter,
|
||||
Icon: CpuIcon,
|
||||
header: sortableHeader,
|
||||
},
|
||||
{
|
||||
accessorKey: "info.mp",
|
||||
id: "memory",
|
||||
name: () => t`Memory`,
|
||||
invertSorting: true,
|
||||
cell: CellFormatter,
|
||||
Icon: MemoryStickIcon,
|
||||
header: sortableHeader,
|
||||
},
|
||||
{
|
||||
accessorKey: "info.dp",
|
||||
id: "disk",
|
||||
name: () => t`Disk`,
|
||||
invertSorting: true,
|
||||
cell: CellFormatter,
|
||||
Icon: HardDriveIcon,
|
||||
header: sortableHeader,
|
||||
},
|
||||
{
|
||||
accessorFn: (originalRow) => originalRow.info.g,
|
||||
id: "gpu",
|
||||
name: () => "GPU",
|
||||
invertSorting: true,
|
||||
sortUndefined: -1,
|
||||
cell: CellFormatter,
|
||||
Icon: GpuIcon,
|
||||
header: sortableHeader,
|
||||
},
|
||||
{
|
||||
accessorFn: (originalRow) => originalRow.info.b || 0,
|
||||
id: "net",
|
||||
name: () => t`Net`,
|
||||
invertSorting: true,
|
||||
size: 50,
|
||||
Icon: EthernetIcon,
|
||||
header: sortableHeader,
|
||||
cell(info) {
|
||||
const val = info.getValue() as number
|
||||
return (
|
||||
<span
|
||||
className={cn("tabular-nums whitespace-nowrap", {
|
||||
"ps-1": viewMode === "table",
|
||||
})}
|
||||
>
|
||||
{decimalString(val, val >= 100 ? 1 : 2)} MB/s
|
||||
</span>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (originalRow) => originalRow.info.dt,
|
||||
id: "temp",
|
||||
name: () => t({ message: "Temp", comment: "Temperature label in systems table" }),
|
||||
invertSorting: true,
|
||||
sortUndefined: -1,
|
||||
size: 50,
|
||||
hideSort: true,
|
||||
Icon: ThermometerIcon,
|
||||
header: sortableHeader,
|
||||
cell(info) {
|
||||
const val = info.getValue() as number
|
||||
if (!val) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<span
|
||||
className={cn("tabular-nums whitespace-nowrap", {
|
||||
"ps-1.5": viewMode === "table",
|
||||
})}
|
||||
>
|
||||
{decimalString(val)} °C
|
||||
</span>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "info.v",
|
||||
id: "agent",
|
||||
name: () => t`Agent`,
|
||||
invertSorting: true,
|
||||
size: 50,
|
||||
Icon: WifiIcon,
|
||||
hideSort: true,
|
||||
header: sortableHeader,
|
||||
cell(info) {
|
||||
const version = info.getValue() as string
|
||||
if (!version) {
|
||||
return null
|
||||
}
|
||||
const system = info.row.original
|
||||
return (
|
||||
<span
|
||||
className={cn("flex gap-2 items-center md:pe-5 tabular-nums", {
|
||||
"ps-1": viewMode === "table",
|
||||
})}
|
||||
>
|
||||
<IndicatorDot
|
||||
system={system}
|
||||
className={
|
||||
(system.status !== "up" && "bg-primary/30") ||
|
||||
(version === globalThis.BESZEL.HUB_VERSION && "bg-green-500") ||
|
||||
"bg-yellow-500"
|
||||
}
|
||||
/>
|
||||
<span>{info.getValue() as string}</span>
|
||||
</span>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
// @ts-ignore
|
||||
name: () => t({ message: "Actions", comment: "Table column" }),
|
||||
size: 50,
|
||||
cell: ({ row }) => (
|
||||
<div className="flex justify-end items-center gap-1">
|
||||
<AlertsButton system={row.original} />
|
||||
<ActionsButton system={row.original} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
] as ColumnDef<SystemRecord>[]
|
||||
}, [])
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns: columnDefs,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
},
|
||||
defaultColumn: {
|
||||
minSize: 0,
|
||||
size: 900,
|
||||
maxSize: 900,
|
||||
},
|
||||
})
|
||||
|
||||
const rows = table.getRowModel().rows
|
||||
const columns = table.getAllColumns()
|
||||
const visibleColumns = table.getVisibleLeafColumns()
|
||||
// TODO: hiding temp then gpu messes up table headers
|
||||
const CardHead = useMemo(() => {
|
||||
return (
|
||||
<CardHeader className="pb-5 px-2 sm:px-6 max-sm:pt-5 max-sm:pb-1">
|
||||
<div className="grid md:flex gap-5 w-full items-end">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle className="mb-2.5">
|
||||
<Trans>All Systems</Trans>
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
<Trans>Updated in real time. Click on a system to view information.</Trans>
|
||||
</CardDescription>
|
||||
</div>
|
||||
<div className="flex gap-2 ms-auto w-full md:w-80">
|
||||
<Input placeholder={t`Filter...`} onChange={(e) => setFilter(e.target.value)} className="px-4" />
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<Settings2Icon className="me-1.5 size-4 opacity-80" />
|
||||
<Trans>View</Trans>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="h-72 md:h-auto min-w-48 md:min-w-auto overflow-y-auto">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 divide-y md:divide-s md:divide-y-0">
|
||||
<div>
|
||||
<DropdownMenuLabel className="pt-2 px-3.5 flex items-center gap-2">
|
||||
<LayoutGridIcon className="size-4" />
|
||||
<Trans>Layout</Trans>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuRadioGroup
|
||||
className="px-1 pb-1"
|
||||
value={viewMode}
|
||||
onValueChange={(view) => setViewMode(view as ViewMode)}
|
||||
>
|
||||
<DropdownMenuRadioItem value="table" onSelect={(e) => e.preventDefault()} className="gap-2">
|
||||
<LayoutListIcon className="size-4" />
|
||||
<Trans>Table</Trans>
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="grid" onSelect={(e) => e.preventDefault()} className="gap-2">
|
||||
<LayoutGridIcon className="size-4" />
|
||||
<Trans>Grid</Trans>
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<DropdownMenuLabel className="pt-2 px-3.5 flex items-center gap-2">
|
||||
<ArrowUpDownIcon className="size-4" />
|
||||
<Trans>Sort By</Trans>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<div className="px-1 pb-1">
|
||||
{columns.map((column) => {
|
||||
if (!column.getCanSort()) return null
|
||||
let Icon = <span className="w-6"></span>
|
||||
// if current sort column, show sort direction
|
||||
if (sorting[0]?.id === column.id) {
|
||||
if (sorting[0]?.desc) {
|
||||
Icon = <ArrowUpIcon className="me-2 size-4" />
|
||||
} else {
|
||||
Icon = <ArrowDownIcon className="me-2 size-4" />
|
||||
}
|
||||
}
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
onSelect={(e) => {
|
||||
e.preventDefault()
|
||||
setSorting([{ id: column.id, desc: sorting[0]?.id === column.id && !sorting[0]?.desc }])
|
||||
}}
|
||||
key={column.id}
|
||||
>
|
||||
{Icon}
|
||||
{/* @ts-ignore */}
|
||||
{column.columnDef.name()}
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<DropdownMenuLabel className="pt-2 px-3.5 flex items-center gap-2">
|
||||
<EyeIcon className="size-4" />
|
||||
<Trans>Visible Fields</Trans>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<div className="px-1.5 pb-1">
|
||||
{columns
|
||||
.filter((column) => column.getCanHide())
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
onSelect={(e) => e.preventDefault()}
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(value) => column.toggleVisibility(!!value)}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
{column.columnDef.name()}
|
||||
</DropdownMenuCheckboxItem>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
)
|
||||
}, [visibleColumns.length, sorting, viewMode, locale])
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{CardHead}
|
||||
<div className="p-6 pt-0 max-sm:py-3 max-sm:px-2">
|
||||
{viewMode === "table" ? (
|
||||
// table layout
|
||||
<div className="rounded-md border overflow-hidden">
|
||||
<AllSystemsTable table={table} rows={rows} colLength={visibleColumns.length} />
|
||||
</div>
|
||||
) : (
|
||||
// grid layout
|
||||
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{rows?.length ? (
|
||||
rows.map((row) => {
|
||||
return <SystemCard key={row.original.id} row={row} table={table} colLength={visibleColumns.length} />
|
||||
})
|
||||
) : (
|
||||
<div className="col-span-full text-center py-8">
|
||||
<Trans>No systems found.</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
const AllSystemsTable = memo(
|
||||
({ table, rows, colLength }: { table: TableType<SystemRecord>; rows: Row<SystemRecord>[]; colLength: number }) => {
|
||||
return (
|
||||
<Table>
|
||||
<SystemsTableHead table={table} colLength={colLength} />
|
||||
<TableBody>
|
||||
{rows.length ? (
|
||||
rows.map((row) => (
|
||||
<SystemTableRow key={row.original.id} row={row} length={rows.length} colLength={colLength} />
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={colLength} className="h-24 text-center">
|
||||
<Trans>No systems found.</Trans>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
function SystemsTableHead({ table, colLength }: { table: TableType<SystemRecord>; colLength: number }) {
|
||||
const { i18n } = useLingui()
|
||||
return useMemo(() => {
|
||||
return (
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead className="px-2" key={header.id}>
|
||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||
</TableHead>
|
||||
)
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
)
|
||||
}, [i18n.locale, colLength])
|
||||
}
|
||||
|
||||
const SystemTableRow = memo(
|
||||
({ row, length, colLength }: { row: Row<SystemRecord>; length: number; colLength: number }) => {
|
||||
const system = row.original
|
||||
const { t } = useLingui()
|
||||
return useMemo(() => {
|
||||
return (
|
||||
<TableRow
|
||||
// data-state={row.getIsSelected() && "selected"}
|
||||
className={cn("cursor-pointer transition-opacity", {
|
||||
"opacity-50": system.status === "paused",
|
||||
})}
|
||||
onClick={(e) => {
|
||||
const target = e.target as HTMLElement
|
||||
if (!target.closest("[data-nolink]") && e.currentTarget.contains(target)) {
|
||||
navigate(getPagePath($router, "system", { name: system.name }))
|
||||
}
|
||||
}}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
style={{
|
||||
width: cell.column.getSize(),
|
||||
}}
|
||||
className={cn("overflow-hidden relative", length > 10 ? "py-2" : "py-2.5")}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
)
|
||||
}, [system, system.status, colLength, t])
|
||||
}
|
||||
)
|
||||
|
||||
const SystemCard = memo(
|
||||
({ row, table, colLength }: { row: Row<SystemRecord>; table: TableType<SystemRecord>; colLength: number }) => {
|
||||
const system = row.original
|
||||
const { t } = useLingui()
|
||||
|
||||
return useMemo(() => {
|
||||
return (
|
||||
<Card
|
||||
key={system.id}
|
||||
className={cn(
|
||||
"cursor-pointer hover:shadow-md transition-all bg-transparent w-full dark:border-border duration-200 relative",
|
||||
{
|
||||
"opacity-50": system.status === "paused",
|
||||
}
|
||||
)}
|
||||
>
|
||||
<CardHeader className="py-1 ps-5 pe-3 bg-muted/30 border-b border-border/60">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<CardTitle className="text-base tracking-normal shrink-1 text-primary/90 flex items-center min-h-10 gap-2.5 min-w-0">
|
||||
<div className="flex items-center gap-2.5 min-w-0">
|
||||
<IndicatorDot system={system} />
|
||||
<CardTitle className="text-[.95em]/normal tracking-normal truncate text-primary/90">
|
||||
{system.name}
|
||||
</CardTitle>
|
||||
</div>
|
||||
</CardTitle>
|
||||
{table.getColumn("actions")?.getIsVisible() && (
|
||||
<div className="flex gap-1 flex-shrink-0 relative z-10">
|
||||
<AlertsButton system={system} />
|
||||
<ActionsButton system={system} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2.5 text-sm px-5 pt-3.5 pb-4">
|
||||
{table.getAllColumns().map((column) => {
|
||||
if (!column.getIsVisible() || column.id === "system" || column.id === "actions") return null
|
||||
const cell = row.getAllCells().find((cell) => cell.column.id === column.id)
|
||||
if (!cell) return null
|
||||
// @ts-ignore
|
||||
const { Icon, name } = column.columnDef as ColumnDef<SystemRecord, unknown>
|
||||
return (
|
||||
<div key={column.id} className="flex items-center gap-3">
|
||||
{Icon && <Icon className="size-4 text-muted-foreground" />}
|
||||
<div className="flex items-center gap-3 flex-1">
|
||||
<span className="text-muted-foreground min-w-16">{name()}:</span>
|
||||
<div className="flex-1">{flexRender(cell.column.columnDef.cell, cell.getContext())}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</CardContent>
|
||||
<Link
|
||||
href={getPagePath($router, "system", { name: row.original.name })}
|
||||
className="inset-0 absolute w-full h-full"
|
||||
>
|
||||
<span className="sr-only">{row.original.name}</span>
|
||||
</Link>
|
||||
</Card>
|
||||
)
|
||||
}, [system, colLength, t])
|
||||
}
|
||||
)
|
||||
|
||||
const ActionsButton = memo(({ system }: { system: SystemRecord }) => {
|
||||
const [deleteOpen, setDeleteOpen] = useState(false)
|
||||
const [editOpen, setEditOpen] = useState(false)
|
||||
let editOpened = useRef(false)
|
||||
const { t } = useLingui()
|
||||
const { id, status, host, name } = system
|
||||
|
||||
return useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size={"icon"} data-nolink>
|
||||
<span className="sr-only">
|
||||
<Trans>Open menu</Trans>
|
||||
</span>
|
||||
<MoreHorizontalIcon className="w-5" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
{!isReadOnlyUser() && (
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
editOpened.current = true
|
||||
setEditOpen(true)
|
||||
}}
|
||||
>
|
||||
<PenBoxIcon className="me-2.5 size-4" />
|
||||
<Trans>Edit</Trans>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
className={cn(isReadOnlyUser() && "hidden")}
|
||||
onClick={() => {
|
||||
pb.collection("systems").update(id, {
|
||||
status: status === "paused" ? "pending" : "paused",
|
||||
})
|
||||
}}
|
||||
>
|
||||
{status === "paused" ? (
|
||||
<>
|
||||
<PlayCircleIcon className="me-2.5 size-4" />
|
||||
<Trans>Resume</Trans>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<PauseCircleIcon className="me-2.5 size-4" />
|
||||
<Trans>Pause</Trans>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => copyToClipboard(host)}>
|
||||
<CopyIcon className="me-2.5 size-4" />
|
||||
<Trans>Copy host</Trans>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator className={cn(isReadOnlyUser() && "hidden")} />
|
||||
<DropdownMenuItem className={cn(isReadOnlyUser() && "hidden")} onSelect={() => setDeleteOpen(true)}>
|
||||
<Trash2Icon className="me-2.5 size-4" />
|
||||
<Trans>Delete</Trans>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
{/* edit dialog */}
|
||||
<Dialog open={editOpen} onOpenChange={setEditOpen}>
|
||||
{editOpened.current && <SystemDialog system={system} setOpen={setEditOpen} />}
|
||||
</Dialog>
|
||||
{/* deletion dialog */}
|
||||
<AlertDialog open={deleteOpen} onOpenChange={(open) => setDeleteOpen(open)}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
<Trans>Are you sure you want to delete {name}?</Trans>
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
<Trans>
|
||||
This action cannot be undone. This will permanently delete all current records for {name} from the
|
||||
database.
|
||||
</Trans>
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>
|
||||
<Trans>Cancel</Trans>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className={cn(buttonVariants({ variant: "destructive" }))}
|
||||
onClick={() => pb.collection("systems").delete(id)}
|
||||
>
|
||||
<Trans>Continue</Trans>
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</>
|
||||
)
|
||||
}, [id, status, host, name, t, deleteOpen, editOpen])
|
||||
})
|
||||
|
||||
function IndicatorDot({ system, className }: { system: SystemRecord; className?: ClassValue }) {
|
||||
className ||= {
|
||||
"bg-green-500": system.status === "up",
|
||||
"bg-red-500": system.status === "down",
|
||||
"bg-primary/40": system.status === "paused",
|
||||
"bg-yellow-500": system.status === "pending",
|
||||
}
|
||||
return (
|
||||
<span
|
||||
className={cn("flex-shrink-0 size-2 rounded-full", className)}
|
||||
// style={{ marginBottom: "-1px" }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { DialogTitle, type DialogProps } from "@radix-ui/react-dialog"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import { Search } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn("flex h-full w-full flex-col overflow-hidden bg-popover text-popover-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
interface CommandDialogProps extends DialogProps {}
|
||||
|
||||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
||||
<div className="sr-only">
|
||||
<DialogTitle>Command</DialogTitle>
|
||||
</div>
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="me-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />)
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator ref={ref} className={cn("-mx-1 h-px bg-border", className)} {...props} />
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default opacity-70 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:opacity-90 data-[disabled='true']:pointer-events-none data-[disabled='true']:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return <span className={cn("ms-auto text-xs tracking-wide text-muted-foreground", className)} {...props} />
|
||||
}
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import { SVGProps } from "react"
|
||||
|
||||
// linux-logo-bold from https://github.com/phosphor-icons/core (MIT license)
|
||||
export function TuxIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 256 256" {...props}>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M231 217a12 12 0 0 1-16-2c-2-1-35-44-35-127a52 52 0 1 0-104 0c0 83-33 126-35 127a12 12 0 0 1-18-14c0-1 29-39 29-113a76 76 0 1 1 152 0c0 74 29 112 29 113a12 12 0 0 1-2 16m-127-97a16 16 0 1 0-16-16 16 16 0 0 0 16 16m64-16a16 16 0 1 0-16 16 16 16 0 0 0 16-16m-73 51 28 12a12 12 0 0 0 10 0l28-12a12 12 0 0 0-10-22l-23 10-23-10a12 12 0 0 0-10 22m33 29a57 57 0 0 0-39 15 12 12 0 0 0 17 18 33 33 0 0 1 44 0 12 12 0 1 0 17-18 57 57 0 0 0-39-15"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
// MingCute Apache License 2.0 https://github.com/Richard9394/MingCute
|
||||
export function Rows(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5 3a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm0 2h14v4H5zm0 8a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2zm0 2h14v4H5z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
// IconPark Apache License 2.0 https://github.com/bytedance/IconPark
|
||||
export function ChartAverage(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg fill="none" viewBox="0 0 48 48" stroke="currentColor" {...props}>
|
||||
<path strokeWidth="3" d="M4 4v40h40" />
|
||||
<path strokeWidth="3" d="M10 38S15.3 4 27 4s17 34 17 34" />
|
||||
<path strokeWidth="4" d="M10 24h34" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
// IconPark Apache License 2.0 https://github.com/bytedance/IconPark
|
||||
export function ChartMax(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg fill="none" viewBox="0 0 48 48" stroke="currentColor" {...props}>
|
||||
<path strokeWidth="3" d="M4 4v40h40" />
|
||||
<path strokeWidth="3" d="M10 38S15.3 4 27 4s17 34 17 34" />
|
||||
<path strokeWidth="4" d="M10 4h34" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
// Lucide https://github.com/lucide-icons/lucide (not in package for some reason)
|
||||
export function EthernetIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg fill="none" stroke="currentColor" strokeLinecap="round" strokeWidth="2" viewBox="0 0 24 24" {...props}>
|
||||
<path d="m15 20 3-3h2a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h2l3 3zM6 8v1m4-1v1m4-1v1m4-1v1" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
// Phosphor MIT https://github.com/phosphor-icons/core
|
||||
export function ThermometerIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 256 256" {...props} fill="currentColor">
|
||||
<path d="M212 56a28 28 0 1 0 28 28 28 28 0 0 0-28-28m0 40a12 12 0 1 1 12-12 12 12 0 0 1-12 12m-60 50V40a32 32 0 0 0-64 0v106a56 56 0 1 0 64 0m-16-42h-32V40a16 16 0 0 1 32 0Z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
// Huge icons (MIT)
|
||||
export function GpuIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" {...props} stroke="currentColor" fill="none" strokeWidth="2">
|
||||
<path d="M4 21V4.1a1.5 1.5 0 0 0-1.1-1L2 3m2 2h13c2.4 0 3.5 0 4.3.7s.7 2 .7 4.3v4.5c0 2.4 0 3.5-.7 4.3-.8.7-2 .7-4.3.7h-4.9a1.8 1.8 0 0 1-1.6-1c-.3-.6-1-1-1.6-1H4" />
|
||||
<path d="M19 11.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0m-11.5-3h2m-2 3h2m-2 3h2" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Input.displayName = "Input"
|
||||
|
||||
export { Input }
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from "@/components/ui/toast"
|
||||
import { useToast } from "@/components/ui/use-toast"
|
||||
|
||||
export function Toaster() {
|
||||
const { toasts } = useToast()
|
||||
|
||||
return (
|
||||
<ToastProvider>
|
||||
{toasts.map(function ({ id, title, description, action, ...props }) {
|
||||
return (
|
||||
<Toast key={id} {...props}>
|
||||
<div className="grid gap-1">
|
||||
{title && <ToastTitle>{title}</ToastTitle>}
|
||||
{description && <ToastDescription>{description}</ToastDescription>}
|
||||
</div>
|
||||
{action}
|
||||
<ToastClose />
|
||||
</Toast>
|
||||
)
|
||||
})}
|
||||
<ToastViewport />
|
||||
</ToastProvider>
|
||||
)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import * as React from "react"
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider
|
||||
|
||||
const Tooltip = TooltipPrimitive.Root
|
||||
|
||||
const TooltipTrigger = TooltipPrimitive.Trigger
|
||||
|
||||
const TooltipContent = React.forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<TooltipPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
||||
@@ -1,103 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 30 8% 98.5%;
|
||||
--foreground: 30 0% 0%;
|
||||
--card: 30 0% 100%;
|
||||
--card-foreground: 240 6.67% 2.94%;
|
||||
--popover: 30 0% 100%;
|
||||
--popover-foreground: 240 10% 6.2%;
|
||||
--primary: 240 5.88% 10%;
|
||||
--primary-foreground: 30 0% 100%;
|
||||
--secondary: 240 4.76% 95.88%;
|
||||
--secondary-foreground: 240 5.88% 10%;
|
||||
--muted: 26 6% 94%;
|
||||
--muted-foreground: 24 2.79% 35.1%;
|
||||
--accent: 20 23.08% 94%;
|
||||
--accent-foreground: 240 5.88% 10%;
|
||||
--destructive: 0 66% 53%;
|
||||
--destructive-foreground: 0 0% 98.04%;
|
||||
--border: 30 8.11% 85.49%;
|
||||
--input: 30 4.29% 72.55%;
|
||||
--ring: 30 3.97% 49.41%;
|
||||
--radius: 0.8rem;
|
||||
/* charts */
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
color-scheme: dark;
|
||||
--background: 220 5.5% 9%;
|
||||
--foreground: 220 2% 97%;
|
||||
--card: 220 5.5% 10.5%;
|
||||
--card-foreground: 220 2% 97%;
|
||||
--popover: 220 5.5% 9%;
|
||||
--popover-foreground: 220 2% 97%;
|
||||
--primary: 220 2% 96%;
|
||||
--primary-foreground: 220 4% 10%;
|
||||
--secondary: 220 4% 16%;
|
||||
--secondary-foreground: 220 0% 98%;
|
||||
--muted: 220 6% 16%;
|
||||
--muted-foreground: 220 4% 67%;
|
||||
--accent: 220 5% 15.5%;
|
||||
--accent-foreground: 220 2% 98%;
|
||||
--destructive: 0 62% 46%;
|
||||
--destructive-foreground: 0 0% 97%;
|
||||
--border: 220 3% 16%;
|
||||
--input: 220 4% 22%;
|
||||
--ring: 220 4% 80%;
|
||||
--radius: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonts */
|
||||
@supports (font-variation-settings: normal) {
|
||||
:root {
|
||||
font-family: Inter, InterVariable, sans-serif;
|
||||
}
|
||||
}
|
||||
@font-face {
|
||||
font-family: InterVariable;
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("/static/InterVariable.woff2?v=4.0") format("woff2");
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
overflow-anchor: none;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.link {
|
||||
@apply text-primary font-medium underline-offset-4 hover:underline;
|
||||
}
|
||||
/* New system dialog width */
|
||||
.ns-dialog {
|
||||
min-width: 30.3rem;
|
||||
}
|
||||
:where(:lang(zh), :lang(zh-CN), :lang(ko)) .ns-dialog {
|
||||
min-width: 27.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.recharts-tooltip-wrapper {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.recharts-yAxis {
|
||||
@apply tabular-nums;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import PocketBase from "pocketbase"
|
||||
import { atom, map, PreinitializedWritableAtom } from "nanostores"
|
||||
import { AlertRecord, ChartTimes, SystemRecord, UserSettings } from "@/types"
|
||||
import { basePath } from "@/components/router"
|
||||
|
||||
/** PocketBase JS Client */
|
||||
export const pb = new PocketBase(basePath)
|
||||
|
||||
/** Store if user is authenticated */
|
||||
export const $authenticated = atom(pb.authStore.isValid)
|
||||
|
||||
/** List of system records */
|
||||
export const $systems = atom([] as SystemRecord[])
|
||||
|
||||
/** List of alert records */
|
||||
export const $alerts = atom([] as AlertRecord[])
|
||||
|
||||
/** SSH public key */
|
||||
export const $publicKey = atom("")
|
||||
|
||||
/** Chart time period */
|
||||
export const $chartTime = atom("1h") as PreinitializedWritableAtom<ChartTimes>
|
||||
|
||||
/** Whether to display average or max chart values */
|
||||
export const $maxValues = atom(false)
|
||||
|
||||
/** User settings */
|
||||
export const $userSettings = map<UserSettings>({
|
||||
chartTime: "1h",
|
||||
emails: [pb.authStore.record?.email || ""],
|
||||
})
|
||||
// update local storage on change
|
||||
$userSettings.subscribe((value) => {
|
||||
// console.log('user settings changed', value)
|
||||
$chartTime.set(value.chartTime)
|
||||
})
|
||||
|
||||
/** Container chart filter */
|
||||
export const $containerFilter = atom("")
|
||||
|
||||
/** Fallback copy to clipboard dialog content */
|
||||
export const $copyContent = atom("")
|
||||
|
||||
/** Direction for localization */
|
||||
export const $direction = atom<"ltr" | "rtl">("ltr")
|
||||
@@ -1,357 +0,0 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { toast } from "@/components/ui/use-toast"
|
||||
import { type ClassValue, clsx } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { $alerts, $copyContent, $systems, $userSettings, pb } from "./stores"
|
||||
import { AlertInfo, AlertRecord, ChartTimeData, ChartTimes, SystemRecord } from "@/types"
|
||||
import { RecordModel, RecordSubscription } from "pocketbase"
|
||||
import { WritableAtom } from "nanostores"
|
||||
import { timeDay, timeHour } from "d3-time"
|
||||
import { useEffect, useState } from "react"
|
||||
import { CpuIcon, HardDriveIcon, MemoryStickIcon, ServerIcon } from "lucide-react"
|
||||
import { EthernetIcon, ThermometerIcon } from "@/components/ui/icons"
|
||||
import { prependBasePath } from "@/components/router"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
/** Adds event listener to node and returns function that removes the listener */
|
||||
export function listen<T extends Event = Event>(
|
||||
node: Node,
|
||||
event: string,
|
||||
handler: (event: T) => void
|
||||
) {
|
||||
node.addEventListener(event, handler as EventListener)
|
||||
return () => node.removeEventListener(event, handler as EventListener)
|
||||
}
|
||||
|
||||
export async function copyToClipboard(content: string) {
|
||||
const duration = 1500
|
||||
try {
|
||||
await navigator.clipboard.writeText(content)
|
||||
toast({
|
||||
duration,
|
||||
description: t`Copied to clipboard`,
|
||||
})
|
||||
} catch (e: any) {
|
||||
$copyContent.set(content)
|
||||
}
|
||||
}
|
||||
|
||||
const verifyAuth = () => {
|
||||
pb.collection("users")
|
||||
.authRefresh()
|
||||
.catch(() => {
|
||||
logOut()
|
||||
toast({
|
||||
title: t`Failed to authenticate`,
|
||||
description: t`Please log in again`,
|
||||
variant: "destructive",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const updateSystemList = (() => {
|
||||
let isFetchingSystems = false
|
||||
return async () => {
|
||||
if (isFetchingSystems) {
|
||||
return
|
||||
}
|
||||
isFetchingSystems = true
|
||||
try {
|
||||
const records = await pb
|
||||
.collection<SystemRecord>("systems")
|
||||
.getFullList({ sort: "+name", fields: "id,name,host,port,info,status" })
|
||||
|
||||
if (records.length) {
|
||||
$systems.set(records)
|
||||
} else {
|
||||
verifyAuth()
|
||||
}
|
||||
} finally {
|
||||
isFetchingSystems = false
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
/** Logs the user out by clearing the auth store and unsubscribing from realtime updates. */
|
||||
export async function logOut() {
|
||||
sessionStorage.setItem("lo", "t")
|
||||
pb.authStore.clear()
|
||||
pb.realtime.unsubscribe()
|
||||
}
|
||||
|
||||
export const updateAlerts = () => {
|
||||
pb.collection("alerts")
|
||||
.getFullList<AlertRecord>({ fields: "id,name,system,value,min,triggered", sort: "updated" })
|
||||
.then((records) => {
|
||||
$alerts.set(records)
|
||||
})
|
||||
}
|
||||
|
||||
const hourWithMinutesFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})
|
||||
export const hourWithMinutes = (timestamp: string) => {
|
||||
return hourWithMinutesFormatter.format(new Date(timestamp))
|
||||
}
|
||||
|
||||
const shortDateFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})
|
||||
export const formatShortDate = (timestamp: string) => {
|
||||
return shortDateFormatter.format(new Date(timestamp))
|
||||
}
|
||||
|
||||
const dayFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
})
|
||||
export const formatDay = (timestamp: string) => {
|
||||
return dayFormatter.format(new Date(timestamp))
|
||||
}
|
||||
|
||||
export const updateFavicon = (newIcon: string) => {
|
||||
;(document.querySelector("link[rel='icon']") as HTMLLinkElement).href = prependBasePath(`/static/${newIcon}`)
|
||||
}
|
||||
|
||||
export const isAdmin = () => pb.authStore.record?.role === "admin"
|
||||
export const isReadOnlyUser = () => pb.authStore.record?.role === "readonly"
|
||||
|
||||
/** Update systems / alerts list when records change */
|
||||
export function updateRecordList<T extends RecordModel>(e: RecordSubscription<T>, $store: WritableAtom<T[]>) {
|
||||
const curRecords = $store.get()
|
||||
const newRecords = []
|
||||
if (e.action === "delete") {
|
||||
for (const server of curRecords) {
|
||||
if (server.id !== e.record.id) {
|
||||
newRecords.push(server)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let found = 0
|
||||
for (const server of curRecords) {
|
||||
if (server.id === e.record.id) {
|
||||
found = newRecords.push(e.record)
|
||||
} else {
|
||||
newRecords.push(server)
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
newRecords.push(e.record)
|
||||
}
|
||||
}
|
||||
$store.set(newRecords)
|
||||
}
|
||||
|
||||
export function getPbTimestamp(timeString: ChartTimes, d?: Date) {
|
||||
d ||= chartTimeData[timeString].getOffset(new Date())
|
||||
const year = d.getUTCFullYear()
|
||||
const month = String(d.getUTCMonth() + 1).padStart(2, "0")
|
||||
const day = String(d.getUTCDate()).padStart(2, "0")
|
||||
const hours = String(d.getUTCHours()).padStart(2, "0")
|
||||
const minutes = String(d.getUTCMinutes()).padStart(2, "0")
|
||||
const seconds = String(d.getUTCSeconds()).padStart(2, "0")
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
export const chartTimeData: ChartTimeData = {
|
||||
"1h": {
|
||||
type: "1m",
|
||||
expectedInterval: 60_000,
|
||||
label: () => t`1 hour`,
|
||||
// ticks: 12,
|
||||
format: (timestamp: string) => hourWithMinutes(timestamp),
|
||||
getOffset: (endTime: Date) => timeHour.offset(endTime, -1),
|
||||
},
|
||||
"12h": {
|
||||
type: "10m",
|
||||
expectedInterval: 60_000 * 10,
|
||||
label: () => t`12 hours`,
|
||||
ticks: 12,
|
||||
format: (timestamp: string) => hourWithMinutes(timestamp),
|
||||
getOffset: (endTime: Date) => timeHour.offset(endTime, -12),
|
||||
},
|
||||
"24h": {
|
||||
type: "20m",
|
||||
expectedInterval: 60_000 * 20,
|
||||
label: () => t`24 hours`,
|
||||
format: (timestamp: string) => hourWithMinutes(timestamp),
|
||||
getOffset: (endTime: Date) => timeHour.offset(endTime, -24),
|
||||
},
|
||||
"1w": {
|
||||
type: "120m",
|
||||
expectedInterval: 60_000 * 120,
|
||||
label: () => t`1 week`,
|
||||
ticks: 7,
|
||||
format: (timestamp: string) => formatDay(timestamp),
|
||||
getOffset: (endTime: Date) => timeDay.offset(endTime, -7),
|
||||
},
|
||||
"30d": {
|
||||
type: "480m",
|
||||
expectedInterval: 60_000 * 480,
|
||||
label: () => t`30 days`,
|
||||
ticks: 30,
|
||||
format: (timestamp: string) => formatDay(timestamp),
|
||||
getOffset: (endTime: Date) => timeDay.offset(endTime, -30),
|
||||
},
|
||||
}
|
||||
|
||||
/** Sets the correct width of the y axis in recharts based on the longest label */
|
||||
export function useYAxisWidth() {
|
||||
const [yAxisWidth, setYAxisWidth] = useState(0)
|
||||
let maxChars = 0
|
||||
let timeout: Timer
|
||||
function updateYAxisWidth(str: string) {
|
||||
if (str.length > maxChars) {
|
||||
maxChars = str.length
|
||||
const div = document.createElement("div")
|
||||
div.className = "text-xs tabular-nums tracking-tighter table sr-only"
|
||||
div.innerHTML = str
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => {
|
||||
document.body.appendChild(div)
|
||||
const width = div.offsetWidth + 24
|
||||
if (width > yAxisWidth) {
|
||||
setYAxisWidth(div.offsetWidth + 24)
|
||||
}
|
||||
document.body.removeChild(div)
|
||||
})
|
||||
}
|
||||
return str
|
||||
}
|
||||
return { yAxisWidth, updateYAxisWidth }
|
||||
}
|
||||
|
||||
export function toFixedWithoutTrailingZeros(num: number, digits: number) {
|
||||
return parseFloat(num.toFixed(digits)).toString()
|
||||
}
|
||||
|
||||
export function toFixedFloat(num: number, digits: number) {
|
||||
return parseFloat(num.toFixed(digits))
|
||||
}
|
||||
|
||||
let decimalFormatters: Map<number, Intl.NumberFormat> = new Map()
|
||||
/** Format number to x decimal places */
|
||||
export function decimalString(num: number, digits = 2) {
|
||||
let formatter = decimalFormatters.get(digits)
|
||||
if (!formatter) {
|
||||
formatter = new Intl.NumberFormat(undefined, {
|
||||
minimumFractionDigits: digits,
|
||||
maximumFractionDigits: digits,
|
||||
})
|
||||
decimalFormatters.set(digits, formatter)
|
||||
}
|
||||
return formatter.format(num)
|
||||
}
|
||||
|
||||
/** Get value from local storage */
|
||||
function getStorageValue(key: string, defaultValue: any) {
|
||||
const saved = localStorage?.getItem(key)
|
||||
return saved ? JSON.parse(saved) : defaultValue
|
||||
}
|
||||
|
||||
/** Hook to sync value in local storage */
|
||||
export function useLocalStorage<T>(key: string, defaultValue: T) {
|
||||
key = `besz-${key}`
|
||||
const [value, setValue] = useState(() => {
|
||||
return getStorageValue(key, defaultValue)
|
||||
})
|
||||
useEffect(() => {
|
||||
localStorage?.setItem(key, JSON.stringify(value))
|
||||
}, [key, value])
|
||||
|
||||
return [value, setValue]
|
||||
}
|
||||
|
||||
export async function updateUserSettings() {
|
||||
try {
|
||||
const req = await pb.collection("user_settings").getFirstListItem("", { fields: "settings" })
|
||||
$userSettings.set(req.settings)
|
||||
return
|
||||
} catch (e) {
|
||||
console.log("get settings", e)
|
||||
}
|
||||
// create user settings if error fetching existing
|
||||
try {
|
||||
const createdSettings = await pb.collection("user_settings").create({ user: pb.authStore.record!.id })
|
||||
$userSettings.set(createdSettings.settings)
|
||||
} catch (e) {
|
||||
console.log("create settings", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value and unit of size (TB, GB, or MB) for a given size
|
||||
* @param n size in gigabytes or megabytes
|
||||
* @param isGigabytes boolean indicating if n represents gigabytes (true) or megabytes (false)
|
||||
* @returns an object containing the value and unit of size
|
||||
*/
|
||||
export const getSizeAndUnit = (n: number, isGigabytes = true) => {
|
||||
const sizeInGB = isGigabytes ? n : n / 1_000
|
||||
|
||||
if (sizeInGB >= 1_000) {
|
||||
return { v: sizeInGB / 1_000, u: " TB" }
|
||||
} else if (sizeInGB >= 1) {
|
||||
return { v: sizeInGB, u: " GB" }
|
||||
}
|
||||
return { v: isGigabytes ? sizeInGB * 1_000 : n, u: " MB" }
|
||||
}
|
||||
|
||||
export const chartMargin = { top: 12 }
|
||||
|
||||
export const alertInfo: Record<string, AlertInfo> = {
|
||||
Status: {
|
||||
name: () => t`Status`,
|
||||
unit: "",
|
||||
icon: ServerIcon,
|
||||
desc: () => t`Triggers when status switches between up and down`,
|
||||
/** "for x minutes" is appended to desc when only one value */
|
||||
singleDesc: () => t`System` + " " + t`Down`,
|
||||
},
|
||||
CPU: {
|
||||
name: () => t`CPU Usage`,
|
||||
unit: "%",
|
||||
icon: CpuIcon,
|
||||
desc: () => t`Triggers when CPU usage exceeds a threshold`,
|
||||
},
|
||||
Memory: {
|
||||
name: () => t`Memory Usage`,
|
||||
unit: "%",
|
||||
icon: MemoryStickIcon,
|
||||
desc: () => t`Triggers when memory usage exceeds a threshold`,
|
||||
},
|
||||
Disk: {
|
||||
name: () => t`Disk Usage`,
|
||||
unit: "%",
|
||||
icon: HardDriveIcon,
|
||||
desc: () => t`Triggers when usage of any disk exceeds a threshold`,
|
||||
},
|
||||
Bandwidth: {
|
||||
name: () => t`Bandwidth`,
|
||||
unit: " MB/s",
|
||||
icon: EthernetIcon,
|
||||
desc: () => t`Triggers when combined up/down exceeds a threshold`,
|
||||
max: 125,
|
||||
},
|
||||
Temperature: {
|
||||
name: () => t`Temperature`,
|
||||
unit: "°C",
|
||||
icon: ThermometerIcon,
|
||||
desc: () => t`Triggers when any sensor exceeds a threshold`,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Retuns value of system host, truncating full path if socket.
|
||||
* @example
|
||||
* // Assuming system.host is "/var/run/beszel.sock"
|
||||
* const hostname = getHostDisplayValue(system) // hostname will be "beszel.sock"
|
||||
*/
|
||||
export const getHostDisplayValue = (system: SystemRecord): string => system.host.slice(system.host.lastIndexOf("/") + 1)
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ar\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Arabic\n"
|
||||
"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ar\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# يوم} other {# أيام}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# ساعة} other {# ساعات}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 ساعة"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 أسبوع"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 ساعة"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 ساعة"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 يومًا"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "إجراءات"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "التنبيهات النشطة"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "إضافة <0>نظام</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "إضافة نظام جديد"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "إضافة نظام"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "إضافة عنوان URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "تعديل خيارات العرض للرسوم البيانية."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "مسؤول"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "وكيل"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "التنبيهات"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "جميع الأنظمة"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "هل أنت متأكد أنك تريد حذف {name}؟"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "النسخ التلقائي يتطلب سياقًا آمنًا."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "متوسط"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "متوسط استخدام وحدة المعالجة المركزية للحاويات"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "المتوسط يتجاوز <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "متوسط استهلاك طاقة GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "متوسط استخدام وحدة المعالجة المركزية على مستوى النظام"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "متوسط استخدام {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "النسخ الاحتياطية"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "عرض النطاق الترددي"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "يدعم Beszel OpenID Connect والعديد من مزودي المصادقة OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "يستخدم Beszel <0>Shoutrrr</0> للتكامل مع خدمات الإشعارات الشهيرة."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "ثنائي"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "ذاكرة التخزين المؤقت / المخازن المؤقتة"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "إلغاء"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "تحذير - فقدان محتمل للبيانات"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "تغيير خيارات التطبيق العامة."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "خيارات الرسم البياني"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "تحقق من {email} للحصول على رابط إعادة التعيين."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "تحقق من السجلات لمزيد من التفاصيل."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "تحقق من خدمة الإشعارات الخاصة بك"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "انقر للنسخ"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "تعليمات سطر الأوامر"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "قم بتكوين كيفية تلقي إشعارات التنبيه."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "تأكيد كلمة المرور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "متابعة"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "تم النسخ إلى الحافظة"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "نسخ"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "نسخ المضيف"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "نسخ أمر لينكس"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "نسخ النص"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "المعالج"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "استخدام وحدة المعالجة المركزية"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "إنشاء حساب"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "داكن"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "لوحة التحكم"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "الفترة الزمنية الافتراضية"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "حذف"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "القرص"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "إدخال/إخراج القرص"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "استخدام القرص"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "استخدام القرص لـ {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "استخدام CPU لـ Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "استخدام الذاكرة لـ Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "إدخال/إخراج الشبكة لـ Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "التوثيق"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "البريد الإلكتروني"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "إشعارات البريد الإلكتروني"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "أدخل عنوان البريد الإلكتروني لإعادة تعيين كلمة المرور"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "أدخل عنوان البريد الإلكتروني..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "خطأ"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "يتجاوز {0}{1} في آخر {2, plural, one {# دقيقة} other {# دقائق}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "سيتم حذف الأنظمة الحالية غير المعرفة في <0>config.yml</0>. يرجى عمل نسخ احتياطية بانتظام."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "تصدير التكوين"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "تصدير تكوين الأنظمة الحالية الخاصة بك."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "فشل في المصادقة"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "فشل في حفظ الإعدادات"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "فشل في إرسال إشعار الاختبار"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "فشل في تحديث التنبيه"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "تصفية..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "لمدة <0>{min}</0> {min, plural, one {دقيقة} other {دقائق}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "هل نسيت كلمة المرور؟"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "عام"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "استهلاك طاقة GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "شبكة"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "مضيف / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "إذا فقدت كلمة المرور لحساب المسؤول الخاص بك، يمكنك إعادة تعيينها باستخدام الأمر التالي."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "عنوان البريد الإلكتروني غير صالح."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "كيرنل"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "اللغة"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "التخطيط"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "فاتح"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "تسجيل الخروج"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "تسجيل الدخول"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "فشل محاولة تسجيل الدخول"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "السجلات"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "هل تبحث عن مكان لإنشاء التنبيهات؟ انقر على أيقونات الجرس <0/> في جدول الأنظمة."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "إدارة تفضيلات العرض والإشعارات."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "1 دقيقة كحد"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "الذاكرة"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "استخدام الذاكرة"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "استخدام الذاكرة لحاويات Docker"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "الاسم"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "الشبكة"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "حركة مرور الشبكة لحاويات Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "حركة مرور الشبكة للواجهات العامة"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "لم يتم العثور على نتائج."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "لم يتم العثور على أنظمة."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "الإشعارات"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "دعم OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "في كل إعادة تشغيل، سيتم تحديث الأنظمة في قاعدة البيانات لتتطابق مع الأنظمة المعرفة في الملف."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "فتح القائمة"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "أو المتابعة باستخدام"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "الكتابة فوق التنبيهات الحالية"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "صفحة"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "الصفحات / الإعدادات"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "كلمة المرور"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "كلمة المرور يجب أن تتكون من 8 أحرف على الأقل."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "تم استلام طلب إعادة تعيين كلمة المرور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "إيقاف مؤقت"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "يرجى <0>تكوين خادم SMTP</0> لضمان تسليم التنبيهات."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "يرجى التحقق من السجلات لمزيد من التفاصيل."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "يرجى التحقق من بيانات الاعتماد الخاصة بك والمحاولة مرة أخرى"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "يرجى إنشاء حساب مسؤول"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "يرجى تمكين النوافذ المنبثقة لهذا الموقع"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "يرجى تسجيل الدخول مرة أخرى"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "يرجى الاطلاع على <0>التوثيق</0> للحصول على التعليمات."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "يرجى تسجيل الدخول إلى حسابك"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "المنفذ"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "الاستخدام الدقيق في الوقت المسجل"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "اللغة المفضلة"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "المفتاح العام"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "قراءة"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "تم الاستلام"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "إعادة تعيين كلمة المرور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "استئناف"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "احفظ العنوان باستخدام مفتاح الإدخال أو الفاصلة. اتركه فارغًا لتعطيل إشعارات البريد الإلكتروني."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "حفظ الإعدادات"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "بحث"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "البحث عن الأنظمة أو الإعدادات..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "راجع <0>إعدادات الإشعارات</0> لتكوين كيفية تلقي التنبيهات."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "تم الإرسال"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "يحدد النطاق الزمني الافتراضي للرسوم البيانية عند عرض النظام."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "الإعدادات"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "تم حفظ الإعدادات"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "تسجيل الدخول"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "إعدادات SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "الترتيب حسب"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "الحالة"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "مساحة التبديل المستخدمة من قبل النظام"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "استخدام التبديل"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "النظام"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "الأنظمة"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "يمكن إدارة الأنظمة في ملف <0>config.yml</0> داخل دليل البيانات الخاص بك."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "جدول"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "درجة الحرارة"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "درجات حرارة مستشعرات النظام"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "اختبار <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "تم إرسال إشعار الاختبار"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "يجب أن يكون الوكيل قيد التشغيل على النظام للاتصال. انسخ أمر التثبيت للوكيل أدناه."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "يجب أن يكون الوكيل قيد التشغيل على النظام للاتصال. انسخ <0>docker-compose.yml</0> للوكيل أدناه."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "ثم قم بتسجيل الدخول إلى الواجهة الخلفية وأعد تعيين كلمة مرور حساب المستخدم الخاص بك في جدول المستخدمين."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "لا يمكن التراجع عن هذا الإجراء. سيؤدي ذلك إلى حذف جميع السجلات الحالية لـ {name} من قاعدة البيانات بشكل دائم."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "معدل نقل {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "معدل نقل نظام الملفات الجذر"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "إلى البريد الإلكتروني"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "تبديل الشبكة"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "تبديل السمة"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما <20><>تجاوز أي مستشعر عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز الجمع بين الصعود/الهبوط عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام وحدة المعالجة المركزية عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام الذاكرة عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "يتم التفعيل عندما يتغير الحالة بين التشغيل والإيقاف"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام أي قرص عتبة معينة"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "محدث في الوقت الحقيقي. انقر على نظام لعرض المعلومات."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "مدة التشغيل"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "الاستخدام"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "استخدام القسم الجذر"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "مستخدم"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "المستخدمون"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "عرض"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "الأعمدة الظاهرة"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "في انتظار وجود سجلات كافية للعرض"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "هل تريد مساعدتنا في تحسين ترجماتنا؟ تحقق من <0>Crowdin</0> لمزيد من التفاصيل."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "إشعارات Webhook / Push"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "كتابة"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "تكوين YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "تكوين YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "تم تحديث إعدادات المستخدم الخاصة بك."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: bg\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Bulgarian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: bg\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# ден} other {# дни}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# час} other {# часа}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 час"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 седмица"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 часа"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 часа"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 дни"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Действия"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Активни тревоги"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Добави <0>Система</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Добави нова система"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Добави система"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Добави URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Настрой опциите за показване на диаграмите."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Администратор"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Агент"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Тревоги"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Всички системи"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Сигурен ли си, че искаш да изтриеш {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Автоматичното копиране изисква защитен контескт."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Средно"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Средно използване на процесора на контейнерите"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Средната стойност надхвърля <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Средна консумация на ток от графични карти"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Средно използване на процесора на цялата система"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Средно използване на {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Архиви"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandwidth на мрежата"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel поддържа OpenID Connect и много други OAuth2 доставчици за удостоверяване."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel ползва <0>Shoutrrr</0> за да се интегрира с известни услуги за уведомяване."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Двоичен код"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Кеш / Буфери"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Откажи"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Внимание - възможност за загуба на данни"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Смени общите опции на приложението."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Опции на диаграмата"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Провери {email} за линк за нулиране."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Провери log-овете за повече информация."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Провери услугата си за удостоверяване"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Настисни за да копираш"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Инструкции за командната линия"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Настрой как получаваш нотификации за тревоги."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Потвърди парола"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Продължи"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Записано в клипборда"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Копирай"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Копирай хоста"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Копирай linux командата"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Копирай текста"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "Процесор"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Употреба на процесор"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Създай акаунт"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Тъмно"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Табло"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Времеви диапазон по подразбиране"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Изтрий"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Диск"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Диск I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Използване на диск"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Изполване на диск от {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Използване на процесор от docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Изполване на памет от docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Мрежов I/O използван от docker"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Документация"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Имейл"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Имейл нотификации"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Въведи имейл адрес за да нулираш паролата"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Въведи имейл адрес..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Грешка"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Надвишава {0}{1} в последните {2, plural, one {# минута} other {# минути}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Съществуващи системи които не са дефинирани в <0>config.yml</0> ще бъдат изтрити. Моля прави чести архиви."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Експортирай конфигурация"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Експортирай конфигурацията на системите."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Неуспешно удостоверяване"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Неуспешно запазване на настройки"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Неуспешно изпрати тестова нотификация"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Неуспешно обнови тревога"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Филтрирай..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "За <0>{min}</0> {min, plural, one {минута} other {минути}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Забравена парола?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Общо"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Консумация на ток от графична карта"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Мрежово"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Хост / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Ако си загубил паролата до администраторския акаунт, можеш да я нулираш със следващата команда."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Невалиден имейл адрес."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Linux Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Език"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Подреждане"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Светъл"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Изход"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Вход"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Неуспешен опит за вход"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Логове"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Търсиш къде да създадеш тревоги? Натисни емотиконата за звънец <0/> в таблицата за системи."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Управление на предпочитанията за показване и уведомяване."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Максимум 1 минута"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Памет"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Употреба на паметта"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Използването на памет от docker контейнерите"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Име"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Мрежа"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Мрежов трафик на docker контейнери"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Мрежов трафик на публични интерфейси"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Няма намерени резултати."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Няма намерени системи."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Нотификации"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Поддръжка на OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "На всеки рестарт, системите в датабазата ще бъдат обновени да съвпадат със системите зададени във файла."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Отвори менюто"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Или продължи с"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Презапиши съществуващи тревоги"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Страница"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Страници / Настройки"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Парола"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Паролата трябва да е поне 8 символа."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Получено е искането за нулиране на паролата"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Пауза"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Моля <0>конфигурурай SMTP сървър</0> за да се подсигуриш, че тревогите са доставени."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Моля провери log-овете за повече информация."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Моля провери дадената информация и опитай отново"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Моля създай администраторски акаунт"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Моля активирай изскачащите прозорци за този сайт"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Моля влез отново"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Моля виж <0>документацията</0> за инструкции."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Моля влез в акаунта ти"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Точно използване в записаното време"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Предпочитан език"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Публичен ключ"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Прочети"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Получени"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Нулиране на парола"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Възобнови"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Запази адреса с enter или запетая. Остави празно за да изключиш нотификациите чрез имейл."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Запази настройките"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Търси"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Търси за системи или настройки..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Виж <0>настройките за нотификациите</0> за да конфигурираш как получаваш тревоги."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Изпратени"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Задава диапазона за време за диаграмите, когато се разглежда система."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Настройки"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Настройките са запазени"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Влез"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Настройки за SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Сортиране по"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Изполван swap от системата"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Използване на swap"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Система"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Системи"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Системите могат да бъдат управлявани в <0>config.yml</0> файл намиращ се в директорията с данни."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Таблица"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Температура"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Температири на системни сензори"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Тествай <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Тестова нотификация изпратена"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Агента трябва да работи на системата за да се свърже. Копирай инсталационната команда за агента долу."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Агемта трябва да работи на системата за да се свърже. Копирай <0>docker-compose.yml</0> файла за агента долу."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "След това влез в backend-а и нулирай паролата за потребителския акаунт в таблицата за потребители."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Това действие не може да бъде отменено. Това ще изтрие всички записи за {name} от датабазата."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Пропускателна способност на {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Пропускателна способност на root файловата система"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "До имейл(ите)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Превключване на мрежа"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Включи тема"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Задейства се, когато някой даден сензор надвиши зададен праг"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Задейства се, когато комбинираното качване/сваляне надвиши зададен праг"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Задейства се, когато употребата на процесора надвиши зададен праг"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Задейства се, когато употребата на паметта надвиши зададен праг"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Задейства се, когато статуса превключва между долу и горе"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Задейства се, когато употребата на някой диск надивши зададен праг"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Актуализира се в реално време. Натисни на система за да видиш информация."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Време на работа"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Употреба"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Употреба на root partition-а"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Използвани"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Потребители"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Изглед"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Видими полета"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Изчаква се за достатъчно записи за показване"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Искаш да помогнеш да направиш преводите още по-добри? Провери нашия <0>Crowdin</0> за повече детайли."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Пуш нотификации"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Запиши"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML конфигурация"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML конфигурация"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Настройките за потребителя ти са обновени."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: cs\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-14 00:50\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Czech\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: cs\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# den} few {# dny} other {# dní}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# Hodina} few {# Hodiny} many {# Hodin} other {# Hodin}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 hodina"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 týden"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 hodin"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 hodin"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dní"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Akce"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktivní výstrahy"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Přidat <0>Systém</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Přidat nový systém"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Přidat systém"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Přidat URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Upravit možnosti zobrazení pro grafy."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Výstrahy"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Všechny systémy"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Opravdu chcete odstranit {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatická kopie vyžaduje zabezpečený kontext."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Průměr"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Průměrné využití CPU kontejnerů"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Průměr je vyšší než <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Průměrná spotřeba energie GPU"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Průměrné využití CPU v celém systému"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Průměrné využití {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Zálohy"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Přenos"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel podporuje OpenID Connect a mnoho poskytovatelů OAuth2 ověřování."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel používá <0>Shoutrrr</0> k integraci s populárními notifikačními službami."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binary"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / vyrovnávací paměť"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Zrušit"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Upozornění - možná ztráta dat"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Změnit obecné nastavení aplikace."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Možnosti grafu"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Zkontrolujte {email} pro odkaz na obnovení."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Pro více informací zkontrolujte logy."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Zkontrolujte službu upozornění"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Klikněte pro zkopírování"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instrukce příkazového řádku"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfigurace způsobu přijímání upozornění."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Potvrdit heslo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Pokračovat"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Zkopírováno do schránky"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopírovat"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopírovat hostitele"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopírovat příkaz Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopírovat text"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "Procesor"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Využití procesoru"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Vytvořit účet"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Tmavý"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Přehled"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Výchozí doba"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Odstranit"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Využití disku"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Využití disku {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Využití CPU Dockeru"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Využití paměti Dockeru"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Síťové I/O Dockeru"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentace"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr "Nefunkční"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "Upravit"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Emailová upozornění"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Zadejte e-mailovou adresu pro obnovu hesla"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Zadejte e-mailovou adresu..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Chyba"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Překračuje {0}{1} za {2, plural, one {poslední # minutu} few {poslední # minuty} other {posledních # minut}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Stávající systémy, které nejsou definovány v <0>config.yml</0>, budou odstraněny. Provádějte pravidelné zálohování."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Exportovat konfiguraci"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exportovat aktuální konfiguraci systémů."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Ověření se nezdařilo"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Nepodařilo se uložit nastavení"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Nepodařilo se odeslat testovací oznámení"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Nepodařilo se aktualizovat upozornění"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filtr..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Za <0>{min}</0> {min, plural, one {minutu} few {minuty} other {minut}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Zapomněli jste heslo?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Obecné"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Spotřeba energie GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Mřížka"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Hostitel / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Pokud jste ztratili heslo k vašemu účtu správce, můžete jej obnovit pomocí následujícího příkazu."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Neplatná e-mailová adresa."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Jazyk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Rozvržení"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Světlý"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Odhlásit"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Přihlásit"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Pokus o přihlášení selhal"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logy"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Hledáte místo kde vytvářet upozornění? Klikněte na ikonu zvonku <0/> v systémové tabulce."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Správa nastavení zobrazení a oznámení."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr "Pokyny k manuálnímu nastavení"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max. 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Paměť"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Využití paměti"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Využití paměti docker kontejnerů"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Název"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Síť"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Síťový provoz kontejnerů docker"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Síťový provoz veřejných rozhraní"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Nenalezeny žádné výskyty."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Nenalezeny žádné systémy."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Upozornění"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Podpora OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Při každém restartu budou systémy v databázi aktualizovány tak, aby odpovídaly systémům definovaným v souboru."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Otevřít menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Nebo pokračujte s"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Přepsat existující upozornění"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Stránka"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Stránky / Nastavení"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Heslo"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Heslo musí obsahovat alespoň 8 znaků."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "Heslo musí být menší než 72 bytů."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Žádost o obnovu hesla byla přijata"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pozastavit"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr "Pozastaveno"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "<0>nakonfigurujte SMTP server</0> pro zajištění toho, aby byla upozornění doručena."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Pro více informací zkontrolujte logy."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Zkontrolujte prosím Vaše přihlašovací údaje a zkuste to znovu"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Vytvořte si prosím účet administrátora"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Prosím povolte vyskakovací okna pro tento web"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Přihlaste se prosím znovu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Instrukce naleznete v <0>dokumentaci</0>."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Přihlaste se prosím k vašemu účtu"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Přesné využití v zaznamenaném čase"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Upřednostňovaný jazyk"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Veřejný klíč"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Číst"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Přijato"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Obnovit heslo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Pokračovat"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Adresu uložte pomocí klávesy enter nebo čárky. Pro deaktivaci e-mailových oznámení ponechte prázdné pole."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Uložit nastavení"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr "Uložit systém"
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Hledat"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Hledat systémy nebo nastavení..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Podívejte se na <0>nastavení upozornění</0> pro nastavení toho, jak přijímáte upozornění."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Odeslat"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Nastaví výchozí časový rozsah grafů, když je systém zobrazen."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Nastavení"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Nastavení uloženo"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Přihlásit se"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Nastavení SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Seřadit podle"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Stav"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap prostor využívaný systémem"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap využití"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Systém"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systémy"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systémy lze spravovat v souboru <0>config.yml</0> uvnitř datového adresáře."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabulka"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr "Teplota"
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Teplota"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Teploty systémových senzorů"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testovací oznámení odesláno"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Agent musí být v systému spuštěn, aby se mohl připojit. Zkopírujte níže uvedený instalační příkaz pro agenta."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Agent musí být v systému spuštěn, aby se mohl připojit. Zkopírujte níže uvedený soubor<0>docker-compose.yml</0> pro agenta."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Poté se přihlaste do backendu a obnovte heslo k uživatelskému účtu v tabulce uživatelů."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Tuto akci nelze vzít zpět. Tím se z databáze trvale odstraní všechny aktuální záznamy pro {name}."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Propustnost {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Propustnost kořenového souborového systému"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Na email(y)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Přepnout mřížku"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Přepnout motiv"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Spustí se, když některý senzor překročí prahovou hodnotu"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Spustí se, když kombinace up/down překročí prahovou hodnotu"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Spustí se, když využití procesoru překročí prahovou hodnotu"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Spustí se, když využití paměti překročí prahovou hodnotu"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Spouští se, když se změní dostupnost"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Spustí se, když využití disku překročí prahovou hodnotu"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr "Funkční"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Aktualizováno v reálném čase. Klepnutím na systém zobrazíte informace."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Doba provozu"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Využití"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Využití kořenového oddílu"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Využito"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Uživatelé"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Zobrazení"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Viditelné sloupce"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Čeká se na dostatek záznamů k zobrazení"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Chcete nám pomoci s našimi překlady ještě lépe? Podívejte se na <0>Crowdin</0> pro více informací."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push oznámení"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Psát"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML konfigurace"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML konfigurace"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vaše uživatelská nastavení byla aktualizována."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: da\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Danish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: da\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# day} other {# days}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# hour} other {# hours}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 time"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 uge"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 timer"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 timer"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dage"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Handlinger"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktive Alarmer"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Tilføj <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Tilføj nyt system"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Tilføj system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Tilføj URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Juster visningsindstillinger for diagrammer."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Alarmer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Alle systemer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Er du sikker på, at du vil slette {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisk kopiering kræver en sikker kontekst."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Gennemsnitlig"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Gennemsnitlig CPU udnyttelse af containere"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Gennemsnit overstiger <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Gennemsnitligt strømforbrug for GPU'er"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Gennemsnitlig systembaseret CPU-udnyttelse"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Gennemsnitlig udnyttelse af {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Sikkerhedskopier"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Båndbredde"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel understøtter OpenID Connect og mange OAuth2 godkendelsesudbydere."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel bruger <0>Shoutrrr</0> til at integrere med populære notifikationstjenester."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binær"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffere"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Fortryd"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Forsigtig - muligt tab af data"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Skift generelle applikationsindstillinger."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Diagrammuligheder"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Tjek {email} for et nulstillingslink."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Tjek logfiler for flere detaljer."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Tjek din notifikationstjeneste"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Klik for at kopiere"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instruktioner for kommandolinje"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfigurer hvordan du modtager advarselsmeddelelser."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekræft adgangskode"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Forsæt"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Kopieret til udklipsholder"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopier"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopier host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopier Linux kommando"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopier tekst"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU forbrug"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Opret konto"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Mørk"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Oversigtspanel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Standard tidsperiode"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Slet"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Diskforbrug"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Diskforbrug af {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU forbrug"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Hukommelsesforbrug"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Netværk I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentation"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Email-notifikationer"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Indtast e-mailadresse for at nulstille adgangskoden"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Indtast e-mailadresse..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Fejl"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Overskrider {0}{1} i sidste {2, plural, one {# minut} other {# minutter}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Eksisterende systemer ikke defineret i <0>config.yml</0> vil blive slettet. Opret venligst regelmæssige sikkerhedskopier."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Eksporter konfiguration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Eksporter din nuværende systemkonfiguration."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Kunne ikke godkende"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Kunne ikke gemme indstillinger"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Afsendelse af testnotifikation mislykkedes"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Kunne ikke opdatere alarm"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "For <0>{min}</0> {min, plural, one {minut} other {minutter}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Glemt adgangskode?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Generelt"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Gpu Strøm Træk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Gitter"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Vært / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Hvis du har mistet adgangskoden til din administratorkonto, kan du nulstille den ved hjælp af følgende kommando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Ugyldig email adresse."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Sprog"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Layout"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Lys"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Log ud"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Log ind"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Loginforsøg mislykkedes"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Leder du i stedet for efter hvor du kan oprette alarmer? Klik på klokken <0/> ikoner i system tabellen."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Administrer display og notifikationsindstillinger."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks. 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Hukommelse"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Hukommelsesforbrug"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Hukommelsesforbrug af dockercontainere"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Navn"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Netværkstrafik af dockercontainere"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Netværkstrafik af offentlige grænseflader"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Ingen resultater fundet."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Ingen systemer fundet."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Notifikationer"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC understøttelse"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Ved hver genstart vil systemer i databasen blive opdateret til at matche de systemer, der er defineret i filen."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Åbn menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Eller fortsæt med"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overskriv eksisterende alarmer"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Side"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Sider / Indstillinger"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Adgangskode"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Adgangskoden skal være på mindst 8 tegn."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Anmodning om nulstilling af adgangskode modtaget"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Konfigurer <0>en SMTP server</0> for at sikre at alarmer bliver leveret."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Tjek logfiler for flere detaljer."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Tjek dine legitimationsoplysninger og prøv igen"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Opret venligst en administratorkonto"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Aktiver pop-ups for dette websted"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Log venligst ind igen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Se <0>dokumentationen</0> for instruktioner."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Log venligst ind på din konto"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Præcis udnyttelse på det registrerede tidspunkt"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Foretrukket sprog"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Offentlig nøgle"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Læs"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Modtaget"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Nulstil adgangskode"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Genoptag"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Gem adresse ved hjælp af enter eller komma. Lad feltet stå tomt for at deaktivere e-mail-meddelelser."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Gem indstillinger"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Søg"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Søg efter systemer eller indstillinger..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Se <0>meddelelsesindstillinger</0> for at konfigurere, hvordan du modtager alarmer."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Sendt"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Sætter standardtidsintervallet for diagrammer når et system vises."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Indstillinger"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Indstillinger gemt"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Log ind"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP-indstillinger"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sorter efter"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap plads brugt af systemet"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap forbrug"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systemer"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systemer kan være administreres i filen <0>config.yml</0> i din datamappe."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabel"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturer i systemsensorer"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Test notifikation sendt"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Agenten skal køre på systemet for at forbinde. Kopier installationskommandoen for agenten nedenfor."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Agenten skal køre på systemet for at forbinde. Kopier <0>docker-compose.yml</0> for agenten nedenfor."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Log derefter ind på backend og nulstil adgangskoden til din brugerkonto i tabellen brugere."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Denne handling kan ikke fortrydes. Dette vil permanent slette alle aktuelle elementer for {name} fra databasen."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Gennemløb af {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Gennemløb af rodfilsystemet"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Til email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Slå gitter til/fra"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Skift tema"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Udløser når en sensor overstiger en tærskel"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Udløses når de kombinerede op/ned overstiger en tærskel"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Udløser når CPU-forbrug overstiger en tærskel"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Udløser når hukommelsesforbruget overstiger en tærskel"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Udløser når status skifter mellem op og ned"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Udløser når brugen af en disk overstiger en tærskel"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Opdateret i realtid. Klik på et system for at se information."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Oppetid"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Forbrug"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Brug af rodpartition"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Brugt"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Brugere"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Vis"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Synlige felter"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Venter på nok posteringer til at vise"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Vil du hjælpe os med at gøre vores oversættelser endnu bedre? Tjek <0>Crowdin</0> for flere detaljer."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push notifikationer"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Skriv"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML Konfiguration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Konfiguration"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Dine brugerindstillinger er opdateret."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: de\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# Tag} other {# Tage}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# Stunde} other {# Stunden}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 Stunde"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 Woche"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 Stunden"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 Stunden"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 Tage"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Aktionen"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktive Warnungen"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>System</0> hinzufügen"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Neues System hinzufügen"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "System hinzufügen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "URL hinzufügen"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Anzeigeoptionen für Diagramme anpassen."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Warnungen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Alle Systeme"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Möchtest du {name} wirklich löschen?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisches Kopieren erfordert einen sicheren Kontext."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Durchschnitt"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Durchschnittliche CPU-Auslastung der Container"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Durchschnitt überschreitet <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Durchschnittlicher Stromverbrauch der GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Durchschnittliche systemweite CPU-Auslastung"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Durchschnittliche Auslastung von {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandbreite"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel unterstützt OpenID Connect und viele OAuth2-Authentifizierungsanbieter."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel verwendet <0>Shoutrrr</0>, um sich mit beliebten Benachrichtigungsdiensten zu integrieren."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binär"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Puffer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Vorsicht - potenzieller Datenverlust"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Allgemeine Anwendungsoptionen ändern."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Diagrammoptionen"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Überprüfe {email} auf einen Link zum Zurücksetzen."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Überprüfe die Protokolle für weitere Details."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Überprüfe deinen Benachrichtigungsdienst"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Zum Kopieren klicken"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Befehlszeilenanweisungen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfiguriere, wie du Warnbenachrichtigungen erhältst."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Passwort bestätigen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Fortfahren"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "In die Zwischenablage kopiert"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopieren"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Host kopieren"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linux-Befehl kopieren"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Text kopieren"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU-Auslastung"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Konto erstellen"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Dunkel"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Standardzeitraum"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Festplatte"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Festplatten-I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Festplattennutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Festplattennutzung von {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker-CPU-Auslastung"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker-Arbeitsspeichernutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker-Netzwerk-I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentation"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "Bearbeiten"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "E-Mail"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "E-Mail-Benachrichtigungen"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "E-Mail-Adresse eingeben, um das Passwort zurückzusetzen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "E-Mail-Adresse eingeben..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Fehler"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Überschreitet {0}{1} in den letzten {2, plural, one {# Minute} other {# Minuten}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Bestehende Systeme, die nicht in der <0>config.yml</0> definiert sind, werden gelöscht. Bitte mache regelmäßige Backups."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Konfiguration exportieren"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exportiere die aktuelle Systemkonfiguration."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Authentifizierung fehlgeschlagen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Einstellungen konnten nicht gespeichert werden"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Testbenachrichtigung konnte nicht gesendet werden"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Warnung konnte nicht aktualisiert werden"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Für <0>{min}</0> {min, plural, one {Minute} other {Minuten}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Passwort vergessen?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Allgemein"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU-Leistungsaufnahme"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Raster"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Wenn du das Passwort für dein Administratorkonto verloren hast, kannst du es mit dem folgenden Befehl zurücksetzen."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Ungültige E-Mail-Adresse."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Sprache"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Anordnung"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Hell"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Abmelden"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Anmeldeversuch fehlgeschlagen"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Protokolle"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Du möchtest neue Warnungen erstellen? Klicke dafür auf die Glocken-<0/>-Symbole in der Systemtabelle."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Anzeige- und Benachrichtigungseinstellungen verwalten."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 Min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Arbeitsspeicher"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Arbeitsspeichernutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Arbeitsspeichernutzung der Docker-Container"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Netz"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Netzwerkverkehr der Docker-Container"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Netzwerkverkehr der öffentlichen Schnittstellen"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Keine Ergebnisse gefunden."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Keine Systeme gefunden."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Benachrichtigungen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC-Unterstützung"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Bei jedem Neustart werden die Systeme in der Datenbank aktualisiert, um den in der Datei definierten Systemen zu entsprechen."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Menü öffnen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Oder fortfahren mit"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Bestehende Warnungen überschreiben"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Seite"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Seiten / Einstellungen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Das Passwort muss mindestens 8 Zeichen haben."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "Das Passwort muss weniger als 72 Bytes lang sein."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Anfrage zum Zurücksetzen des Passworts erhalten"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Bitte <0>konfiguriere einen SMTP-Server</0>, um sicherzustellen, dass Warnungen zugestellt werden."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Bitte überprüfe die Protokolle für weitere Details."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Bitte überprüfe deine Anmeldedaten und versuche es erneut"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Bitte erstelle ein Administratorkonto"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Bitte aktiviere Pop-ups für diese Seite"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Bitte melde dich erneut an"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "In der <0>Dokumentation</0> findest du weitere Anweisungen."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Bitte melde dich bei beinem Konto an"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Genaue Nutzung zum aufgezeichneten Zeitpunkt"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Bevorzugte Sprache"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Schlüssel"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Lesen"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Empfangen"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Passwort zurücksetzen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Fortsetzen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Adresse mit der Enter-Taste oder Komma speichern. Leer lassen, um E-Mail-Benachrichtigungen zu deaktivieren."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Einstellungen speichern"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Suche"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Nach Systemen oder Einstellungen suchen..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Siehe <0>Benachrichtigungseinstellungen</0>, um zu konfigurieren, wie du Warnungen erhältst."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Gesendet"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Legt den Standardzeitraum für Diagramme fest, wenn ein System angezeigt wird."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Einstellungen gespeichert"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP-Einstellungen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sortieren nach"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Vom System genutzter Swap-Speicher"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap-Nutzung"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systeme"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systeme können in einer <0>config.yml</0>-Datei im Datenverzeichnis verwaltet werden."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabelle"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturen der Systemsensoren"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testbenachrichtigung gesendet"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Der Agent muss auf dem System laufen, um eine Verbindung herzustellen. Kopiere den Installationsbefehl für den Agent unten."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Der Agent muss auf dem System laufen, um eine Verbindung herzustellen. Kopiere die <0>docker-compose.yml</0> für den Agent unten."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Melde dich dann im Backend an und setze dein Benutzerkontopasswort in der Benutzertabelle zurück."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Diese Aktion kann nicht rückgängig gemacht werden. Dadurch werden alle aktuellen Datensätze für {name} dauerhaft aus der Datenbank gelöscht."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Durchsatz von {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Durchsatz des Root-Dateisystems"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "An E-Mail(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Raster umschalten"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Darstellung umschalten"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Löst aus, wenn ein Sensor einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die kombinierte Auf-/Abwärtsbewegung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die CPU-Auslastung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die Arbeitsspeichernutzung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Löst aus, wenn der Status zwischen online und offline wechselt"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die Nutzung einer Festplatte einen Schwellenwert überschreitet"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "In Echtzeit aktualisiert. Klicke auf ein System, um Informationen anzuzeigen."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Betriebszeit"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Nutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Nutzung der Root-Partition"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Verwendet"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Ansicht"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Sichtbare Spalten"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Warten auf genügend Datensätze zur Anzeige"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Möchtest du uns helfen, unsere Übersetzungen noch besser zu machen? Schau dir <0>Crowdin</0> für weitere Details an."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push-Benachrichtigungen"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Schreiben"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML-Konfiguration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML-Konfiguration"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Deine Benutzereinstellungen wurden aktualisiert."
|
||||
@@ -1,866 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: en\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# day} other {# days}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# hour} other {# hours}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 hour"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 week"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 hours"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 hours"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 days"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Actions"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Active Alerts"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Add <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Add New System"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Add system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Add URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Adjust display options for charts."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Alerts"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "All Systems"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Are you sure you want to delete {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatic copy requires a secure context."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Average"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Average CPU utilization of containers"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Average exceeds <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Average power consumption of GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Average system-wide CPU utilization"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Average utilization of {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandwidth"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binary"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Caution - potential data loss"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Change general application options."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Chart options"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Check {email} for a reset link."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Check logs for more details."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Check your notification service"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Click to copy"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Command line instructions"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configure how you receive alert notifications."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirm password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Continue"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copied to clipboard"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Copy"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Copy host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copy Linux command"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copy text"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU Usage"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Create account"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Dark"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Default time period"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Delete"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Disk Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Disk usage of {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Memory Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Network I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Documentation"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr "Down"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "Edit"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Email notifications"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Enter email address to reset password"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Enter email address..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Export configuration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Export your current systems configuration."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Failed to authenticate"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Failed to save settings"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Failed to send test notification"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Failed to update alert"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Forgot password?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU Power Draw"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Grid"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Invalid email address."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Language"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Layout"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Light"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Log Out"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Login"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Login attempt failed"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Manage display and notification preferences."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr "Manual setup instructions"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Memory"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Memory Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Memory usage of docker containers"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Network traffic of docker containers"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Network traffic of public interfaces"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "No results found."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "No systems found."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Notifications"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC support"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Open menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Or continue with"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overwrite existing alerts"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Page"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Pages / Settings"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Password must be at least 8 characters."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "Password must be less than 72 bytes."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Password reset request received"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr "Paused"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Please check logs for more details."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Please check your credentials and try again"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Please create an admin account"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Please enable pop-ups for this site"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Please log in again"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Please see <0>the documentation</0> for instructions."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Please sign in to your account"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Precise utilization at the recorded time"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferred Language"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Public Key"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Read"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Received"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Reset Password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Resume"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Save Settings"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr "Save system"
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Search"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Search for systems or settings..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "See <0>notification settings</0> to configure how you receive alerts."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Sent"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Sets the default time range for charts when a system is viewed."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Settings saved"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Sign in"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP settings"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sort By"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap space used by the system"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap Usage"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systems"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Table"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperature"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatures of system sensors"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Test notification sent"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Then log into the backend and reset your user account password in the users table."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Throughput of {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Throughput of root filesystem"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "To email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Toggle grid"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Toggle theme"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Triggers when any sensor exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Triggers when combined up/down exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Triggers when CPU usage exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Triggers when memory usage exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Triggers when status switches between up and down"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Triggers when usage of any disk exceeds a threshold"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr "Up"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Updated in real time. Click on a system to view information."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Usage of root partition"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Used"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Users"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "View"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Visible Fields"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Waiting for enough records to display"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push notifications"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Write"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML Config"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Configuration"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Your user settings have been updated."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: es\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: es-ES\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# día} other {# días}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# hora} other {# horas}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 hora"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 semana"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 horas"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 horas"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 días"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Acciones"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertas Activas"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Agregar <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Agregar Nuevo Sistema"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Agregar sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Agregar URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Ajustar las opciones de visualización para los gráficos."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Administrador"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Alertas"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Todos los Sistemas"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "¿Está seguro de que desea eliminar {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copia automática requiere un contexto seguro."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Promedio"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilización promedio de CPU de los contenedores"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "El promedio excede <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Consumo de energía promedio de GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilización promedio de CPU del sistema"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Uso promedio de {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Copias de Seguridad"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Ancho de banda"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel admite OpenID Connect y muchos proveedores de autenticación OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel utiliza <0>Shoutrrr</0> para integrarse con servicios populares de notificación."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binario"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Caché / Buffers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Precaución - posible pérdida de datos"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Cambiar las opciones generales de la aplicación."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opciones de Gráficos"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Revise {email} para un enlace de restablecimiento."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Revise los registros para más detalles."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Verifique su servicio de notificaciones"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Haga clic para copiar"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instrucciones de línea de comandos"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configure cómo recibe las notificaciones de alertas."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar contraseña"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Continuar"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copiado al portapapeles"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Copiar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Copiar host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copiar comando de Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copiar texto"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Uso de CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Crear cuenta"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Oscuro"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Tablero"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Período de tiempo predeterminado"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Eliminar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "E/S de Disco"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Uso de Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Uso de disco de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Uso de CPU de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Uso de Memoria de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "E/S de Red de Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Documentación"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr "Abajo"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "Editar"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Correo electrónico"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Notificaciones por correo"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Ingrese la dirección de correo electrónico para restablecer la contraseña"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Ingrese dirección de correo..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Excede {0}{1} en el último {2, plural, one {# minuto} other {# minutos}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Los sistemas existentes no definidos en <0>config.yml</0> serán eliminados. Por favor, haga copias de seguridad regularmente."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Exportar configuración"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exporte la configuración actual de sus sistemas."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Error al autenticar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Error al guardar la configuración"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Error al enviar la notificación de prueba"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Error al actualizar la alerta"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrar..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Por <0>{min}</0> {min, plural, one {minuto} other {minutos}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "¿Olvidó su contraseña?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo de energía de la GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Cuadrícula"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Si ha perdido la contraseña de su cuenta de administrador, puede restablecerla usando el siguiente comando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Dirección de correo electrónico no válida."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Idioma"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Diseño"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Claro"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Cerrar Sesión"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Iniciar sesión"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Intento de inicio de sesión fallido"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Registros"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "¿Busca dónde crear alertas? Haga clic en los iconos de campana <0/> en la tabla de sistemas."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Administrar preferencias de visualización y notificaciones."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr "Instrucciones manuales de configuración"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Máx 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Memoria"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Uso de Memoria"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Uso de memoria de los contenedores de Docker"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Red"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Tráfico de red de los contenedores de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Tráfico de red de interfaces públicas"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "No se encontraron resultados."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "No se encontraron sistemas."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Notificaciones"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Soporte para OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "En cada reinicio, los sistemas en la base de datos se actualizarán para coincidir con los sistemas definidos en el archivo."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Abrir menú"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "O continuar con"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sobrescribir alertas existentes"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Página"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Páginas / Configuraciones"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Contraseña"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "La contraseña debe tener al menos 8 caracteres."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "La contraseña debe ser menor de 72 bytes."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Solicitud de restablecimiento de contraseña recibida"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pausar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Por favor, <0>configure un servidor SMTP</0> para asegurar que las alertas sean entregadas."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Por favor, revise los registros para más detalles."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Por favor, verifique sus credenciales e intente de nuevo"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Por favor, cree una cuenta de administrador"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Por favor, habilite las ventanas emergentes para este sitio"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Por favor, inicie sesión de nuevo"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Por favor, consulte <0>la documentación</0> para obtener instrucciones."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Por favor, inicie sesión en su cuenta"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Puerto"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilización precisa en el momento registrado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Idioma Preferido"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Clave Pública"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Lectura"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Recibido"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Restablecer Contraseña"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Reanudar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Guarde la dirección usando la tecla enter o coma. Deje en blanco para desactivar las notificaciones por correo."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Guardar Configuración"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr "Guardar Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Buscar sistemas o configuraciones..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Consulte <0>configuración de notificaciones</0> para configurar cómo recibe alertas."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Enviado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Establece el rango de tiempo predeterminado para los gráficos cuando se visualiza un sistema."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Configuración"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Configuración guardada"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Iniciar sesión"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Configuración SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Ordenar por"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espacio de swap utilizado por el sistema"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Uso de Swap"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemas"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Los sistemas pueden ser gestionados en un archivo <0>config.yml</0> dentro de su directorio de datos."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabla"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturas de los sensores del sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Probar <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notificación de prueba enviada"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "El agente debe estar ejecutándose en el sistema para conectarse. Copie el comando de instalación para el agente a continuación."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "El agente debe estar ejecutándose en el sistema para conectarse. Copie el <0>docker-compose.yml</0> para el agente a continuación."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Luego inicie sesión en el backend y restablezca la contraseña de su cuenta de usuario en la tabla de usuarios."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Esta acción no se puede deshacer. Esto eliminará permanentemente todos los registros actuales de {name} de la base de datos."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Rendimiento de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Rendimiento del sistema de archivos raíz"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "A correo(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Alternar cuadrícula"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Alternar tema"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Se activa cuando cualquier sensor supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Se activa cuando la suma de subida/bajada supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Se activa cuando el uso de CPU supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Se activa cuando el uso de memoria supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Se activa cuando el estado cambia entre activo e inactivo"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Se activa cuando el uso de cualquier disco supera un umbral"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr "Activo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Actualizado en tiempo real. Haga clic en un sistema para ver la información."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Tiempo de actividad"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Uso"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Uso de la partición raíz"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Usado"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Usuarios"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Vista"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Columnas visibles"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Esperando suficientes registros para mostrar"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "¿Quieres ayudarnos a mejorar nuestras traducciones? Consulta <0>Crowdin</0> para más detalles."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notificaciones Webhook / Push"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Escritura"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "Configuración YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuración YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Su configuración de usuario ha sido actualizada."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: fa\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Persian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: fa\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# روز} other {# روز}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# ساعت} other {# ساعت}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "۱ ساعت"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "۱ هفته"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "۱۲ ساعت"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "۲۴ ساعت"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "۳۰ روز"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "عملیات"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr " هشدارهای فعال"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "افزودن <0>سیستم</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "افزودن سیستم جدید"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "افزودن سیستم"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "افزودن آدرس اینترنتی"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "تنظیم گزینههای نمایش برای نمودارها."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "مدیر"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "عامل"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "هشدارها"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "همه سیستمها"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "آیا مطمئن هستید که میخواهید {name} را حذف کنید؟"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "کپی خودکار نیاز به یک زمینه امن دارد."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "میانگین"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "میانگین استفاده از CPU کانتینرها"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "میانگین مصرف برق پردازندههای گرافیکی"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "میانگین استفاده از CPU در کل سیستم"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "میانگین استفاده از {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "پشتیبانگیریها"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "پهنای باند"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "بِزل از OpenID Connect و بسیاری از ارائهدهندگان احراز هویت OAuth2 پشتیبانی میکند."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "بِزل از <0>Shoutrrr</0> برای ادغام با سرویسهای اطلاعرسانی محبوب استفاده میکند."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "دودویی"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "حافظه پنهان / بافرها"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "لغو"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "احتیاط - احتمال از دست رفتن دادهها"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "تغییر گزینههای کلی برنامه."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "گزینههای نمودار"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "ایمیل {email} خود را برای لینک بازنشانی بررسی کنید."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "برای جزئیات بیشتر، لاگها را بررسی کنید."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "سرویس اطلاعرسانی خود را بررسی کنید"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "برای کپی کردن کلیک کنید"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "دستورالعملهای خط فرمان"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "نحوه دریافت هشدارهای اطلاعرسانی را پیکربندی کنید."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "تأیید رمز عبور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "ادامه"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "در کلیپبورد کپی شد"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "کپی"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "کپی میزبان"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "کپی دستور لینوکس"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "کپی متن"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "پردازنده"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "میزان استفاده از پردازنده"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "ایجاد حساب کاربری"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "تیره"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "داشبورد"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "بازه زمانی پیشفرض"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "حذف"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "دیسک"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "ورودی/خروجی دیسک"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "میزان استفاده از دیسک"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "میزان استفاده از دیسک {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "میزان استفاده از CPU داکر"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "میزان استفاده از حافظه داکر"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "ورودی/خروجی شبکه داکر"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "مستندات"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "ایمیل"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "اعلانهای ایمیلی"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "آدرس ایمیل را برای بازنشانی رمز عبور وارد کنید"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "آدرس ایمیل را وارد کنید..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "خطا"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "در {2, plural, one {# دقیقه} other {# دقیقه}} گذشته از {0}{1} بیشتر است"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "سیستمهای موجود که در <0>config.yml</0> تعریف نشدهاند حذف خواهند شد. لطفاً به طور منظم پشتیبانگیری کنید."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "خارج کردن پیکربندی"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "پیکربندی سیستمهای فعلی خود را خارج کنید."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "احراز هویت ناموفق بود"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "ذخیره تنظیمات ناموفق بود"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "ارسال اعلان آزمایشی ناموفق بود"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "بهروزرسانی هشدار ناموفق بود"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "فیلتر..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "برای <0>{min}</0> {min, plural, one {دقیقه} other {دقیقه}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "رمز عبور را فراموش کردهاید؟"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "عمومی"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "مصرف برق پردازنده گرافیکی"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "جدول"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "میزبان / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "اگر رمز عبور حساب مدیر خود را گم کردهاید، میتوانید آن را با استفاده از دستور زیر بازنشانی کنید."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "آدرس ایمیل نامعتبر است."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "هسته"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "زبان"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "طرحبندی"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "روشن"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "خروج"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "ورود"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "تلاش برای ورود ناموفق بود"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "لاگها"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "به دنبال جایی برای ایجاد هشدار هستید؟ روی آیکونهای زنگ <0/> در جدول سیستمها کلیک کنید."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "مدیریت تنظیمات نمایش و اعلانها."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "حداکثر ۱ دقیقه"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "حافظه"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "میزان استفاده از حافظه"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "میزان استفاده از حافظه کانتینرهای داکر"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "نام"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "شبکه"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "ترافیک شبکه کانتینرهای داکر"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "ترافیک شبکه رابطهای عمومی"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "هیچ نتیجهای یافت نشد."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "هیچ سیستمی یافت نشد."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "اعلانها"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "پشتیبانی از OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "در هر بار راهاندازی مجدد، سیستمهای موجود در پایگاه داده با سیستمهای تعریف شده در فایل مطابقت داده میشوند."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "باز کردن منو"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "یا ادامه با"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "بازنویسی هشدارهای موجود"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "صفحه"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "صفحات / تنظیمات"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "رمز عبور"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "رمز عبور باید حداقل ۸ کاراکتر باشد."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "درخواست بازنشانی رمز عبور دریافت شد"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "توقف"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "لطفاً برای اطمینان از تحویل هشدارها، یک <0>سرور SMTP پیکربندی کنید</0>."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "لطفاً برای جزئیات بیشتر، لاگها را بررسی کنید."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "لطفاً اعتبارنامههای خود را بررسی کرده و دوباره تلاش کنید."
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "لطفاً یک حساب مدیر ایجاد کنید"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "لطفاً پنجرههای بازشو را برای این سایت فعال کنید"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "لطفاً دوباره وارد شوید"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "لطفاً برای دستورالعملها به <0>مستندات</0> مراجعه کنید."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "لطفاً به حساب کاربری خود وارد شوید"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "پورت"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "میزان دقیق استفاده در زمان ثبت شده"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "زبان ترجیحی"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "کلید عمومی"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "خواندن"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "دریافت شد"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "بازنشانی رمز عبور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "ادامه"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "آدرس را با استفاده از کلید Enter یا کاما ذخیره کنید. برای غیرفعال کردن اعلانهای ایمیلی، خالی بگذارید."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "ذخیره تنظیمات"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "جستجو"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "جستجو برای سیستمها یا تنظیمات..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "برای پیکربندی نحوه دریافت هشدارها، به <0>تنظیمات اعلان</0> مراجعه کنید."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "ارسال شد"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "بازه زمانی پیشفرض برای نمودارها هنگام مشاهده یک سیستم را تعیین میکند."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "تنظیمات"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "تنظیمات ذخیره شد"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "ورود"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "تنظیمات SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "مرتبسازی بر اساس"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "وضعیت"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "فضای Swap استفاده شده توسط سیستم"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "میزان استفاده از Swap"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "سیستم"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "سیستمها"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "سیستمها ممکن است در یک فایل <0>config.yml</0> درون دایرکتوری داده شما مدیریت شوند."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "جدول"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "دما"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "دمای حسگرهای سیستم"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "تست <0>آدرس اینترنتی</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "اعلان آزمایشی ارسال شد"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "برای اتصال، عامل باید روی سیستم در حال اجرا باشد. دستور نصب عامل را از زیر کپی کنید."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "برای اتصال، عامل باید روی سیستم در حال اجرا باشد. <0>docker-compose.yml</0> مربوط به عامل را از زیر کپی کنید."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "سپس وارد بخش پشتیبان شوید و رمز عبور حساب کاربری خود را در جدول کاربران بازنشانی کنید."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "این عمل قابل برگشت نیست. این کار تمام رکوردهای فعلی {name} را برای همیشه از پایگاه داده حذف خواهد کرد."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "توان عملیاتی {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "توان عملیاتی سیستم فایل ریشه"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "به ایمیل(ها)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "تغییر نمایش جدول"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "تغییر تم"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "هنگامی که هر حسگری از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "هنگامی که مجموع بالا/پایین از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "هنگامی که میزان استفاده از CPU از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "هنگامی که میزان استفاده از حافظه از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "هنگامی که وضعیت بین بالا و پایین تغییر میکند، فعال میشود"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "هنگامی که استفاده از هر دیسکی از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "به صورت لحظهای بهروزرسانی میشود. برای مشاهده اطلاعات، روی یک سیستم کلیک کنید."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "آپتایم"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "میزان استفاده"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "میزان استفاده از پارتیشن ریشه"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "استفاده شده"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "کاربران"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "مشاهده"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "فیلدهای قابل مشاهده"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "در انتظار رکوردهای کافی برای نمایش"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "میخواهید به ما کمک کنید تا ترجمههای خود را بهتر کنیم؟ برای جزئیات بیشتر به <0>Crowdin</0> مراجعه کنید."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "اعلانهای Webhook / Push"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "نوشتن"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "پیکربندی YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "پیکربندی YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "تنظیمات کاربری شما بهروزرسانی شد."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: fr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: fr\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# jour} other {# jours}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# heure} other {# heures}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 heure"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 semaine"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 heures"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 heures"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 jours"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Actions"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertes actives"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Ajouter <0>Système</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Ajouter un nouveau système"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Ajouter un système"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Ajouter URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Ajuster les options d'affichage pour les graphiques."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Alertes"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Tous les systèmes"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer {name} ?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copie automatique nécessite un contexte sécurisé."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Moyenne"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilisation moyenne du CPU des conteneurs"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "La moyenne dépasse <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Consommation d'énergie moyenne des GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilisation moyenne du CPU à l'échelle du système"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Utilisation moyenne de {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Sauvegardes"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bande passante"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel prend en charge OpenID Connect et de nombreux fournisseurs d'authentification OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel utilise <0>Shoutrrr</0> pour s'intégrer aux services de notification populaires."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binaire"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Tampons"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Attention - perte de données potentielle"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Modifier les options générales de l'application."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Options de graphique"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Vérifiez {email} pour un lien de réinitialisation."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Vérifiez les journaux pour plus de détails."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Vérifiez votre service de notification"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Cliquez pour copier"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instructions en ligne de commande"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configurez comment vous recevez les notifications d'alerte."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmer le mot de passe"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Continuer"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copié dans le presse-papiers"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Copier"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Copier l'hôte"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copier la commande Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copier le texte"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Utilisation du CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Créer un compte"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Sombre"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Tableau de bord"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Période par défaut"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disque"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Entrée/Sortie disque"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Utilisation du disque"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Utilisation du disque de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Utilisation du CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Utilisation de la mémoire Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Entrée/Sortie réseau Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Documentation"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Notifications par email"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Entrez l'adresse email pour réinitialiser le mot de passe"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Entrez l'adresse email..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Erreur"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Dépasse {0}{1} dans {2, plural, one {la dernière # minute} other {les dernières # minutes}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Les systèmes existants non définis dans <0>config.yml</0> seront supprimés. Veuillez faire des sauvegardes régulières."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Exporter la configuration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exportez la configuration actuelle de vos systèmes."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Échec de l'authentification"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Échec de l'enregistrement des paramètres"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Échec de l'envoi de la notification de test"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Échec de la mise à jour de l'alerte"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrer..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Pour <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Mot de passe oublié ?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Général"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consommation du GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Grille"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Hôte / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Si vous avez perdu le mot de passe de votre compte administrateur, vous pouvez le réinitialiser en utilisant la commande suivante."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Adresse email invalide."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Noyau"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Langue"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Disposition"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Clair"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Connexion"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Échec de la tentative de connexion"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Journaux"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Vous cherchez plutôt où créer des alertes ? Cliquez sur les icônes de cloche <0/> dans le tableau des systèmes."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gérer les préférences d'affichage et de notification."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Mémoire"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Utilisation de la mémoire"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilisation de la mémoire des conteneurs Docker"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Trafic réseau des conteneurs Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Trafic réseau des interfaces publiques"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Aucun résultat trouvé."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Aucun système trouvé."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Notifications"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Support OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "À chaque redémarrage, les systèmes dans la base de données seront mis à jour pour correspondre aux systèmes définis dans le fichier."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Ouvrir le menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Ou continuer avec"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Écraser les alertes existantes"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Page"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Pages / Paramètres"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Le mot de passe doit contenir au moins 8 caractères."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Demande de réinitialisation du mot de passe reçue"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Veuillez <0>configurer un serveur SMTP</0> pour garantir la livraison des alertes."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Veuillez vérifier les journaux pour plus de détails."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Veuillez vérifier vos identifiants et réessayer"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Veuillez créer un compte administrateur"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Veuillez activer les pop-ups pour ce site"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Veuillez vous reconnecter"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Veuillez consulter <0>la documentation</0> pour les instructions."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Veuillez vous connecter à votre compte"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilisation précise au moment enregistré"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Langue préférée"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Clé publique"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Lecture"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Reçu"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Réinitialiser le mot de passe"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Reprendre"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enregistrez l'adresse en utilisant la touche Entrée ou la virgule. Laissez vide pour désactiver les notifications par email."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Enregistrer les paramètres"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Rechercher des systèmes ou des paramètres..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Voir les <0>paramètres de notification</0> pour configurer comment vous recevez les alertes."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Envoyé"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Définit la plage de temps par défaut pour les graphiques lorsqu'un système est consulté."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Paramètres enregistrés"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Se connecter"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Paramètres SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Trier par"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Statut"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espace Swap utilisé par le système"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Utilisation du swap"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Système"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systèmes"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Les systèmes peuvent être gérés dans un fichier <0>config.yml</0> à l'intérieur de votre répertoire de données."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tableau"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Température"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Températures des capteurs du système"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Tester <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notification de test envoyée"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "L'agent doit être en cours d'exécution sur le système pour se connecter. Copiez la commande d'installation pour l'agent ci-dessous."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "L'agent doit être en cours d'exécution sur le système pour se connecter. Copiez le <0>docker-compose.yml</0> pour l'agent ci-dessous."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Ensuite, connectez-vous au backend et réinitialisez le mot de passe de votre compte utilisateur dans la table des utilisateurs."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Cette action ne peut pas être annulée. Cela supprimera définitivement tous les enregistrements actuels pour {name} de la base de données."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Débit de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Débit du système de fichiers racine"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Aux email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Basculer la grille"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Changer le thème"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque tout capteur dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque le montant/descendant combinée dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation du CPU dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation de la mémoire dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Déclenchement lorsque le statut passe d'opérationnel à indisponible"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation de tout disque dépasse un seuil"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Mis à jour en temps réel. Cliquez sur un système pour voir les informations."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Temps de fonctionnement"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Utilisation"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Utilisation de la partition racine"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Utilisé"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Utilisateurs"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Vue"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Colonnes visibles"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "En attente de suffisamment d'enregistrements à afficher"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Vous voulez nous aider à améliorer nos traductions ? Consultez <0>Crowdin</0> pour plus de détails."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notifications Webhook / Push"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Écriture"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "Configuration YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuration YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vos paramètres utilisateur ont été mis à jour."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: hr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Croatian\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: hr\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dan} other {# dani}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# sat} other {# sati}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 sat"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 tjedan"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 sati"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 sati"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dana"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Akcije"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktivna upozorenja"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Dodaj <0>Sistem</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Dodaj Novi Sistem"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Dodaj sistem"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Dodaj URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Podesite opcije prikaza za grafikone."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Upozorenja"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Svi Sistemi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Jeste li sigurni da želite izbrisati {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatsko kopiranje zahtijeva siguran kontekst."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Prosjek"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Prosječna iskorištenost procesora u spremnicima"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Prosjek premašuje <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Prosječna iskorištenost procesora na cijelom sustavu"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Sigurnosne kopije"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Propusnost"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel podržava OpenID Connect i mnoge druge OAuth2 davatalje autentifikacije."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel koristi <0>Shoutrrr</0> za integraciju sa popularnim servisima za notifikacije."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binarni"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Predmemorija / Međuspremnici"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Otkaži"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Oprez - mogući gubitak podataka"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Promijenite opće opcije aplikacije."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opcije grafikona"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Provjerite {email} za vezu za resetiranje."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Provjerite logove za više detalja."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Provjerite Vaš servis notifikacija"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Pritisnite za kopiranje"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Upute za naredbeni redak"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfigurirajte način primanja obavijesti upozorenja."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Potvrdite lozinku"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Nastavite"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Kopirano u međuspremnik"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopiraj"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopiraj hosta"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiraj Linux komandu"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiraj tekst"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "Procesor"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Iskorištenost procesora"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Napravite račun"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Tamno"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Nadzorna ploča"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Zadano vremensko razdoblje"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Izbriši"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Iskorištenost Diska"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Iskorištenost diska od {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Iskorištenost Docker Procesora"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Iskorištenost Docker Memorije"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Mrežni I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentacija"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Email notifikacije"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Unesite email adresu za resetiranje lozinke"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Unesite email adresu..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Greška"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Premašuje {0}{1} u posljednjih {2, plural, one {# minuta} other {# minute}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Postojeći sistemi koji nisu definirani u <0>config.yml</0> će biti izbrisani. Molimo Vas napravite redovite sigurnosne kopije."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Izvoz konfiguracije"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Izvoz trenutne sistemske konfiguracije."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Provjera autentičnosti nije uspjela"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Neuspješno snimanje postavki"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Neuspješno slanje testne notifikacije"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Ažuriranje upozorenja nije uspjelo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Za <0>{min}</0> {min, plural, one {minutu} other {minute}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Zaboravljena lozinka?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Općenito"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Mreža"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Ako ste izgubili lozinku za svoj administratorski račun, možete ju resetirati pomoću sljedeće naredbe."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Nevažeća adresa e-pošte."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Jezik"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Izgled"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Svijetlo"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Odjava"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Prijava"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Pokušaj prijave nije uspio"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logovi"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Tražite gdje stvoriti upozorenja? Kliknite ikonu zvona <0/> u tablici sustava."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Upravljajte postavkama prikaza i obavijesti."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maksimalno 1 minuta"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Memorija"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Upotreba memorije"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Upotreba memorije Docker spremnika"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Ime"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Mreža"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Mrežni promet Docker spremnika"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Mrežni promet javnih sučelja"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Nema rezultata."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Nije pronađen nijedan sustav."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Obavijesti"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Podrška za OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Prilikom svakog ponovnog pokretanja, sustavi u bazi podataka biti će ažurirani kako bi odgovarali sustavima definiranim u datoteci."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Otvori menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Ili nastavi sa"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Prebrišite postojeća upozorenja"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Stranica"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Stranice / Postavke"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Lozinka"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Lozinka mora imati najmanje 8 znakova."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Zahtjev za ponovno postavljanje lozinke primljen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pauza"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Molimo <0>konfigurirajte SMTP server</0> kako biste osigurali isporuku upozorenja."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Za više detalja provjerite logove."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Provjerite svoje podatke i pokušajte ponovno"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Molimo kreirajte administratorski račun"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Omogućite skočne prozore za ovu stranicu"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Molimo prijavite se ponovno"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Molimo pogledajte <0>dokumentaciju</0> za instrukcije."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Molimo prijavite se u svoj račun"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Precizno iskorištenje u zabilježenom vremenu"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferirani jezik"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Javni Ključ"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Pročitaj"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Primljeno"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Resetiraj Lozinku"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Nastavi"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Spremite adresu pomoću tipke enter ili zareza. Ostavite prazno kako biste onemogućili obavijesti e-poštom."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Spremi Postavke"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Pretraži"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Pretraži za sisteme ili postavke..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Pogledajte <0>postavke obavijesti</0> da biste konfigurirali način primanja upozorenja."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Poslano"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Postavlja zadani vremenski raspon za grafikone kada se sustav gleda."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Postavke"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Postavke spremljene"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Prijava"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP postavke"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sortiraj po"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap prostor uzet od strane sistema"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap Iskorištenost"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Sistem"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemi"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Sistemima se može upravljati u <0>config.yml</0> datoteci unutar data direktorija."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tablica"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperature sistemskih senzora"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Testni <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testna obavijest poslana"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Agent mora biti pokrenut na sistemu da bi se spojio. Kopirajte instalacijske komande za agenta ispod."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Agent mora biti pokrenut na sistemu da bi se spojio. Kopirajte <0>docker-compose.yml</0> za agenta ispod."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Zatim se prijavite u backend i resetirajte lozinku korisničkog računa u tablici korisnika."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Ova radnja se ne može poništiti. Ovo će trajno izbrisati sve trenutne zapise za {name} iz baze podataka."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Protok {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Protok root datotečnog sustava"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Primaoci e-pošte"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Uključi/isključi rešetku"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Uključi/isključi temu"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Pokreće se kada bilo koji senzor prijeđe prag"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Pokreće se kada kombinacija gore/dolje premaši prag"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Pokreće se kada iskorištenost procesora premaši prag"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Pokreće se kada iskorištenost memorije premaši prag"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Pokreće se kada se status sistema promijeni"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Pokreće se kada iskorištenost bilo kojeg diska premaši prag"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Ažurirano odmah. Kliknite na sistem za više informacija."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Vrijeme rada"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Iskorištenost"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Iskorištenost root datotečnog sustava"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Iskorišteno"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Korisnici"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Prikaz"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Vidljiva polja"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Čeka se na više podataka prije prikaza"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Želite li nam pomoći da naše prijevode učinimo još boljim? Posjetite <0>Crowdin</0> za više detalja."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push obavijest"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Piši"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML Config"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Konfiguracija"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vaše korisničke postavke su ažurirane."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: hu\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Hungarian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: hu\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# nap} other {# nap}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# óra} other {# óra}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 óra"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 hét"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 óra"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 óra"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 nap"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Műveletek"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktív riasztások"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Hozzáadás <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Új rendszer hozzáadása"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Rendszer hozzáadása"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "URL hozzáadása"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Állítsa be a diagram megjelenítését."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Ügynök"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Riasztások"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Minden rendszer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Biztosan törölni szeretnéd {name}-t?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Az automatikus másolás biztonságos környezetet igényel."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Átlag"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Konténerek átlagos CPU kihasználtsága"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Az átlag meghaladja a <0>{value}{0}</0> értéket"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "GPU-k átlagos energiafogyasztása"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Rendszerszintű CPU átlagos kihasználtság"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "{0} átlagos kihasználtsága"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Biztonsági mentések"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Sávszélesség"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "A Beszel támogatja az OpenID Connect-et és számos OAuth2 hitelesítési szolgáltatót."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "A Beszel a <0>Shoutrrr</0>-t használja a népszerű értesítési szolgáltatások integrálására."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Bináris"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Gyorsítótár / Pufferelések"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Mégsem"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Figyelem - potenciális adatvesztés"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Általános alkalmazásbeállítások módosítása."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Diagram beállítások"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Ellenőrizd a {email} címet a visszaállító linkért."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Ellenőrizd a naplót a további részletekért."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Ellenőrizd az értesítési szolgáltatásodat"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Kattints a másoláshoz"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Parancssori utasítások"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfiguráld, hogyan kapod az értesítéseket."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Jelszó megerősítése"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Tovább"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Vágólapra másolva"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Másolás"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Hoszt másolása"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linux parancs másolása"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Szöveg másolása"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU használat"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Fiók létrehozása"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Sötét"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Áttekintés"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Alapértelmezett időszak"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Törlés"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Lemez"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Lemez I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Lemezhasználat"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Lemezhasználat a {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU használat"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker memória használat"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker hálózat I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentáció"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "E-mail értesítések"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "E-mail cím megadása a jelszó visszaállításához"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Adja meg az e-mail címet..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Hiba"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Túllépi a {0}{1} értéket az elmúlt {2, plural, one {# percben} other {# percben}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "A <0>config.yml</0> fájlban nem definiált meglévő rendszerek törlésre kerülnek. Kérjük, készítsen rendszeres biztonsági mentéseket."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Konfiguráció exportálása"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exportálja a jelenlegi rendszerkonfigurációt."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Hitelesítés sikertelen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Nem sikerült menteni a beállításokat"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Teszt értesítés elküldése sikertelen"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Nem sikerült frissíteni a riasztást"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Szűrő..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "A <0>{min}</0> {min, plural, one {perc} other {percek}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Elfelejtette a jelszavát?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Általános"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU áramfelvétele"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Rács"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Állomás / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Ha elvesztette az admin fiók jelszavát, a következő paranccsal állíthatja vissza."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Érvénytelen e-mail cím."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Nyelv"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Elrendezés"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Világos"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Kijelentkezés"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Bejelentkezés"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Bejelentkezés sikertelen"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Naplók"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Inkább azt keresi, hogy hol hozhat létre riasztásokat? Kattintson a csengő <0/> ikonokra a rendszerek táblázatában."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "A megjelenítési és értesítési beállítások kezelése."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maximum 1 perc"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "RAM"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Memóriahasználat"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker konténerek memória használata"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Név"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Hálózat"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Docker konténerek hálózati forgalma"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Nyilvános interfészek hálózati forgalma"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Nincs találat."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Nem található rendszer."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Értesítések"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC támogatás"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Minden újraindításkor az adatbázisban lévő rendszerek frissítésre kerülnek, hogy megfeleljenek a fájlban meghatározott rendszereknek."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Menü megnyitása"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Vagy folytasd ezzel"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Felülírja a meglévő riasztásokat"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Oldal"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Oldalak / Beállítások"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Jelszó"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "A jelszónak legalább 8 karakternek kell lennie."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Jelszó-visszaállítási kérelmet kaptunk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Szüneteltetés"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Kérjük, <0>konfigurálj egy SMTP szervert</0> az értesítések kézbesítésének biztosítása érdekében."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Kérjük, ellenőrizd a naplókat a további részletekért."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Kérjük, ellenőrizze a hitelesítő adatait, és próbálja újra"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Kérjük, hozzon létre egy admin fiókot"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Kérjük, engedélyezze a felugró ablakokat ezen az oldalon"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Kérjük jelentkezz be újra"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Kérjük, nézze meg <0>a dokumentációt</0> az utasításokért."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Kérjük, jelentkezzen be a fiókjába"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Pontos kihasználás a rögzített időpontban"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferált nyelv"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Nyilvános kulcs"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Olvasás"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Fogadott"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Jelszó visszaállítása"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Folytatás"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Mentse el a címet az Enter billentyű vagy a vessző használatával. Hagyja üresen az e-mail értesítések letiltásához."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Beállítások mentése"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Keresés"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Keresés rendszerek vagy beállítások után..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Lásd <0>az értesítési beállításokat</0>, hogy konfigurálja, hogyan kap értesítéseket."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Elküldve"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Beállítja az alapértelmezett időtartamot a diagramokhoz, amikor egy rendszert néznek."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Beállítások"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Beállítások elmentve"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Bejelentkezés"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP beállítások"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Rendezés"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Állapot"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Rendszer által használt swap terület"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap használat"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Rendszer"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Rendszer"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "A rendszereket egy <0>config.yml</0> fájlban lehet kezelni az adatkönyvtárban."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tábla"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Hőmérséklet"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "A rendszer érzékelőinek hőmérséklete"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Teszt <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Teszt értesítés elküldve"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "A csatlakozáshoz az ügynöknek futnia kell a rendszerben. Másolja ki az alábbi telepítési parancsot az ügynök telepítéséhez."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "A csatlakozáshoz az ügynöknek futnia kell a rendszerben. Másolja az<0>docker-compose.yml</0> fájlt az ügynök futtatásához."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Ezután jelentkezzen be a backendbe, és állítsa vissza a felhasználói fiók jelszavát a felhasználók táblázatban."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Ezt a műveletet nem lehet visszavonni! Véglegesen törli a {name} összes jelenlegi rekordját az adatbázisból!"
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "A {extraFsName} átviteli teljesítménye"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "A gyökér fájlrendszer átviteli teljesítménye"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "E-mailben"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Rács ki- és bekapcsolása"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Téma váltása"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha bármelyik érzékelő túllép egy küszöbértéket"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha bármelyik érzékelő túllép egy küszöbértéket"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha a CPU érzékelő túllép egy küszöbértéket"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha a Ram érzékelő túllép egy küszöbértéket"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Bekapcsol, amikor az állapot fel és le között változik"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha a lemez érzékelő túllép egy küszöbértéket"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Valós időben frissítve. Kattintson egy rendszerre az információk megtekintéséhez."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Üzemidő"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Használat"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Root partíció kihasználtsága"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Felhasznált"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Felhasználók"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Nézet"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Látható mezők"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Elegendő rekordra várva a megjelenítéshez"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Szeretne segíteni nekünk abban, hogy fordításaink még jobbak legyenek? További részletekért nézze meg a <0>Crowdin</0> honlapot."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push értesítések"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Írás"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML konfiguráció"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML konfiguráció"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "A felhasználói beállítások frissítésre kerültek."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: is\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Icelandic\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: is\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dagur} other {# dagar}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# klukkustund} other {# klukkustundir}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 klukkustund"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 vika"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 klukkustundir"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 klukkustundir"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dagar"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Aðgerðir"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Virkar tilkynningar"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Bæta við <0>Kerfi</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Bæta við nýju kerfi"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Bæta við kerfi"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Bæta við léni"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Tilkynningar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Öll kerfi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Ertu viss um að þú viljir eyða {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Sjálfvisk afritun krefst öruggs samhengis."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Meðal"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Meðal örgjörva notkun container-a."
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Meðaltal er yfir <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Meðal orkunotkun skjákorta"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Meðal nýting örgjörva yfir allt kerfið"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Meðal notkun af {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Öryggisafrit"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Gangnaflutningsgeta"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel styður OpenID Connect og margar OAuth2 auðkenningarveitendur."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel notar <0>Shoutrrr</0> til að tengjast vinsælum tilkynningaþjónustum."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binary"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Skyndiminni / Biðminni"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Hætta við"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Aðvörun - möguleiki á gagnatapi"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Breyta almennum stillingum."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Valkostir fyrir línurit"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Skoðaðu {email} fyrir endurstillingar lén."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Skoðaðu logga til að sjá meiri upplýsingar."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Athugaðu tilkynningaþjónustuna þína"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Smelltu til að afrita"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Skipanalínu leiðbeiningar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Stilltu hvernig þú vilt fá tilkynningar."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Staðfestu lykilorð"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Halda áfram"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Afritað í klippiborð"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Afrita"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Afrita host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Afrita Linux aðgerð"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Afrita texta"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "Örgjörvi"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Örgjörva notkun"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Búa til aðgang"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Dökkt"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Yfirlitssíða"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Sjálfgefið tímabil"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Eyða"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Diskur"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Diskanotkun"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Diska notkun af {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU notkun"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Minnisnotkun Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Skjal"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Netfang"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Tilkynningar í tölvupósti"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Settu netfang til að endursetja lykilorð"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Settu inn Netfang..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Villa"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Fór yfir {0}{1} á síðustu {2, plural, one {# mínútu} other {# mínútum}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Villa í auðkenningu"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Villa við að vista stillingar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Villa í sendingu prufu skilaboða"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Mistókst að uppfæra tilkynningu"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Sía..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Gleymt lykilorð?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Almennt"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Skjákorts rafmagnsnotkun"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Ógilt netfang."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Tungumál"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr ""
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Ljóst"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Útskrá"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Innskrá"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Innskránings tilraun misheppnaðist"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Loggar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Mest 1 mínúta"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Minni"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Minnisnotkun"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Minnisnotkun docker kerfa"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Nafn"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Net traffík docker kerfa"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Engar niðurstöður fundust."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Engin kerfi fundust."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Tilkynningar"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC stuðningur"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Opna valmynd"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Eða halda áfram með"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Yfirskrifa núverandi tilkynningu"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Síða"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Síða / Stillingar"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Lykilorð"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Lykilorðið verður að vera minnst 8 stafir."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Beiðni um að endurstilla lykilorð móttekin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pása"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Skoðaðu logga til að sjá meiri upplýsingar."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Vinsamlegast farðu yfir upplýsingarnar þínar og reyndu aftur"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Vinsamlegast búðu til admin aðgang"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Vinsamlegast skráðu þið inn aftur"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Vinsamlegast skoðaðu <0>skjölin</0> fyrir leiðbeiningar."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Vinsamlegast skráðu þig inn á aðganginn þinn"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Valið tungumál"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Dreifilykill"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Lesa"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Móttekið"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Endurstilla lykilorð"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Halda áfram"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Vista stillingar"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Leita"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Leita að kerfum eða stillingum..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr ""
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Sent"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Stillingar"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Stillingar vistaðar"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Innskrá"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP stillingar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Raða eftir"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Staða"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Skipti minni"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Kerfi"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Kerfi"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tafla"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Hitastig"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Hitastig kerfa skynjara"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Prufa <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Prufu tilkynning send"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Skráðu þig þá inní bakendann og endurstilltu lykilorðið þitt inni í notenda töflunni."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Þessi aðgerð er óafturkvæmanleg. Þetta mun eyða gögnum fyrir {name} varanlega úr gagnagrunninum."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Til tölvupósta"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Velja þema"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Virkjast þegar einhver skynjari fer yfir þröskuld"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Virkjast þegar samanlagt sent/móttekið fer yfir þröskuld"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Virkjast þegar örgjörva notkun fer yfir þröskuld"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Virkjast þegar minnisnotkun fer yfir þröskuld"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Virkjast þegar staða breytist milli virkur og óvirkur"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Virkjast þegar diska notkun fer yfir þröskuld"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Uppfærist í rauntíma. Veldu kerfi til að skoða upplýsingar."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Notað"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Notendur"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Skoða"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Sjáanlegir reitir"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Bíður eftir nægum upplýsingum til að sýna"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Tilkynningar"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Skrifa"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Notenda stillingar vistaðar."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: it\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Italian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: it\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# giorno} other {# giorni}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# ora} other {# ore}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 ora"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 settimana"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 ore"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 ore"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 giorni"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Azioni"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Avvisi Attivi"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Aggiungi <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Aggiungi Nuovo Sistema"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Aggiungi sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Aggiungi URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Regola le opzioni di visualizzazione per i grafici."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Amministratore"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Avvisi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Tutti i Sistemi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Sei sicuro di voler eliminare {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copia automatica richiede un contesto sicuro."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Media"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilizzo medio della CPU dei container"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "La media supera <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Consumo energetico medio delle GPU"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilizzo medio della CPU a livello di sistema"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Utilizzo medio di {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Backup"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Larghezza di banda"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel supporta OpenID Connect e molti provider di autenticazione OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel utilizza <0>Shoutrrr</0> per integrarsi con i servizi di notifica popolari."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binario"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Attenzione - possibile perdita di dati"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Modifica le opzioni generali dell'applicazione."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opzioni del grafico"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Controlla {email} per un link di reset."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Controlla i log per maggiori dettagli."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Controlla il tuo servizio di notifica"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Clicca per copiare"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Istruzioni da riga di comando"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configura come ricevere le notifiche di avviso."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Conferma password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Continua"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copiato negli appunti"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Copia"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Copia host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copia comando Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copia testo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Utilizzo CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Crea account"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Scuro"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Cruscotto"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Periodo di tempo predefinito"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Elimina"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "I/O Disco"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Utilizzo Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Utilizzo del disco di {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Utilizzo CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Utilizzo Memoria Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "I/O di Rete Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Documentazione"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Notifiche email"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Inserisci l'indirizzo email per reimpostare la password"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Inserisci l'indirizzo email..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Errore"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Supera {0}{1} negli ultimi {2, plural, one {# minuto} other {# minuti}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "I sistemi esistenti non definiti in <0>config.yml</0> verranno eliminati. Si prega di effettuare backup regolari."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Esporta configurazione"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Esporta la configurazione attuale dei tuoi sistemi."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Autenticazione fallita"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Salvataggio delle impostazioni fallito"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Invio della notifica di test fallito"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Aggiornamento dell'avviso fallito"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filtra..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Per <0>{min}</0> {min, plural, one {minuto} other {minuti}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Password dimenticata?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Generale"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo della GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Griglia"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Se hai perso la password del tuo account amministratore, puoi reimpostarla utilizzando il seguente comando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Indirizzo email non valido."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Lingua"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Aspetto"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Chiaro"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Disconnetti"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Accedi"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Tentativo di accesso fallito"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Log"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Cerchi invece dove creare avvisi? Clicca sulle icone della campana <0/> nella tabella dei sistemi."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gestisci le preferenze di visualizzazione e notifica."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Memoria"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Utilizzo Memoria"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilizzo della memoria dei container Docker"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Rete"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Traffico di rete dei container Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Traffico di rete delle interfacce pubbliche"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Nessun risultato trovato."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Nessun sistema trovato."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Notifiche"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Supporto OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Ad ogni riavvio, i sistemi nel database verranno aggiornati per corrispondere ai sistemi definiti nel file."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Apri menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Oppure continua con"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sovrascrivi avvisi esistenti"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Pagina"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Pagine / Impostazioni"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "La password deve contenere almeno 8 caratteri."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Richiesta di reimpostazione password ricevuta"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pausa"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Si prega di <0>configurare un server SMTP</0> per garantire la consegna degli avvisi."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Si prega di controllare i log per maggiori dettagli."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Si prega di controllare le credenziali e riprovare"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Si prega di creare un account amministratore"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Si prega di abilitare i pop-up per questo sito"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Si prega di accedere nuovamente"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Si prega di consultare <0>la documentazione</0> per le istruzioni."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Si prega di accedere al proprio account"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilizzo preciso al momento registrato"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Lingua Preferita"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Chiave Pub"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Lettura"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Ricevuto"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Reimposta Password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Riprendi"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Salva l'indirizzo usando il tasto invio o la virgola. Lascia vuoto per disabilitare le notifiche email."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Salva Impostazioni"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Cerca"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Cerca sistemi o impostazioni..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Vedi <0>impostazioni di notifica</0> per configurare come ricevere gli avvisi."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Inviato"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Imposta l'intervallo di tempo predefinito per i grafici quando viene visualizzato un sistema."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Impostazioni"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Impostazioni salvate"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Accedi"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Impostazioni SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Ordina per"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Stato"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Spazio di swap utilizzato dal sistema"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Utilizzo Swap"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemi"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "I sistemi possono essere gestiti in un file <0>config.yml</0> all'interno della tua directory dati."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabella"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperature dei sensori di sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notifica di test inviata"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "L'agente deve essere in esecuzione sul sistema per connettersi. Copia il comando di installazione per l'agente qui sotto."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "L'agente deve essere in esecuzione sul sistema per connettersi. Copia il<0>docker-compose.yml</0> per l'agente qui sotto."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Quindi accedi al backend e reimposta la password del tuo account utente nella tabella degli utenti."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Questa azione non può essere annullata. Questo eliminerà permanentemente tutti i record attuali per {name} dal database."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Throughput di {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Throughput del filesystem root"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "A email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Attiva/disattiva griglia"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Attiva/disattiva tema"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Attiva quando un sensore supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Attiva quando il combinato up/down supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo della CPU supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo della memoria supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Attiva quando lo stato passa tra up e down"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo di un disco supera una soglia"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Aggiornato in tempo reale. Clicca su un sistema per visualizzare le informazioni."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Tempo di attività"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Utilizzo"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Utilizzo della partizione root"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Utilizzato"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Utenti"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Vista"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Colonne visibili"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "In attesa di abbastanza record da visualizzare"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Vuoi aiutarci a migliorare ulteriormente le nostre traduzioni? Dai un'occhiata a <0>Crowdin</0> per maggiori dettagli."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notifiche Webhook / Push"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Scrittura"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "Configurazione YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configurazione YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Le impostazioni utente sono state aggiornate."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ja\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-13 10:13\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Japanese\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ja\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 日} other {# 日}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# 時間} other {# 時間}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1時間"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1週間"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12時間"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24時間"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30日間"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "アクション"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "アクティブなアラート"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>システム</0>を追加"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "新しいシステムを追加"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "システムを追加"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "URLを追加"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "チャートの表示オプションを調整します。"
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "管理者"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "エージェント"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "アラート"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "すべてのシステム"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "{name}を削除してもよろしいですか?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "自動コピーには安全なコンテキストが必要です。"
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "平均"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "コンテナの平均CPU使用率"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "平均が<0>{value}{0}</0>を超えています"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "GPUの平均消費電力"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "システム全体の平均CPU使用率"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "{0}の平均使用率"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "バックアップ"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "帯域幅"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "BeszelはOpenID Connectと多くのOAuth2認証プロバイダーをサポートしています。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszelは<0>Shoutrrr</0>を使用して、人気のある通知サービスと統合します。"
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "バイナリ"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "キャッシュ / バッファ"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "キャンセル"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "注意 - データ損失の可能性"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "一般的なアプリケーションオプションを変更します。"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "チャートオプション"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "{email}を確認してリセットリンクを探してください。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "詳細についてはログを確認してください。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "通知サービスを確認してください"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "クリックしてコピー"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "コマンドラインの指示"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "アラート通知の受信方法を設定します。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "パスワードを確認"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "続行"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "クリップボードにコピーされました"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "コピー"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "ホストをコピー"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linuxコマンドをコピー"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "テキストをコピー"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU使用率"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "アカウントを作成"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "ダーク"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "ダッシュボード"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "デフォルトの期間"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "削除"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "ディスク"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "ディスクI/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "ディスク使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}のディスク使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Dockerメモリ使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "DockerネットワークI/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "ドキュメント"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr "停止"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "編集"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "メール"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "メール通知"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "パスワードをリセットするためにメールアドレスを入力してください"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "メールアドレスを入力..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "エラー"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "過去{2, plural, one {# 分} other {# 分}}で{0}{1}を超えています"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "<0>config.yml</0>に定義されていない既存のシステムは削除されます。定期的にバックアップを作成してください。"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "設定をエクスポート"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "現在のシステム設定をエクスポートします。"
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "認証に失敗しました"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "設定の保存に失敗しました"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "テスト通知の送信に失敗しました"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "アラートの更新に失敗しました"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "フィルター..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "<0>{min}</0> {min, plural, one {分} other {分}}の間"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "パスワードをお忘れですか?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "一般"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPUの消費電力"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "グリッド"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "ホスト / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "管理者アカウントのパスワードを忘れた場合は、次のコマンドを使用してリセットできます。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "無効なメールアドレスです。"
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "カーネル"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "言語"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "レイアウト"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "ライト"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "ログアウト"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "ログイン"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "ログイン試行に失敗しました"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "ログ"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "アラートを作成する場所を探していますか?システムテーブルのベル<0/>アイコンをクリックしてください。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "表示と通知の設定を管理します。"
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr "手動セットアップの手順"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "最大1分"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "メモリ"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "メモリ使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Dockerコンテナのメモリ使用率"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "名前"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "帯域"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Dockerコンテナのネットワークトラフィック"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "パブリックインターフェースのネットワークトラフィック"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "結果が見つかりませんでした。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "システムが見つかりませんでした。"
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "通知"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDCサポート"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "再起動のたびに、データベース内のシステムはファイルに定義されたシステムに一致するように更新されます。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "メニューを開く"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "または、以下の方法でログイン"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "既存のアラートを上書き"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "ページ"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "ページ / 設定"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "パスワード"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "パスワードは8文字以上である必要があります。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "パスワードは72バイト未満でなければなりません。"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "パスワードリセットのリクエストを受け取りました"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "一時停止"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr "一時停止中"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "アラートが配信されるように<0>SMTPサーバーを設定</0>してください。"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "詳細についてはログを確認してください。"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "資格情報を確認して再試行してください"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "管理者アカウントを作成してください"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "このサイトのポップアップを有効にしてください"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "再度ログインしてください"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "手順については<0>ドキュメント</0>を参照してください。"
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "アカウントにサインインしてください"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "ポート"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "記録された時点での正確な利用"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "優先言語"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "公開鍵"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "読み取り"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "受信"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "パスワードをリセット"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "再開"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enterキーまたはカンマを使用してアドレスを保存します。空白のままにするとメール通知が無効になります。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "設定を保存"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr "システムを保存"
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "検索"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "システムまたは設定を検索..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "アラートの受信方法を設定するには<0>通知設定</0>を参照してください。"
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "送信"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "システムを表示する際のチャートのデフォルトの時間範囲を設定します。"
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "設定が保存されました"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "サインイン"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP設定"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "並び替え基準"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "ステータス"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "システムが使用するスワップ領域"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "スワップ使用量"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "システム"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "システム"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "システムはデータディレクトリ内の<0>config.yml</0>ファイルで管理できます。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "テーブル"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr "温度"
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "温度"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "システムセンサーの温度"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "テスト<0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "テスト通知が送信されました"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "接続するにはエージェントがシステム上で実行されている必要があります。以下のエージェントのインストールコマンドをコピーしてください。"
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "接続するにはエージェントがシステム上で実行されている必要があります。以下のエージェント用<0>docker-compose.yml</0>をコピーしてください。"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "その後、バックエンドにログインして、ユーザーテーブルでユーザーアカウントのパスワードをリセットしてください。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "この操作は元に戻せません。これにより、データベースから{name}のすべての現在のレコードが永久に削除されます。"
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}のスループット"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "ルートファイルシステムのスループット"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "宛先メールアドレス"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "グリッドを切り替え"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "テーマを切り替え"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "センサーがしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "上り/下りの合計がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "CPU使用率がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "メモリ使用率がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "ステータスが上から下に切り替わるときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "ディスクの使用量がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr "正常"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "リアルタイムで更新されます。システムをクリックして情報を表示します。"
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "稼働時間"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "使用量"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "ルートパーティションの使用量"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "使用中"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "ユーザー"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "表示"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "表示列"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "表示するのに十分なレコードを待っています"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "翻訳をさらに良くするためにご協力いただけますか?詳細については<0>Crowdin</0>をご覧ください。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / プッシュ通知"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "書き込み"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML設定"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML設定"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "ユーザー設定が更新されました。"
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ko\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-07 10:06\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Korean\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ko\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 일} other {# 일}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# 시간} other {# 시간}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1시간"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1주"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12시간"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24시간"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30일"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "작업"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "활성화된 알림들"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>시스템</0> 추가"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "새 시스템 추가"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "시스템 추가"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "URL 추가"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "차트 표시 옵션 변경."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "관리자"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "에이전트"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "알림"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "모든 시스템"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "{name}을(를) 삭제하시겠습니까?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "자동 복사는 안전한 컨텍스트가 필요합니다."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "평균"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "컨테이너의 평균 CPU 사용량"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "평균이 <0>{value}{0}</0>을(를) 초과합니다"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "GPU들의 평균 전원 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "시스템 전체의 평균 CPU 사용량"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "평균 {0} 사용량"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "백업"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "대역폭"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel은 OpenID Connect 및 많은 OAuth2 인증 제공자를 지원합니다."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel은 여러 인기 있는 알림 서비스와 연동하기 위해 <0>Shoutrrr</0>을 이용합니다."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "실행 파일"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "캐시 / 버퍼"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "취소"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "주의 - 데이터 손실 가능성"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "일반 애플리케이션 옵션 변경."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "차트 옵션"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "{email}에서 재설정 링크를 확인하세요."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "자세한 내용은 로그를 확인하세요."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "알림 서비스를 확인하세요."
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "클릭하여 복사"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "명령어 사용 지침"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "알림을 수신할 방법을 설정하세요."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "비밀번호 확인"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "계속"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "클립보드에 복사됨"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "복사"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "호스트 복사"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "리눅스 명령어 복사"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "텍스트 복사"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU 사용량"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "계정 생성"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "어둡게"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "대시보드"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "기본 기간"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "삭제"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "디스크"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "디스크 I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "디스크 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}의 디스크 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker 메모리 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker 네트워크 I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "문서"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr "오프라인"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "수정"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "이메일"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "이메일 알림"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "비밀번호를 재설정하려면 이메일 주소를 입력하세요"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "이메일 주소 입력..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "오류"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "마지막 {2, plural, one {# 분} other {# 분}} 동안 {0}{1} 초과"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "<0>config.yml</0>에 정의되지 않은 기존 시스템은 삭제됩니다. 정기적으로 백업을 하세요."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "구성 내보내기"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "현재 시스템 구성 내보내기"
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "인증 실패"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "설정 저장 실패"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "테스트 알림 전송 실패"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "알림 수정 실패"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "필터..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "<0>{min}</0> {min, plural, one {분} other {분}} 동안"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "비밀번호를 잊으셨나요?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "일반"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU 전원 사용량"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "그리드"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "호스트 / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "관리자 계정의 비밀번호를 잃어버린 경우, 다음 명령어를 사용하여 재설정할 수 있습니다."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "잘못된 이메일 주소입니다."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "커널"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "언어"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "레이아웃"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "밝게"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "로그아웃"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "로그인"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "로그인 실패"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "로그"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "알림을 생성하려 하시나요? 시스템 테이블의 종 <0/> 아이콘을 클릭하세요."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "디스플레이 및 알림 설정"
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr "수동 설정 방법"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "1분간 최댓값"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "메모리"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "메모리 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker 컨테이너의 메모리 사용량"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "이름"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "네트워크"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Docker 컨테이너의 네트워크 트래픽"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "공용 인터페이스의 네트워크 트래픽"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "결과가 없습니다."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "시스템을 찾을 수 없습니다."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "알림"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC 지원"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "매 시작 시, 데이터베이스가 파일에 정의된 시스템과 일치하도록 업데이트됩니다."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "메뉴 열기"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "또는 아래 항목으로 진행하기"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "기존 알림 덮어쓰기"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "페이지"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "페이지 / 설정"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "비밀번호"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "비밀번호는 최소 8자 이상이어야 합니다."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "비밀번호는 72 바이트 이하여야 합니다."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "비밀번호 재설정 요청이 접수되었습니다"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "일시 중지"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr "일시 정지됨"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "알림이 전달되도록 <0>SMTP 서버를 구성</0>하세요."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "자세한 내용은 로그를 확인하세요."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "자격 증명을 확인하고 다시 시도하세요."
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "관리자 계정을 생성하세요."
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "이 사이트에 대해 팝업을 활성화하세요."
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "다시 로그인하세요."
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "사용법은 <0>문서</0>를 참조하세요."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "계정에 로그인하세요."
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "포트"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "기록된 시간의 정확한 사용량"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "선호 언어"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "공개 키"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "읽기"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "수신됨"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "비밀번호 재설정"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "재개"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enter 키 또는 쉼표를 사용하여 주소를 저장하세요. 이메일 알림을 비활성화하려면 비워 두세요."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "설정 저장"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr "시스템 저장"
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "검색"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "시스템 또는 설정 검색..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "알림을 받는 방법을 구성하려면 <0>알림 설정</0>을 참조하세요."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "보냄"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "시스템을 볼 때 차트의 기본 시간 범위를 설정합니다."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "설정"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "설정이 저장되었습니다."
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "로그인"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP 설정"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "정렬 기준"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "상태"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "시스템에서 사용된 스왑 공간"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "스왑 사용량"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "시스템"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "시스템"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "시스템은 데이터 디렉토리 내의 <0>config.yml</0> 파일에서 관리할 수 있습니다."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "표"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr "온도"
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "온도"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "시스템 센서의 온도"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "테스트 <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "테스트 알림이 전송되었습니다."
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "에이전트가 시스템에서 실행 중이어야 연결할 수 있습니다. 아래의 에이전트 설치 명령을 복사하세요."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "에이전트가 시스템에서 실행 중이어야 연결할 수 있습니다. 아래의 <0>docker-compose.yml</0>을 복사하세요."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "그런 다음 백엔드에 로그인하여 사용자 테이블에서 사용자 계정 비밀번호를 재설정하세요."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "이 작업은 되돌릴 수 없습니다. 데이터베이스에서 {name}에 대한 모든 현재 기록이 영구적으로 삭제됩니다."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}의 처리량"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "루트 파일 시스템의 처리량"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "받는사람(들)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "그리드 전환"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "테마 전환"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "센서가 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "업로드와 다운로드 대역폭의 합이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "CPU 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "메모리 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "시스템의 전원이 켜지거나 꺼질때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "디스크 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr "온라인"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "실시간으로 업데이트됩니다. 시스템을 클릭하여 정보를 확인하세요."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "가동 시간"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "루트 파티션의 사용량"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "사용됨"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "사용자"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "보기"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "표시할 열"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "표시할 충분한 기록을 기다리는 중"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "번역을 더 좋게 만드는 데 도움을 주시겠습니까? 자세한 내용은 <0>Crowdin</0>을 확인하세요."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / 푸시 알림"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "쓰기"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML 구성"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML 구성"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "사용자 설정이 업데이트되었습니다."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: nl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: nl\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dag} other {# dagen}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# uur} other {# uren}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 uur"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 week"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 uren"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 uren"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dagen"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Acties"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Actieve waarschuwingen"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Voeg <0>Systeem</0> toe"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Nieuw systeem toevoegen"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Voeg systeem toe"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Voeg URL toe"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Weergaveopties voor grafieken aanpassen."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Waarschuwingen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Alle systemen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Weet je zeker dat je {name} wilt verwijderen?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisch kopiëren vereist een veilige context."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Gemiddelde"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Gemiddeld CPU-gebruik van containers"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Gemiddelde overschrijdt <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Gemiddeld stroomverbruik van GPU's"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Gemiddeld systeembrede CPU-gebruik"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Gemiddeld gebruik van {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Back-ups"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandbreedte"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel ondersteunt OpenID Connect en vele OAuth2 authenticatieaanbieders."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel gebruikt <0>Shoutrr</0> om te integreren met populaire meldingsdiensten."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binair"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Opgelet - potentieel gegevensverlies"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Wijzig algemene applicatie opties."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Grafiekopties"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Controleer {email} op een reset link."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Controleer de logs voor meer details."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Controleer je meldingsservice"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Klik om te kopiëren"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instructies voor de opdrachtregel"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configureer hoe je waarschuwingsmeldingen ontvangt."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Bevestig wachtwoord"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Volgende"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Gekopieerd naar het klembord"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopieer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopieer host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopieer Linux-opdracht"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopieer tekst"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Processorgebruik"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Account aanmaken"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Donker"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Standaard tijdsduur"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Verwijderen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Schijf"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Schijf I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Schijfgebruik"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Schijfgebruik van {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU-gebruik"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker geheugengebruik"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker netwerk I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Documentatie"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "E-mailnotificaties"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Voer een e-mailadres in om het wachtwoord opnieuw in te stellen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Voer een e-mailadres in..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Fout"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Overschrijdt {0}{1} in de laatste {2, plural, one {# minuut} other {# minuten}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Bestaande systemen die niet gedefinieerd zijn in <0>config.yml</0> zullen worden verwijderd. Maak regelmatige backups."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Configuratie exporteren"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exporteer je huidige systeemconfiguratie."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Authenticatie mislukt"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Instellingen opslaan mislukt"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Versturen test notificatie mislukt"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Bijwerken waarschuwing mislukt"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Voor <0>{min}</0> {min, plural, one {minuut} other {minuten}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Wachtwoord vergeten?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Algemeen"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU stroomverbruik"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Raster"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP-adres"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Als je het wachtwoord voor je beheerdersaccount bent kwijtgeraakt, kan je het opnieuw instellen met behulp van de volgende opdracht."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Ongeldig e-mailadres."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Taal"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Indeling"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Licht"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Afmelden"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Aanmelden"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Aanmelding mislukt"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Zoek je waar je meldingen kunt aanmaken? Klik op de bel <0/> in de systeemtabel."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Weergave- en notificatievoorkeuren beheren."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Geheugen"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Geheugengebruik"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Geheugengebruik van docker containers"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Naam"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Netwerkverkeer van docker containers"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Netwerkverkeer van publieke interfaces"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Geen resultaten gevonden."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Geen systemen gevonden."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Meldingen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC ondersteuning"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Bij elke herstart zullen systemen in de database worden bijgewerkt om overeen te komen met de systemen die in het bestand zijn gedefinieerd."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Open menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Of ga verder met"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overschrijf bestaande waarschuwingen"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Pagina"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Pagina's / Instellingen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Het wachtwoord moet minimaal 8 tekens bevatten."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Wachtwoord reset aanvraag ontvangen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pauze"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "<0>Configureer een SMTP-server </0> om ervoor te zorgen dat waarschuwingen worden afgeleverd."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Controleer de logs voor meer details."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Controleer je aanmeldgegevens en probeer het opnieuw"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Maak een beheerdersaccount aan"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Activeer pop-ups voor deze website"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Meld je opnieuw aan"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Bekijk <0>de documentatie</0> voor instructies."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Meld je aan bij je account"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Poort"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Nauwkeurig gebruik op de opgenomen tijd"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Voorkeurstaal"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Publieke sleutel"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Lezen"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Ontvangen"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Wachtwoord resetten"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Hervatten"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Bewaar het adres met de enter-toets of komma. Laat leeg om e-mailmeldingen uit te schakelen."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Instellingen opslaan"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Zoeken"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Zoek naar systemen of instellingen..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Zie <0>notificatie-instellingen</0> om te configureren hoe je meldingen ontvangt."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Verzonden"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Stelt het standaard tijdsbereik voor grafieken in wanneer een systeem wordt bekeken."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Instellingen"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Instellingen opgeslagen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Aanmelden"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP-instellingen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sorteren op"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap ruimte gebruikt door het systeem"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap gebruik"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Systeem"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systemen"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systemen kunnen worden beheerd in een <0>config.yml</0> bestand in je data map."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabel"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatuur"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatuur van systeem sensoren"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testmelding verzonden"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "De agent moet op het systeem draaien om te verbinden. Kopieer het installatiecommando voor de agent hieronder."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "De agent moet op het systeem draaien om te verbinden. Kopieer de<0>docker-compose.yml</0> voor de agent hieronder."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Log vervolgens in op de backend en reset het wachtwoord van je gebruikersaccount in het gebruikersoverzicht."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Deze actie kan niet ongedaan worden gemaakt. Dit zal alle huidige records voor {name} permanent verwijderen uit de database."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Doorvoer van {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Doorvoer van het root bestandssysteem"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Naar e-mail(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Schakel raster"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Schakel thema"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Triggert wanneer een sensor een drempelwaarde overschrijdt"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Triggert wanneer de gecombineerde up/down een drempelwaarde overschrijdt"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Triggert wanneer het CPU-gebruik een drempelwaarde overschrijdt"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Triggert wanneer het geheugengebruik een drempelwaarde overschrijdt"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Triggert wanneer de status schakelt tussen up en down"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Triggert wanneer het gebruik van een schijf een drempelwaarde overschrijdt"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "In realtime bijgewerkt. Klik op een systeem om informatie te bekijken."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Actief"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Gebruik"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Gebruik van root-partitie"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Gebruikt"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Gebruikers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Weergave"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Zichtbare kolommen"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Wachtend op genoeg records om weer te geven"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Wil je ons helpen onze vertalingen nog beter te maken? Bekijk <0>Crowdin</0> voor meer informatie."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Pushmeldingen"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Schrijven"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML Configuratie"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Configuratie"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Je gebruikersinstellingen zijn bijgewerkt."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: no\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Norwegian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: no\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dag} other {# dager}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# time} other {# timer}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 time"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 uke"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 timer"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 timer"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dager"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Handlinger"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktive Alarmer"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Legg til <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Legg Til Nytt System"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Legg til system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Legg Til URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Juster visningsalternativer for diagrammer."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Alarmer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Alle Systemer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Er du sikker på at du vil slette {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisk kopiering krever en sikker kontekst."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Gjennomsnitt"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Gjennomsnittlig CPU-utnyttelse av konteinere"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Gjennomsnittet overstiger <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Gjennomsnittlig strømforbruk for GPU-er"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Gjennomsnittlig CPU-utnyttelse for hele systemet"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Gjennomsnittlig utnyttelse av {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Sikkerhetskopier"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Båndbredde"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel støtter OpenID Connect og mange OAuth2 autentiserings-tilbydere."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel bruker <0>Shoutrrr</0> for integrering mot populære meldingstjenester."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binær"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffere"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Avbryt"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Advarsel - potensielt tap av data"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Endre generelle program-innstillinger."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Diagraminnstillinger"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Sjekk {email} for en nullstillings-link."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Sjekk loggene for flere detaljer."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Sjekk din meldingstjeneste"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Klikk for å kopiere"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Kommandolinje-instrukser"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfigurer hvordan du vil motta alarmvarsler."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekreft passord"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Fortsett"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Kopiert til utklippstavlen"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopier"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopier vert"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopier Linux-kommando"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopier tekst"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU-bruk"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Opprett konto"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Mørkt"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashbord"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Standard tidsperiode"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Slett"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Diskbruk"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Diskbruk av {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU-bruk"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Minnebruk"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Nettverks-I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentasjon"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr "Nede"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "Rediger"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "E-post"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "E-postvarslinger"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Skriv inn e-postadresse for å nullstille passordet"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Skriv inn e-postadresse..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Feil"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Overstiger {0}{1} {2, plural, one {det siste minuttet} other {de siste # minuttene}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Eksisterende systemer som ikke er er definert i <0>config.yml</0> vil bli slettet. Vennligst ta jevnlige sikkerhetskopier."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Eksporter konfigurasjon"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Eksporter din nåværende systemkonfigurasjon"
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Autentisering mislyktes"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Kunne ikke lagre innstillingene"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Kunne ikke sende test-varsling"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Kunne ikke oppdatere alarm"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "I <0>{min}</0> {min, plural, one {minutt} other {minutter}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Glemt passord?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Generelt"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU Effektforbruk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Rutenett"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Vert / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Dersom du har mistet passordet til admin-kontoen kan du nullstille det med følgende kommando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Ugyldig e-postadresse."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kjerne"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Språk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Layout"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Lyst"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Logg Ut"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Logg Inn"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Innlogging mislyktes"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logger"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Ser du etter hvor du kan opprette alarmer? Klikk på bjelle-ikonene <0/> i systemtabellen."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Endre visnings- og varslingsinnstillinger."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr "Instruks for Manuell Installasjon"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Minne"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Minnebruk"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Minnebruk av docker-konteinere"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Navn"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Nett"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Nettverkstrafikk av docker-konteinere"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Nettverkstrafikk av eksterne nettverksgrensesnitt"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Ingen resultater funnet."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Ingen systemer funnet."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Varslinger"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC-støtte"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Ved hver omstart vil systemer i databasen bli oppdatert til å matche systemene definert i fila."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Åpne meny"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Eller fortsett med"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overskriv eksisterende alarmer"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Side"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Sider / Innstillinger"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Passord"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Passord må bestå av minst 8 tegn."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "Passord må være mindre enn 72 byte."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Mottatt forespørsel om å nullstille passord"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Vennligst <0>konfigurer en SMTP-server</0> for å forsikre deg om at varsler blir levert."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Vennligst sjekk loggene for mer informasjon."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Vennligst kontroller dine innloggingsopplysninger og prøv igjen"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Vennligst opprett en admin-konto"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Vennligst aktiver pop-ups for nettsiden"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Vennligst logg inn på nytt"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Vennligst se <0>dokumentasjonen</0> for instrukser."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Vennligst logg inn på kontoen din"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Nøyaktig utnyttelse på registrert tidspunkt"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Foretrukket Språk"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Offentlig Nøkkel"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Lesing"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Mottatt"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Nullstill Passord"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Gjenoppta"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Lagre adressen med Enter-tasten eller komma. La feltet være tomt for å deaktivere e-postvarsler."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Lagre Innstillinger"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr "Lagre system"
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Søk"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Søk etter systemer eller innstillinger..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Se <0>varslingsinnstillingene</0> for å konfigurere hvordan du vil motta varsler."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Sendt"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Angir standard tidsperiode for diagrammer når et system vises."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Innstillinger"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Innstillinger lagret"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Logg inn"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP-innstillinger"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sorter Etter"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap-plass i bruk av systemet"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap-bruk"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systemer"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systemer kan håndteres i en <0>config.yml</0>-fil i din data-katalog."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabell"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturer på system-sensorer"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Test-varsling sendt"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Agenten må kjøre på systemet du vil koble til. Kopier installasjons-kommandoen for agenten under."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Agenten må kjøre på systemet du vil koble til. Kopier <0>docker-compose.yml</0> for agenten under."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Logg deretter inn i backend og nullstill passordet på din konto i users-tabellen."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Denne handlingen kan ikke omgjøres. Dette vil slette alle poster for {name} permanent fra databasen."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Gjennomstrømning av {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Gjennomstrømning av rot-filsystemet"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Til e-postadresse(r)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Rutenett av/på"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Tema av/på"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Slår inn når enhver sensor overstiger en grenseverdi"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Slår inn når kombinert opp/ned overskrider en grenseverdi"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Slår inn når CPU-bruken overstiger en grenseverdi"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Slår inn når minnebruken overstiger en grenseverdi"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Slår inn når statusen veksler mellom oppe og nede"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Slår inn når forbruk av hvilken som helst disk overstiger en grenseverdi"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr "Oppe"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Oppdatert i sanntid. Klikk på et system for å se mer informasjon."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Oppetid"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Forbruk"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Forbruk av rot-partisjon"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Brukt"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Brukere"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Visning"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Synlige Felter"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Venter på nok registreringer til å vise"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Vil du hjelpe oss med å gjøre oversettelsene enda bedre? Ta en titt på <0>Crowdin</0> for mer informasjon."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push-varslinger"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Skriving"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML Oppsett"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Konfigurasjon"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Dine brukerinnstillinger har blitt oppdatert."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: pl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Polish\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: pl\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {godzinę} few {# godziny} many {# godzin} other {# godziny}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 godzina"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 tydzień"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 godzin"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 godziny"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dni"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Akcje"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktywne alerty"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Dodaj <0>system</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Dodaj nowy system"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Dodaj system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Dodaj URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Dostosuj opcje wyświetlania wykresów."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Alerty"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Wszystkie systemy"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Czy na pewno chcesz usunąć {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatyczne kopiowanie wymaga bezpiecznego kontekstu."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Średnia"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Średnie wykorzystanie procesora przez kontenery"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Średnia przekracza <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Średnie zużycie energii przez GPU"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Średnie wykorzystanie procesora w całym systemie"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Średnie użycie {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Kopie"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Przepustowość"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel obsługuje OpenID Connect i wielu dostawców uwierzytelniania OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel używa <0>Shoutrrr</0> do integracji z popularnych serwisami powiadomień."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Plik binarny"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Pamięć podręczna / Bufory"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Uwaga- potencjalna utrata danych."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Zmiana ogólnych ustawień aplikacji."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opcje wykresu"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Sprawdź {email}, aby uzyskać link do resetowania."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Sprawdź logi, aby uzyskać więcej informacji."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Sprawdź swój serwis powiadomień"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Kliknij, aby skopiować"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instrukcje wiersza poleceń"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Skonfiguruj sposób otrzymywania powiadomień."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Potwierdź hasło"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Kontynuuj"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Skopiowano do schowka"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopiuj"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopiuj host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiuj polecenie Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiuj tekst"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "Procesor"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Użycie procesora"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Utwórz konto"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Ciemny"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Panel kontrolny"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Domyślny przedział czasu"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Usuń"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Dysk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Dysk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Użycie dysku"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Wykorzystanie dysku {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Wykorzystanie procesora przez Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Wykorzystanie pamięci przez Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Sieć Docker I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentacja"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Powiadomienia e-mail"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Wprowadź adres e-mail, aby zresetować hasło"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Wprowadź adres e-mail..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Błąd"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Przekracza {0}{1} w ciągu ostatnich {2, plural, one {# minuty} other {# minut}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Istniejące systemy, które nie są zdefiniowane w <0>config.yml</0>, zostaną usunięte. Proszę regularnie tworzyć kopie zapasowe."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Eksportuj konfigurację"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Eksportuj aktualną konfigurację systemów."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Błąd autoryzacji"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Nie udało się zapisać ustawień"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Nie udało się wysłać testowego powiadomienia"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Nie udało się zaktualizować powiadomienia"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filtruj..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Na <0>{min}</0> {min, plural, one {minutę} other {minut}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Zapomniałeś hasła?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Ogólne"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Moc GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Siatka"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / adres IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Jeśli utraciłeś hasło do swojego konta administratora, możesz je zresetować, używając następującego polecenia."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Nieprawidłowy adres e-mail."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Jądro"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Język"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Układ"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Jasny"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Wyloguj"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Logowanie"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Próba logowania nie powiodła się"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logi"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Szukasz, gdzie utworzyć powiadomienia? Kliknij ikonę dzwonka <0/> w tabeli systemów."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Zarządzaj preferencjami wyświetlania i powiadomień."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks. 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Pamięć"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Wykorzystanie pamięci"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Użycie pamięci przez kontenery Docker."
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Nazwa"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Sieć"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Ruch sieciowy kontenerów Docker."
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Ruch sieciowy interfejsów publicznych"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Brak wyników."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Nie znaleziono systemów."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Powiadomienia"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Wsparcie OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Przy każdym ponownym uruchomieniu systemy w bazie danych będą aktualizowane, aby odpowiadały systemom zdefiniowanym w pliku."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Otwórz menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Lub kontynuuj z"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Nadpisz istniejące alerty"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Strona"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Strony / Ustawienia"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Hasło"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Hasło musi mieć co najmniej 8 znaków."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Otrzymane żądanie resetowania hasła"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pauza"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Proszę <0>skonfigurować serwer SMTP</0>, aby zapewnić dostarczanie powiadomień."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Sprawdź logi, aby uzyskać więcej informacji."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Sprawdź swoje poświadczenia i spróbuj ponownie"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Utwórz konto administratora"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Włącz wyskakujące okna dla tej strony"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Zaloguj się ponownie"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Proszę zapoznać się z <0>dokumentacją</0>."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Zaloguj się na swoje konto"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Dokładne wykorzystanie w zarejestrowanym czasie"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferowany język"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Klucz publiczny"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Czytaj"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Otrzymane"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Resetuj hasło"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Wznów"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Zapisz adres, używając klawisza enter lub przecinka. Pozostaw puste, aby wyłączyć powiadomienia e-mail."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Zapisz ustawienia"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Szukaj"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Szukaj systemów lub ustawień..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Zobacz <0>ustawienia powiadomień</0>, aby skonfigurować sposób, w jaki otrzymujesz powiadomienia."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Wysłane"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Ustawia domyślny zakres czasowy dla wykresów, gdy system jest wyświetlony."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Ustawienia"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Ustawienia zapisane"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Zaloguj się"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Ustawienia SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sortuj według"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Pamięć wymiany używana przez system"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Użycie pamięci wymiany"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systemy"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systemy mogą być zarządzane w pliku <0>config.yml</0> znajdującym się w Twoim katalogu danych."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabela"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatury czujników systemowych."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testowe powiadomienie wysłane."
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Agent musi być uruchomiony na systemie, aby nawiązać połączenie. Skopiuj poniżej polecenie instalacji agenta."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Agent musi być uruchomiony na systemie, aby nawiązać połączenie. Skopiuj poniżej plik <0>docker-compose.yml</0> dla agenta."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Następnie zaloguj się do panelu administracyjnego i zresetuj hasło do konta użytkownika w tabeli użytkowników."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Tej akcji nie można cofnąć. Spowoduje to trwałe usunięcie wszystkich bieżących rekordów dla {name} z bazy danych."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Przepustowość {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Przepustowość głównego systemu plików"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Do e-mail(ów)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Przełącz siatkę"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Zmień motyw"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Wyzwalane, gdy jakikolwiek czujnik przekroczy ustalony próg."
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Wyzwalane, gdy łączna wartość w górę/w dół przekroczy próg"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Wyzwalane, gdy użycie procesora przekracza próg"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Wyzwalane, wykorzystanie pamięci przekroczy ustalony próg."
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Wyzwalane, gdy status przełącza się między stanem aktywnym a nieaktywnym"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Wyzwalane, gdy wykorzystanie któregokolwiek dysku przekroczy ustalony próg"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Aktualizowane w czasie rzeczywistym. Kliknij system, aby zobaczyć informacje."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Czas pracy"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Wykorzystanie"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Użycie partycji głównej"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Używane"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Użytkownicy"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Widok"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Widoczne kolumny"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Oczekiwanie na wystarczającą liczbę rekordów do wyświetlenia"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Chcesz pomóc nam uczynić nasze tłumaczenia jeszcze lepszymi? Sprawdź <0>Crowdin</0> po więcej szczegółów."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Powiadomienia push"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Napisz"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "Konf. YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Konfiguracja YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Twoje ustawienia użytkownika zostały zaktualizowane."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: pt\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Portuguese\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: pt-PT\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dia} other {# dias}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# hora} other {# horas}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 hora"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 semana"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 horas"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 horas"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dias"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Ações"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertas Ativos"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Adicionar <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Adicionar Novo Sistema"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Adicionar sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Adicionar URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Ajustar opções de exibição para gráficos."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Alertas"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Todos os Sistemas"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Tem certeza de que deseja excluir {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "A cópia automática requer um contexto seguro."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Média"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilização média de CPU dos contêineres"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "A média excede <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Consumo médio de energia pelas GPU's"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilização média de CPU em todo o sistema"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Utilização média de {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Largura de Banda"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel suporta OpenID Connect e muitos provedores de autenticação OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel usa <0>Shoutrrr</0> para integrar com serviços de notificação populares."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binário"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Cuidado - possível perda de dados"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Alterar opções gerais do aplicativo."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opções de gráfico"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Verifique {email} para um link de redefinição."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Verifique os logs para mais detalhes."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Verifique seu serviço de notificação"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Clique para copiar"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instruções de linha de comando"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configure como você recebe notificações de alerta."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar senha"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Continuar"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copiado para a área de transferência"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Copiar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Copiar host"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copiar comando Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copiar texto"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Uso de CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Criar conta"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Escuro"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Painel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Período de tempo padrão"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Excluir"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "E/S de Disco"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Uso de Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Uso de disco de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Uso de CPU do Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Uso de Memória do Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "E/S de Rede do Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Documentação"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr "Editar"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Notificações por email"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Digite o endereço de email para redefinir a senha"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Digite o endereço de email..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Erro"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Excede {0}{1} no último {2, plural, one {# minuto} other {# minutos}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Sistemas existentes não definidos em <0>config.yml</0> serão excluídos. Faça backups regulares."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Exportar configuração"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exporte a configuração atual dos seus sistemas."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Falha na autenticação"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Falha ao guardar as definições"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Falha ao enviar notificação de teste"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Falha ao atualizar alerta"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrar..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Por <0>{min}</0> {min, plural, one {minuto} other {minutos}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Esqueceu a senha?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Geral"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo de Energia da GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Grade"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Se você perdeu a senha da sua conta de administrador, pode redefini-la usando o seguinte comando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Endereço de email inválido."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Idioma"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Aspeto"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Claro"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Sair"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Entrar"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Tentativa de login falhou"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Procurando onde criar alertas? Clique nos ícones de sino <0/> na tabela de sistemas."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gerenciar preferências de exibição e notificação."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Máx 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Memória"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Uso de Memória"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Uso de memória dos contêineres Docker"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Rede"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Tráfego de rede dos contêineres Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Tráfego de rede das interfaces públicas"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Nenhum resultado encontrado."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Nenhum sistema encontrado."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Notificações"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Suporte a OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "A cada reinício, os sistemas no banco de dados serão atualizados para corresponder aos sistemas definidos no arquivo."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Abrir menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Ou continue com"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sobrescrever alertas existentes"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Página"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Páginas / Configurações"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "A senha deve ter pelo menos 8 caracteres."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "A password tem que ter menos de 72 bytes."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Solicitação de redefinição de senha recebida"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Pausar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Por favor, <0>configure um servidor SMTP</0> para garantir que os alertas sejam entregues."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Por favor, verifique os logs para mais detalhes."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Por favor, verifique suas credenciais e tente novamente"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Por favor, crie uma conta de administrador"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Por favor, habilite pop-ups para este site"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Por favor, faça login novamente"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Por favor, veja <0>a documentação</0> para instruções."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Por favor, entre na sua conta"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilização precisa no momento registrado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Idioma Preferido"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Chave Pública"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Ler"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Recebido"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Redefinir Senha"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Retomar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Salve o endereço usando a tecla enter ou vírgula. Deixe em branco para desativar notificações por email."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Guardar Definições"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr "Guardar Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Pesquisar"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Pesquisar por sistemas ou configurações..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Veja <0>configurações de notificação</0> para configurar como você recebe alertas."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Enviado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Define o intervalo de tempo padrão para gráficos quando um sistema é visualizado."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Configurações"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Definições guardadas"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Entrar"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Configurações SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Ordenar Por"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espaço de swap usado pelo sistema"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Uso de Swap"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemas"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Os sistemas podem ser gerenciados em um arquivo <0>config.yml</0> dentro do seu diretório de dados."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabela"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturas dos sensores do sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Testar <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notificação de teste enviada"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "O agente deve estar em execução no sistema para conectar. Copie o comando de instalação para o agente abaixo."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "O agente deve estar em execução no sistema para conectar. Copie o <0>docker-compose.yml</0> para o agente abaixo."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Em seguida, faça login no backend e redefina a senha da sua conta de usuário na tabela de usuários."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Esta ação não pode ser desfeita. Isso excluirá permanentemente todos os registros atuais de {name} do banco de dados."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Taxa de transferência de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Taxa de transferência do sistema de arquivos raiz"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Para email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Alternar grade"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Alternar tema"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Dispara quando qualquer sensor excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Dispara quando a soma de subida/descida excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de CPU excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de memória excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Dispara quando o status alterna entre ativo e inativo"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de qualquer disco excede um limite"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Atualizado em tempo real. Clique em um sistema para ver informações."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Tempo de Atividade"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Uso"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Uso da partição raiz"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Usado"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Usuários"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Visual"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Campos Visíveis"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Aguardando registros suficientes para exibir"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Quer nos ajudar a melhorar ainda mais nossas traduções? Confira <0>Crowdin</0> para mais detalhes."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notificações Webhook / Push"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Escrever"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "Configuração YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuração YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "As configurações do seu usuário foram atualizadas."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ru\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Russian\n"
|
||||
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ru\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# день} other {# дней}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# час} other {# часов}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 час"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 неделя"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 часов"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 часа"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 дней"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Действия"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Активные оповещения"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Добавить <0>Систему</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Добавить новую систему"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Добавить систему"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Добавить URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Настроить параметры отображения для графиков."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Администратор"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Агент"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Оповещения"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Все системы"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Вы уверены, что хотите удалить {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Автоматическое копирование требует безопасного контекста."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Среднее"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Среднее использование CPU контейнерами"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Среднее превышает <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Среднее потребление мощности всеми GPU"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Среднее использование CPU по всей системе"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Среднее использование {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Резервные копии"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Пропускная способность"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel поддерживает OpenID Connect и множество поставщиков аутентификации OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel использует <0>Shoutrrr</0> для интеграции с популярными сервисами уведомлений."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Двоичный"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Кэш / Буферы"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Отмена"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Внимание - возможная потеря данных"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Изменить общие параметры приложения."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Параметры графиков"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Проверьте {email} для получения ссылки на сброс."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Проверьте журналы для получения более подробной информации."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Проверьте ваш сервис уведомлений"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Нажмите, чтобы скопировать"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Инструкции командной строки"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Настройте, как вы получаете уведомления об оповещениях."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Подтвердите пароль"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Продолжить"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Скопировано в буфер обмена"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Копировать"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Копировать хост"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Копировать команду Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Копировать текст"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "Использование CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Создать аккаунт"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Темная"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Панель управления"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Период по умолчанию"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Удалить"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Диск"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Дисковый ввод/вывод"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Использование диска"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Использование диска {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Использование CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Использование памяти Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Сетевой ввод/вывод Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Документация"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "Электронная почта"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "Уведомления по электронной почте"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Введите адрес электронной почты для сброса пароля"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Введите адрес электронной почты..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Ошибка"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Превышает {0}{1} за последние {2, plural, one {# минуту} other {# минут}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Существующие системы, не определенные в <0>config.yml</0>, будут удалены. Пожалуйста, делайте регулярные резервные копии."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Экспорт конфигурации"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Экспортируйте текущую конфигурацию систем."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Не удалось аутентифицировать"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Не удалось сохранить настройки"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Не удалось отправить тестовое уведомление"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Не удалось обновить оповещение"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Фильтр..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "На <0>{min}</0> {min, plural, one {минуту} other {минут}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Забыли пароль?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Общие"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Потребляемая мощность GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Сетка"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Хост / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Если вы потеряли пароль от своей учетной записи администратора, вы можете сбросить его, используя следующую команду."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Неверный адрес электронной почты."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Ядро"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Язык"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Макет"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Светлая"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Выйти"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Вход"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Попытка входа не удалась"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Журналы"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Ищете, где создать оповещения? Нажмите на значки колокольчика <0/> в таблице систем."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Управляйте предпочтениями отображения и уведомлений."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr "Инструкции по ручной настройке"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Макс 1 мин"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Память"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Использование памяти"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Использование памяти контейнерами Docker"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Имя"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Сеть"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Сетевой трафик контейнеров Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Сетевой трафик публичных интерфейсов"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Результаты не найдены."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Системы не найдены."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Уведомления"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Поддержка OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "При каждом перезапуске системы в базе данных будут обновлены в соответствии с системами, определенными в файле."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Открыть меню"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Или продолжить с"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Перезаписать существующие оповещения"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Страница"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Страницы / Настройки"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Пароль"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Пароль должен содержать не менее 8 символов."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr "Пароль должен быть меньше 72 символов."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Запрос на сброс пароля получен"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Пауза"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Пожалуйста, <0>настройте SMTP-сервер</0>, чтобы гарантировать доставку оповещений."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Пожалуйста, проверьте журналы для получения более подробной информации."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Пожалуйста, проверьте свои учетные данные и попробуйте снова"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Пожалуйста, создайте учетную запись администратора"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Пожалуйста, включите всплывающие окна для этого сайта"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Пожалуйста, войдите снова"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Пожалуйста, смотрите <0>документацию</0> для получения инструкций."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Пожалуйста, войдите в свою учетную запись"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Точное использование в записанное время"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Предпочтительный язык"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Ключ"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Чтение"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Получено"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Сбросить пароль"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Возобновить"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Сохраните адрес, используя клавишу ввода или запятую. Оставьте пустым, чтобы отключить уведомления по электронной почте."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Сохранить настройки"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Поиск"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Поиск систем или настроек..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Смотрите <0>настройки уведомлений</0>, чтобы настроить, как вы получаете оповещения."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Отправлено"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Устанавливает диапазон времени по умолчанию для графиков при просмотре системы."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Настройки"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Настройки сохранены"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Войти"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "Настройки SMTP"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Сортировать по"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Используемое системой пространство подкачки"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Использование подкачки"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Система"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Системы"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Системы могут управляться в файле <0>config.yml</0> внутри вашего каталога данных."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Таблица"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Температура"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Температуры датчиков системы"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Тест <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Тестовое уведомление отправлено"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Агент должен работать на системе для подключения. Скопируйте команду установки агента ниже."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Агент должен работать на системе для подключения. Скопируйте <0>docker-compose.yml</0> для агента ниже."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Затем войдите в бэкенд и сбросьте пароль вашей учетной записи в таблице пользователей."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Это действие не может быть отменено. Это навсегда удалит все текущие записи для {name} из базы данных."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Пропускная способность {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Пропускная способность корневой файловой системы"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "На электронную почту"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Переключить сетку"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Переключить тему"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Срабатывает, когда любой датчик превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Срабатывает, когда комбинированный вход/выход превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Срабатывает, когда использование CPU превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Срабатывает, когда использование памяти превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Срабатывает, когда статус переключается между включено и выключено"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Срабатывает, когда использование любого диска превышает порог"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Обновляется в реальном времени. Нажмите на систему, чтобы просмотреть информацию."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Время работы"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Использование"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Использование корневого раздела"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Использовано"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Пользователи"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Вид"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Видимые столбцы"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Ожидание достаточного количества записей для отображения"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Хотите помочь нам улучшить наши переводы? Посетите <0>Crowdin</0> для получения более подробной информации."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push уведомления"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Запись"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML конфигурация"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML конфигурация"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Ваши настройки пользователя были обновлены."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: sl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Slovenian\n"
|
||||
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: sl\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dan} two {# dneva} few {# dni} other {# dni}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# ura} two {# uri} few {# ur} other {# ur}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 ura"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 teden"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 ur"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 ur"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dni"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Dejanja"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktivna opozorila"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Dodaj <0>sistem</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Dodaj nov sistem"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Dodaj sistem"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Dodaj URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Prilagodi možnosti prikaza za grafikone."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Administrator"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Opozorila"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Vsi sistemi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Ali ste prepričani, da želite izbrisati {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Za samodejno kopiranje je potreben varen kontekst."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Povprečno"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Povprečna izkoriščenost procesorja kontejnerjev"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Povprečje presega <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Povprečna poraba energije GPU"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Povprečna CPU izkoriščenost v celotnem sistemu"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Povprečna poraba {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Varnostne kopije"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Pasovna širina"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel podpira OpenID Connect in številne ponudnike preverjanja pristnosti OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel uporablja <0>Shoutrrr</0> za integracijo s priljubljenimi storitvami obveščanja."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binarno"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Predpomnilnik / medpomnilniki"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Prekliči"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Pozor - možna izguba podatkov"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Spremeni splošne možnosti aplikacije."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Možnosti grafikona"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Preverite {email} za povezavo za ponastavitev."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Za več podrobnosti preverite dnevnike."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Preverite storitev obveščanja"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Klikni za kopiranje"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Navodila za ukazno vrstico"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Nastavi način prejemanja opozorilnih obvestil."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Potrdite geslo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Nadaljuj"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Kopirano v odložišče"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopiraj"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopiraj gostitelja"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiraj Linux ukaz"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiraj besedilo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU poraba"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Ustvari račun"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Temno"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Nadzorna plošča"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Privzeto časovno obdobje"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Izbriši"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Poraba diska"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Poraba diska za {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU poraba"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker poraba spomina"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker I/O mreže"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentacija"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "E-pošta"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "E-poštna obvestila"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Vnesite e-poštni naslov za ponastavitev gesla"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Vnesite e-poštni naslov..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Napaka"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Preseženo {0}{1} v zadnjih {2, plural, one {# minuti} other {# minutah}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Obstoječi sistemi, ki niso definirani v <0>config.yml</0>, bodo izbrisani. Prosimo, naredite redne varnostne kopije."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Izvozi nastavitve"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Izvozi trenutne nastavitve sistema."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Preverjanje pristnosti ni uspelo"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Shranjevanje nastavitev ni uspelo"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Pošiljanje testnega obvestila ni uspelo"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Opozorila ni bilo mogoče posodobiti"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Za <0>{min}</0> {min, plural, one {minuto} other {minut}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Pozabljeno geslo?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Splošno"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU poraba moči"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Mreža"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Gostitelj / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Če ste izgubili geslo za svoj skrbniški račun, ga lahko ponastavite z naslednjim ukazom."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Napačen e-poštni naslov."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Jedro"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Jezik"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Postavitev"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Svetlo"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Odjava"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Prijava"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Poskus prijave ni uspel"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Dnevniki"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Namesto tega iščete, kje ustvariti opozorila? Kliknite ikone zvonca <0/> v sistemski tabeli."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Upravljajte nastavitve prikaza in obvestil."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Največ 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Pomnilnik"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Poraba pomnilnika"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Poraba pomnilnika docker kontejnerjev"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Naziv"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Mreža"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Omrežni promet docker kontejnerjev"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Omrežni promet javnih vmesnikov"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Ni rezultatov."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Ne najdem sistema."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Obvestila"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Podpora za OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Ob vsakem ponovnem zagonu bodo sistemi v zbirki podatkov posodobljeni, da se bodo ujemali s sistemi, definiranimi v datoteki."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Odpri menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Ali nadaljuj z"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Prepiši obstoječe alarme"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Stran"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Strani / Nastavitve"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Geslo"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Geslo mora imeti vsaj 8 znakov."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Prejeta zahteva za ponastavitev gesla"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Premor"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "<0>Nastavite strežnik SMTP</0>, da zagotovite dostavo opozoril."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Za več podrobnosti preverite dnevnike."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Preverite svoje poverilnice in poskusite znova"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Ustvarite skrbniški račun"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Omogočite pojavna okna za to spletno mesto"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Prosimo, prijavite se znova"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Za navodila glejte <0>dokumentacijo</0>."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Prijavite se v svoj račun"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Vrata"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Natančna poraba v zabeleženem času"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Prednostni jezik"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Javni ključ"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Preberano"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Prejeto"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Ponastavi geslo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Nadaljuj"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Shranite naslov s tipko enter ali vejico. Pustite prazno, da onemogočite e-poštna obvestila."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Shrani nastavitve"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Iskanje"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Iskanje sistemov ali nastavitev..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Glejte <0>nastavitve obvestil</0>, da nastavite način prejemanja opozoril."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Poslano"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Nastavi privzeti časovni obseg za grafikone, ko si ogledujete sistem."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Nastavitve"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Nastavitve so shranjene"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Prijavite se"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP nastavitve"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Razvrsti po"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap prostor, ki ga uporablja sistem"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap uporaba"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "Sistemsko"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemi"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Sisteme lahko upravljate v datoteki <0>config.yml</0> v vašem podatkovnem imeniku."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabela"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperature sistemskih senzorjev"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Preveri <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testno obvestilo je poslano"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Za vzpostavitev povezave mora biti agent zagnan v sistemu. Kopirajte spodnji namestitveni ukaz za agenta."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Za vzpostavitev povezave mora biti agent zagnan v sistemu. Kopirajte <0>docker-compose.yml</0> za spodnjega agenta."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Nato se prijavite v zaledni sistem in ponastavite geslo svojega uporabniškega računa v tabeli uporabnikov."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Tega dejanja ni mogoče razveljaviti. To bo trajno izbrisalo vse trenutne zapise za {name} iz zbirke podatkov."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Prepustnost {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Prepustnost korenskega datotečnega sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "E-pošta za"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Preklopi način mreže"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Obrni temo"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Sproži se, ko kateri koli senzor preseže prag"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Sproži, ko kombinacija gor/dol preseže prag"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Sproži se, ko poraba procesorja preseže prag"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Sproži se, ko uporaba pomnilnika preseže prag"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Sproži se, ko se stanje preklaplja med gor in dol"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Sproži se, ko uporaba katerega koli diska preseže prag"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Posodobljeno v realnem času. Za ogled informacij kliknite na sistem."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Čas delovanja"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Uporaba"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Uporaba korenske particije"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Uporabljeno"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Uporabniki"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Pogled"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Vidna polja"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Čakam na dovolj zapisov za prikaz"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Ali nam želite pomagati, da bomo naše prevode še izboljšali? Za več podrobnosti si oglejte <0>Crowdin</0>."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / potisna obvestila"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Pisanje"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML nastaviitev"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML nastavitev"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vaše uporabniške nastavitve so posodobljene."
|
||||
@@ -1,871 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: sv\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-03-06 07:27\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Swedish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: sv-SE\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx:259
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dag} other {# dagar}}"
|
||||
|
||||
#: src/components/routes/system.tsx:257
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# timme} other {# timmar}}"
|
||||
|
||||
#: src/lib/utils.ts:168
|
||||
msgid "1 hour"
|
||||
msgstr "1 timme"
|
||||
|
||||
#: src/lib/utils.ts:191
|
||||
msgid "1 week"
|
||||
msgstr "1 vecka"
|
||||
|
||||
#: src/lib/utils.ts:176
|
||||
msgid "12 hours"
|
||||
msgstr "12 timmar"
|
||||
|
||||
#: src/lib/utils.ts:184
|
||||
msgid "24 hours"
|
||||
msgstr "24 timmar"
|
||||
|
||||
#: src/lib/utils.ts:199
|
||||
msgid "30 days"
|
||||
msgstr "30 dagar"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:304
|
||||
msgid "Actions"
|
||||
msgstr "Åtgärder"
|
||||
|
||||
#: src/components/routes/home.tsx:94
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktiva larm"
|
||||
|
||||
#: src/components/add-system.tsx:43
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Lägg till <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
msgid "Add New System"
|
||||
msgstr "Lägg till nytt system"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Add system"
|
||||
msgstr "Lägg till system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:158
|
||||
msgid "Add URL"
|
||||
msgstr "Lägg till URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Justera visningsalternativ för diagram."
|
||||
|
||||
#: src/components/command-palette.tsx:131
|
||||
#: src/components/command-palette.tsx:144
|
||||
#: src/components/command-palette.tsx:158
|
||||
#: src/components/command-palette.tsx:172
|
||||
#: src/components/command-palette.tsx:187
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:270
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:33
|
||||
#: src/components/alerts/alert-button.tsx:79
|
||||
msgid "Alerts"
|
||||
msgstr "Larm"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:347
|
||||
#: src/components/alerts/alert-button.tsx:99
|
||||
msgid "All Systems"
|
||||
msgstr "Alla system"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:696
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Är du säker på att du vill ta bort {name}?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisk kopiering kräver en säker kontext."
|
||||
|
||||
#: src/components/routes/system.tsx:670
|
||||
msgid "Average"
|
||||
msgstr "Genomsnitt"
|
||||
|
||||
#: src/components/routes/system.tsx:446
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Genomsnittlig CPU-användning för containrar"
|
||||
|
||||
#. placeholder {0}: data.alert.unit
|
||||
#: src/components/alerts/alerts-system.tsx:253
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Genomsnittet överskrider <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:547
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Genomsnittlig strömförbrukning för GPU:er"
|
||||
|
||||
#: src/components/routes/system.tsx:435
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Genomsnittlig systemomfattande CPU-användning"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx:569
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Genomsnittlig användning av {0}"
|
||||
|
||||
#: src/components/navbar.tsx:94
|
||||
#: src/components/command-palette.tsx:169
|
||||
msgid "Backups"
|
||||
msgstr "Säkerhetskopior"
|
||||
|
||||
#: src/lib/utils.ts:337
|
||||
#: src/components/routes/system.tsx:491
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandbredd"
|
||||
|
||||
#: src/components/login/auth-form.tsx:305
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel stöder OpenID Connect och många OAuth2-autentiseringsleverantörer."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:129
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel använder <0>Shoutrrr</0> för att integrera med populära aviseringstjänster."
|
||||
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Binary"
|
||||
msgstr "Binär"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:87
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffertar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:707
|
||||
msgid "Cancel"
|
||||
msgstr "Avbryt"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:69
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Varning - potentiell dataförlust"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Ändra allmänna programalternativ."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Diagramalternativ"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:35
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Kontrollera {email} för en återställningslänk."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:41
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Kontrollera loggarna för mer information."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:185
|
||||
msgid "Check your notification service"
|
||||
msgstr "Kontrollera din aviseringstjänst"
|
||||
|
||||
#: src/components/add-system.tsx:205
|
||||
msgid "Click to copy"
|
||||
msgstr "Klicka för att kopiera"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:84
|
||||
#: src/components/login/forgot-pass-form.tsx:90
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instruktioner för kommandoraden"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:79
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfigurera hur du tar emot larmaviseringar."
|
||||
|
||||
#: src/components/login/auth-form.tsx:213
|
||||
#: src/components/login/auth-form.tsx:218
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekräfta lösenord"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:713
|
||||
msgid "Continue"
|
||||
msgstr "Fortsätt"
|
||||
|
||||
#: src/lib/utils.ts:35
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Kopierat till urklipp"
|
||||
|
||||
#: src/components/add-system.tsx:216
|
||||
#: src/components/add-system.tsx:218
|
||||
msgid "Copy"
|
||||
msgstr "Kopiera"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:678
|
||||
msgid "Copy host"
|
||||
msgstr "Kopiera värd"
|
||||
|
||||
#: src/components/add-system.tsx:225
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiera Linux-kommando"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiera text"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/lib/utils.ts:319
|
||||
#: src/components/routes/system.tsx:434
|
||||
#: src/components/charts/area-chart.tsx:58
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU-användning"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Create account"
|
||||
msgstr "Skapa konto"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:22
|
||||
msgid "Dark"
|
||||
msgstr "Mörkt"
|
||||
|
||||
#: src/components/command-palette.tsx:80
|
||||
#: src/components/routes/home.tsx:36
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Standardtidsperiod"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:683
|
||||
msgid "Delete"
|
||||
msgstr "Ta bort"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:204
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:481
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/lib/utils.ts:331
|
||||
#: src/components/routes/system.tsx:474
|
||||
#: src/components/charts/disk-chart.tsx:77
|
||||
msgid "Disk Usage"
|
||||
msgstr "Diskanvändning"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Diskanvändning av {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:445
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU-användning"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Minnesanvändning"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Nätverks-I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:123
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentation"
|
||||
|
||||
#. Context: System is down
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/systems-table/systems-table.tsx:142
|
||||
#: src/components/routes/system.tsx:345
|
||||
msgid "Down"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:126
|
||||
#: src/components/systems-table/systems-table.tsx:653
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:54
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Email"
|
||||
msgstr "E-post"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:93
|
||||
msgid "Email notifications"
|
||||
msgstr "E-postaviseringar"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Ange e-postadress för att återställa lösenord"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:113
|
||||
msgid "Enter email address..."
|
||||
msgstr "Ange e-postadress..."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:189
|
||||
#: src/components/routes/settings/config-yaml.tsx:29
|
||||
#: src/components/login/auth-form.tsx:137
|
||||
msgid "Error"
|
||||
msgstr "Fel"
|
||||
|
||||
#. placeholder {0}: alert.value
|
||||
#. placeholder {1}: info.unit
|
||||
#. placeholder {2}: alert.min
|
||||
#: src/components/routes/home.tsx:113
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Överskrider {0}{1} under de senaste {2, plural, one {# minuten} other {# minuterna}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:73
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Befintliga system som inte definieras i <0>config.yml</0> kommer att tas bort. Gör regelbundna säkerhetskopior."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:94
|
||||
msgid "Export configuration"
|
||||
msgstr "Exportera konfiguration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:49
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exportera din nuvarande systemkonfiguration."
|
||||
|
||||
#: src/lib/utils.ts:48
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Autentisering misslyckades"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:64
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Kunde inte spara inställningar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:190
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Kunde inte skicka testavisering"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:26
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Kunde inte uppdatera larm"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:354
|
||||
#: src/components/routes/system.tsx:643
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrera..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:285
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Under <0>{min}</0> {min, plural, one {minut} other {minuter}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:328
|
||||
msgid "Forgot password?"
|
||||
msgstr "Glömt lösenordet?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/layout.tsx:52
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
msgid "General"
|
||||
msgstr "Allmänt"
|
||||
|
||||
#: src/components/routes/system.tsx:546
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU-strömförbrukning"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:381
|
||||
msgid "Grid"
|
||||
msgstr "Rutnät"
|
||||
|
||||
#: src/components/add-system.tsx:159
|
||||
msgid "Host / IP"
|
||||
msgstr "Värd / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:94
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Om du har glömt lösenordet till ditt administratörskonto kan du återställa det med följande kommando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:18
|
||||
msgid "Invalid email address."
|
||||
msgstr "Ogiltig e-postadress."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:271
|
||||
msgid "Kernel"
|
||||
msgstr "Kärna"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Språk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:367
|
||||
msgid "Layout"
|
||||
msgstr "Layout"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:17
|
||||
msgid "Light"
|
||||
msgstr "Ljust"
|
||||
|
||||
#: src/components/navbar.tsx:105
|
||||
msgid "Log Out"
|
||||
msgstr "Logga ut"
|
||||
|
||||
#: src/components/login/login.tsx:19
|
||||
msgid "Login"
|
||||
msgstr "Logga in"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
#: src/components/login/auth-form.tsx:40
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Inloggningsförsök misslyckades"
|
||||
|
||||
#: src/components/navbar.tsx:86
|
||||
#: src/components/command-palette.tsx:155
|
||||
msgid "Logs"
|
||||
msgstr "Loggar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:82
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Letar du istället efter var du skapar larm? Klicka på klockikonerna <0/> i systemtabellen."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:86
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Hantera visnings- och aviseringsinställningar."
|
||||
|
||||
#: src/components/add-system.tsx:227
|
||||
msgid "Manual setup instructions"
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:673
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:195
|
||||
msgid "Memory"
|
||||
msgstr "Minne"
|
||||
|
||||
#: src/lib/utils.ts:325
|
||||
#: src/components/routes/system.tsx:456
|
||||
msgid "Memory Usage"
|
||||
msgstr "Minnesanvändning"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Minnesanvändning för dockercontainrar"
|
||||
|
||||
#: src/components/add-system.tsx:155
|
||||
msgid "Name"
|
||||
msgstr "Namn"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:223
|
||||
msgid "Net"
|
||||
msgstr "Nät"
|
||||
|
||||
#: src/components/routes/system.tsx:508
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Nätverkstrafik för dockercontainrar"
|
||||
|
||||
#: src/components/routes/system.tsx:493
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Nätverkstrafik för publika gränssnitt"
|
||||
|
||||
#: src/components/command-palette.tsx:48
|
||||
msgid "No results found."
|
||||
msgstr "Inga resultat hittades."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:472
|
||||
#: src/components/systems-table/systems-table.tsx:495
|
||||
msgid "No systems found."
|
||||
msgstr "Inga system hittades."
|
||||
|
||||
#: src/components/command-palette.tsx:109
|
||||
#: src/components/routes/settings/notifications.tsx:76
|
||||
#: src/components/routes/settings/layout.tsx:57
|
||||
msgid "Notifications"
|
||||
msgstr "Aviseringar"
|
||||
|
||||
#: src/components/login/auth-form.tsx:300
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Stöd för OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:62
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Vid varje omstart kommer systemen i databasen att uppdateras för att matcha systemen som definieras i filen."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:639
|
||||
msgid "Open menu"
|
||||
msgstr "Öppna menyn"
|
||||
|
||||
#: src/components/login/auth-form.tsx:251
|
||||
msgid "Or continue with"
|
||||
msgstr "Eller fortsätt med"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:120
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Skriv över befintliga larm"
|
||||
|
||||
#: src/components/command-palette.tsx:83
|
||||
msgid "Page"
|
||||
msgstr "Sida"
|
||||
|
||||
#: src/components/command-palette.tsx:70
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Sidor / Inställningar"
|
||||
|
||||
#: src/components/login/auth-form.tsx:195
|
||||
#: src/components/login/auth-form.tsx:200
|
||||
msgid "Password"
|
||||
msgstr "Lösenord"
|
||||
|
||||
#: src/components/login/auth-form.tsx:21
|
||||
msgid "Password must be at least 8 characters."
|
||||
msgstr "Lösenordet måste vara minst 8 tecken."
|
||||
|
||||
#: src/components/login/auth-form.tsx:22
|
||||
msgid "Password must be less than 72 bytes."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Password reset request received"
|
||||
msgstr "Begäran om återställning av lösenord mottagen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:672
|
||||
msgid "Pause"
|
||||
msgstr "Paus"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:143
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:97
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Vänligen <0>konfigurera en SMTP-server</0> för att säkerställa att larm levereras."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Vänligen kontrollera loggarna för mer information."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:17
|
||||
#: src/components/login/auth-form.tsx:41
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Vänligen kontrollera dina inloggningsuppgifter och försök igen"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Vänligen skapa ett administratörskonto"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Vänligen aktivera popup-fönster för den här webbplatsen"
|
||||
|
||||
#: src/lib/utils.ts:49
|
||||
msgid "Please log in again"
|
||||
msgstr "Vänligen logga in igen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Vänligen se <0>dokumentationen</0> för instruktioner."
|
||||
|
||||
#: src/components/login/login.tsx:40
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Vänligen logga in på ditt konto"
|
||||
|
||||
#: src/components/add-system.tsx:171
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:457
|
||||
#: src/components/routes/system.tsx:577
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Exakt användning vid den registrerade tidpunkten"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Föredraget språk"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:182
|
||||
msgid "Public Key"
|
||||
msgstr "Offentlig nyckel"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/charts/area-chart.tsx:62
|
||||
#: src/components/charts/area-chart.tsx:72
|
||||
msgid "Read"
|
||||
msgstr "Läs"
|
||||
|
||||
#. Network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:67
|
||||
msgid "Received"
|
||||
msgstr "Mottaget"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:77
|
||||
msgid "Reset Password"
|
||||
msgstr "Återställ lösenord"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:667
|
||||
msgid "Resume"
|
||||
msgstr "Återuppta"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:119
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Spara adressen med Enter-tangenten eller komma. Lämna tomt för att inaktivera e-postaviseringar."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:169
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
msgid "Save Settings"
|
||||
msgstr "Spara inställningar"
|
||||
|
||||
#: src/components/add-system.tsx:232
|
||||
msgid "Save system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:134
|
||||
msgid "Search"
|
||||
msgstr "Sök"
|
||||
|
||||
#: src/components/command-palette.tsx:45
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Sök efter system eller inställningar..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:82
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Se <0>aviseringsinställningar</0> för att konfigurera hur du tar emot larm."
|
||||
|
||||
#. Network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Sent"
|
||||
msgstr "Skickat"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Anger standardtidsintervallet för diagram när ett system visas."
|
||||
|
||||
#: src/components/command-palette.tsx:94
|
||||
#: src/components/command-palette.tsx:97
|
||||
#: src/components/command-palette.tsx:112
|
||||
#: src/components/routes/settings/layout.tsx:72
|
||||
#: src/components/routes/settings/layout.tsx:83
|
||||
msgid "Settings"
|
||||
msgstr "Inställningar"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Settings saved"
|
||||
msgstr "Inställningar sparade"
|
||||
|
||||
#: src/components/login/auth-form.tsx:239
|
||||
msgid "Sign in"
|
||||
msgstr "Logga in"
|
||||
|
||||
#: src/components/command-palette.tsx:184
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP-inställningar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:389
|
||||
msgid "Sort By"
|
||||
msgstr "Sortera efter"
|
||||
|
||||
#: src/lib/utils.ts:311
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:523
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap-utrymme som används av systemet"
|
||||
|
||||
#: src/components/routes/system.tsx:522
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap-användning"
|
||||
|
||||
#. System theme
|
||||
#: src/lib/utils.ts:316
|
||||
#: src/components/mode-toggle.tsx:27
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:56
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "System kan hanteras i en <0>config.yml</0>-fil i din datakatalog."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:377
|
||||
msgid "Table"
|
||||
msgstr "Tabell"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/systems-table/systems-table.tsx:244
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:344
|
||||
#: src/components/routes/system.tsx:534
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx:535
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturer för systemsensorer"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:213
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Testa <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:184
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testavisering skickad"
|
||||
|
||||
#: src/components/add-system.tsx:147
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Agenten måste köras på systemet för att ansluta. Kopiera installationskommandot för agenten nedan."
|
||||
|
||||
#: src/components/add-system.tsx:138
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Agenten måste köras på systemet för att ansluta. Kopiera <0>docker-compose.yml</0> för agenten nedan."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:99
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Logga sedan in på backend och återställ ditt användarkontos lösenord i användartabellen."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:699
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Den här åtgärden kan inte ångras. Detta kommer permanent att ta bort alla aktuella poster för {name} från databasen."
|
||||
|
||||
#: src/components/routes/system.tsx:615
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Genomströmning av {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:482
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Genomströmning av rotfilsystemet"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:108
|
||||
msgid "To email(s)"
|
||||
msgstr "Till e-postadress(er)"
|
||||
|
||||
#: src/components/routes/system.tsx:409
|
||||
#: src/components/routes/system.tsx:422
|
||||
msgid "Toggle grid"
|
||||
msgstr "Växla rutnät"
|
||||
|
||||
#: src/components/mode-toggle.tsx:34
|
||||
msgid "Toggle theme"
|
||||
msgstr "Växla tema"
|
||||
|
||||
#: src/lib/utils.ts:347
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Utlöses när någon sensor överskrider ett tröskelvärde"
|
||||
|
||||
#: src/lib/utils.ts:340
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Utlöses när kombinerad upp/ner överskrider ett tröskelvärde"
|
||||
|
||||
#: src/lib/utils.ts:322
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Utlöses när CPU-användningen överskrider ett tröskelvärde"
|
||||
|
||||
#: src/lib/utils.ts:328
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Utlöses när minnesanvändningen överskrider ett tröskelvärde"
|
||||
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Utlöses när status växlar mellan upp och ner"
|
||||
|
||||
#: src/lib/utils.ts:334
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Utlöses när användningen av någon disk överskrider ett tröskelvärde"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/systems-table/systems-table.tsx:141
|
||||
#: src/components/routes/system.tsx:343
|
||||
msgid "Up"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:350
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Uppdateras i realtid. Klicka på ett system för att visa information."
|
||||
|
||||
#: src/components/routes/system.tsx:270
|
||||
msgid "Uptime"
|
||||
msgstr "Drifttid"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
#: src/components/routes/system.tsx:602
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Usage"
|
||||
msgstr "Användning"
|
||||
|
||||
#: src/components/routes/system.tsx:474
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Användning av rotpartitionen"
|
||||
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
#: src/components/charts/mem-chart.tsx:63
|
||||
#: src/components/charts/area-chart.tsx:75
|
||||
msgid "Used"
|
||||
msgstr "Använt"
|
||||
|
||||
#: src/components/navbar.tsx:70
|
||||
#: src/components/command-palette.tsx:141
|
||||
msgid "Users"
|
||||
msgstr "Användare"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:359
|
||||
msgid "View"
|
||||
msgstr "Visa"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:424
|
||||
msgid "Visible Fields"
|
||||
msgstr "Synliga fält"
|
||||
|
||||
#: src/components/routes/system.tsx:707
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Väntar på tillräckligt med poster att visa"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Vill du hjälpa oss att göra våra översättningar ännu bättre? Kolla in <0>Crowdin</0> för mer information."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:126
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push-aviseringar"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
#: src/components/charts/area-chart.tsx:71
|
||||
msgid "Write"
|
||||
msgstr "Skriv"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:62
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML-konfiguration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:46
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML-konfiguration"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:35
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Dina användarinställningar har uppdaterats."
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user